From 9874613d69894ede3e7e4e0f7e409be8b2ef8366 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 16 Jan 2024 17:47:17 -0500 Subject: [PATCH] Add more uniformity tests (#3269) Fixes #3266 Fixes #3226 * Add tests covering lhs * and & expressions * Add tests requiring `pointer_composite_access` language feature --- src/webgpu/capability_info.ts | 1 + .../validation/uniformity/uniformity.spec.ts | 187 +++++++++++++++++- 2 files changed, 185 insertions(+), 3 deletions(-) diff --git a/src/webgpu/capability_info.ts b/src/webgpu/capability_info.ts index 1bd5d3b7c698..d26d93ca2e8d 100644 --- a/src/webgpu/capability_info.ts +++ b/src/webgpu/capability_info.ts @@ -821,6 +821,7 @@ export const kKnownWGSLLanguageFeatures = [ 'readonly_and_readwrite_storage_textures', 'packed_4x8_integer_dot_product', 'unrestricted_pointer_parameters', + 'pointer_composite_access', ] as const; export type WGSLLanguageFeature = (typeof kKnownWGSLLanguageFeatures)[number]; diff --git a/src/webgpu/shader/validation/uniformity/uniformity.spec.ts b/src/webgpu/shader/validation/uniformity/uniformity.spec.ts index 41249e445d1c..aaba1f95aa54 100644 --- a/src/webgpu/shader/validation/uniformity/uniformity.spec.ts +++ b/src/webgpu/shader/validation/uniformity/uniformity.spec.ts @@ -367,7 +367,14 @@ function generatePointerCheck(check: string): string { } } -const kPointerCases = { +interface PointerCase { + code: string; + check: 'address' | 'contents'; + uniform: boolean | 'never'; + needs_deref_sugar?: boolean; +} + +const kPointerCases: Record = { address_uniform_literal: { code: `let ptr = &wg_array[0];`, check: `address`, @@ -585,6 +592,168 @@ const kPointerCases = { check: `contents`, uniform: false, }, + contents_lhs_ref_pointer_deref1: { + code: `*&func_scalar = uniform_value; + let test_val = func_scalar;`, + check: `contents`, + uniform: true, + }, + contents_lhs_ref_pointer_deref1a: { + code: `*&func_scalar = nonuniform_value; + let test_val = func_scalar;`, + check: `contents`, + uniform: false, + }, + contents_lhs_ref_pointer_deref2: { + code: `*&(func_array[nonuniform_value]) = uniform_value; + let test_val = func_array[0];`, + check: `contents`, + uniform: false, + }, + contents_lhs_ref_pointer_deref2a: { + code: `(func_array[nonuniform_value]) = uniform_value; + let test_val = func_array[0];`, + check: `contents`, + uniform: false, + }, + contents_lhs_ref_pointer_deref3: { + code: `*&(func_array[needs_uniform(uniform_value)]) = uniform_value; + let test_val = func_array[0];`, + check: `contents`, + uniform: true, + }, + contents_lhs_ref_pointer_deref3a: { + code: `*&(func_array[needs_uniform(nonuniform_value)]) = uniform_value; + let test_val = func_array[0];`, + check: `contents`, + uniform: 'never', + }, + contents_lhs_ref_pointer_deref4: { + code: `*&((*&(func_struct.x[uniform_value])).x[uniform_value].x[uniform_value]) = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: true, + }, + contents_lhs_ref_pointer_deref4a: { + code: `*&((*&(func_struct.x[uniform_value])).x[uniform_value].x[uniform_value]) = nonuniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: false, + }, + contents_lhs_ref_pointer_deref4b: { + code: `*&((*&(func_struct.x[uniform_value])).x[uniform_value].x[nonuniform_value]) = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: false, + }, + contents_lhs_ref_pointer_deref4c: { + code: `*&((*&(func_struct.x[uniform_value])).x[nonuniform_value]).x[uniform_value] = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: false, + }, + contents_lhs_ref_pointer_deref4d: { + code: `*&((*&(func_struct.x[nonuniform_value])).x[uniform_value].x)[uniform_value] = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: false, + }, + contents_lhs_ref_pointer_deref4e: { + code: `*&((*&(func_struct.x[uniform_value])).x[needs_uniform(nonuniform_value)].x[uniform_value]) = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: 'never', + }, + + // The following cases require the 'pointer_composite_access' language feature. + contents_lhs_pointer_deref2: { + code: `(&func_array)[uniform_value] = uniform_value; + let test_val = func_array[0];`, + check: `contents`, + uniform: true, + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref2a: { + code: `(&func_array)[nonuniform_value] = uniform_value; + let test_val = func_array[0];`, + check: `contents`, + uniform: false, + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref3: { + code: `(&func_array)[needs_uniform(uniform_value)] = uniform_value; + let test_val = func_array[0];`, + check: `contents`, + uniform: true, + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref3a: { + code: `(&func_array)[needs_uniform(nonuniform_value)] = uniform_value; + let test_val = func_array[0];`, + check: `contents`, + uniform: 'never', + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref4: { + code: `(&((&(func_struct.x[uniform_value])).x[uniform_value]).x)[uniform_value] = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: true, + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref4a: { + code: `(&((&(func_struct.x[uniform_value])).x[uniform_value]).x)[uniform_value] = nonuniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: false, + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref4b: { + code: `(&((&(func_struct.x[uniform_value])).x)[uniform_value]).x[nonuniform_value] = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: false, + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref4c: { + code: `(&((&(func_struct.x[uniform_value])).x[nonuniform_value]).x)[uniform_value] = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: false, + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref4d: { + code: `(&((&(func_struct.x[nonuniform_value])).x[uniform_value]).x)[uniform_value] = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: false, + needs_deref_sugar: true, + }, + contents_lhs_pointer_deref4e: { + code: `(&((&(func_struct.x[uniform_value])).x)[needs_uniform(nonuniform_value)].x[uniform_value]) = uniform_value; + let test_val = func_struct.x[0].x[0].x[0];`, + check: `contents`, + uniform: 'never', + needs_deref_sugar: true, + }, + contents_rhs_pointer_deref1: { + code: `let test_val = (&func_array)[uniform_value];`, + check: `contents`, + uniform: true, + needs_deref_sugar: true, + }, + contents_rhs_pointer_deref1a: { + code: `let test_val = (&func_array)[nonuniform_value];`, + check: `contents`, + uniform: false, + needs_deref_sugar: true, + }, + contents_rhs_pointer_deref2: { + code: `let test_val = (&func_array)[needs_uniform(nonuniform_value)];`, + check: `contents`, + uniform: `never`, + needs_deref_sugar: true, + }, }; g.test('pointers') @@ -612,6 +781,13 @@ var uniform_value : u32; @group(0) @binding(1) var nonuniform_value : u32; +fn needs_uniform(val : u32) -> u32{ + if val == 0 { + workgroupBarrier(); + } + return val; +} + @compute @workgroup_size(16, 1, 1) fn main(@builtin(local_invocation_id) lid : vec3, @builtin(global_invocation_id) gid : vec3) { @@ -627,11 +803,16 @@ fn main(@builtin(local_invocation_id) lid : vec3, ` ${generatePointerCheck(testcase.check)} }`; - if (!testcase.uniform) { + + if (testcase.needs_deref_sugar === true) { + t.skipIfLanguageFeatureNotSupported('pointer_composite_access'); + } + // Explicitly check false to distinguish from never. + if (testcase.uniform === false) { const without_check = code + `}\n`; t.expectCompileResult(true, without_check); } - t.expectCompileResult(testcase.uniform, with_check); + t.expectCompileResult(testcase.uniform === true, with_check); }); function expectedUniformity(uniform: string, init: string): boolean {