diff --git a/src/webgpu/listing_meta.json b/src/webgpu/listing_meta.json index ac0678301f59..23207a3bfdb7 100644 --- a/src/webgpu/listing_meta.json +++ b/src/webgpu/listing_meta.json @@ -1536,6 +1536,9 @@ "webgpu:shader,execution,expression,unary,bool_conversion:i32:*": { "subcaseMS": 8.219 }, "webgpu:shader,execution,expression,unary,bool_conversion:u32:*": { "subcaseMS": 7.401 }, "webgpu:shader,execution,expression,unary,bool_logical:negation:*": { "subcaseMS": 6.413 }, + "webgpu:shader,execution,expression,unary,indirection:deref:*": { "subcaseMS": 0.0 }, + "webgpu:shader,execution,expression,unary,indirection:deref_index:*": { "subcaseMS": 0.0 }, + "webgpu:shader,execution,expression,unary,indirection:deref_member:*": { "subcaseMS": 0.0 }, "webgpu:shader,execution,expression,unary,f16_arithmetic:negation:*": { "subcaseMS": 117.604 }, "webgpu:shader,execution,expression,unary,f16_conversion:bool:*": { "subcaseMS": 34.694 }, "webgpu:shader,execution,expression,unary,f16_conversion:f16:*": { "subcaseMS": 36.013 }, diff --git a/src/webgpu/shader/execution/expression/expression.ts b/src/webgpu/shader/execution/expression/expression.ts index 436d99f2288a..e1ac03d53bc4 100644 --- a/src/webgpu/shader/execution/expression/expression.ts +++ b/src/webgpu/shader/execution/expression/expression.ts @@ -32,6 +32,8 @@ export const allInputSources: InputSource[] = ['const', 'uniform', 'storage_r', /** Just constant input source */ export const onlyConstInputSource: InputSource[] = ['const']; +export const allButConstInputSource: InputSource[] = ['uniform', 'storage_r', 'storage_rw']; + /** Configuration for running a expression test */ export type Config = { // Where the input values are read from diff --git a/src/webgpu/shader/execution/expression/unary/indirection.spec.ts b/src/webgpu/shader/execution/expression/unary/indirection.spec.ts new file mode 100644 index 000000000000..0574df57c4e1 --- /dev/null +++ b/src/webgpu/shader/execution/expression/unary/indirection.spec.ts @@ -0,0 +1,156 @@ +export const description = ` +Execution Tests for unary indirection (dereference) +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { keysOf } from '../../../../../common/util/data_tables.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { ScalarKind, scalarType } from '../../../../util/conversion.js'; +import { sparseScalarF32Range } from '../../../../util/math.js'; +import { + allButConstInputSource, + basicExpressionWithPredeclarationBuilder, + run, +} from '../expression.js'; + +export const g = makeTestGroup(GPUTest); + +// All the ways to deref an expression +const kDerefCases = { + deref_address_of_identifier: { + wgsl: '(*(&a))', + requires_pointer_composite_access: false, + }, + deref_pointer: { + wgsl: '(*p)', + requires_pointer_composite_access: false, + }, + address_of_identifier: { + wgsl: '(&a)', + requires_pointer_composite_access: true, + }, + pointer: { + wgsl: 'p', + requires_pointer_composite_access: true, + }, +}; + +g.test('deref') + .specURL('https://www.w3.org/TR/WGSL/#indirection') + .desc( + ` +Expression: *e + +Pointer expression dereference. +` + ) + .params(u => + u + .combine('inputSource', allButConstInputSource) + .combine('vectorize', [undefined, 2, 3, 4] as const) + .combine('scalarType', ['u32', 'i32', 'f32'] as ScalarKind[]) + .combine('derefType', keysOf(kDerefCases)) + .filter(p => !kDerefCases[p.derefType].requires_pointer_composite_access) + ) + .fn(async t => { + const ty = scalarType(t.params.scalarType); + const cases = sparseScalarF32Range().map(e => { + return { input: ty.create(e), expected: ty.create(e) }; + }); + const elemType = ty.kind; + const type = t.params.vectorize ? `vec${t.params.vectorize}<${elemType}>` : elemType; + const shaderBuilder = basicExpressionWithPredeclarationBuilder( + value => `get_dereferenced_value(${value})`, + `fn get_dereferenced_value(value: ${type}) -> ${type} { + var a = value; + let p = &a; + return ${kDerefCases[t.params.derefType].wgsl}; + }` + ); + await run(t, shaderBuilder, [ty], ty, t.params, cases); + }); + +g.test('deref_index') + .specURL('https://www.w3.org/TR/WGSL/#logical-expr') + .desc( + ` +Expression: (*e)[index] + +Pointer expression dereference as lhs of index accessor expression +` + ) + .params(u => + u + .combine('inputSource', allButConstInputSource) + .combine('vectorize', [undefined, 2, 3, 4] as const) + .combine('scalarType', ['i32', 'f32'] as ScalarKind[]) + .combine('derefType', keysOf(kDerefCases)) + ) + .fn(async t => { + if ( + kDerefCases[t.params.derefType].requires_pointer_composite_access && + !t.hasLanguageFeature('pointer_composite_access') + ) { + return; + } + + const ty = scalarType(t.params.scalarType); + const cases = sparseScalarF32Range().map(e => { + return { input: ty.create(e), expected: ty.create(e) }; + }); + const elemType = ty.kind; + const type = t.params.vectorize ? `vec${t.params.vectorize}<${elemType}>` : elemType; + const shaderBuilder = basicExpressionWithPredeclarationBuilder( + value => `get_dereferenced_value(${value})`, + `fn get_dereferenced_value(value: ${type}) -> ${type} { + var a = array<${type}, 1>(value); + let p = &a; + return ${kDerefCases[t.params.derefType].wgsl}[0]; + }` + ); + await run(t, shaderBuilder, [ty], ty, t.params, cases); + }); + +g.test('deref_member') + .specURL('https://www.w3.org/TR/WGSL/#logical-expr') + .desc( + ` +Expression: (*e).member + +Pointer expression dereference as lhs of member accessor expression +` + ) + .params(u => + u + .combine('inputSource', allButConstInputSource) + .combine('vectorize', [undefined, 2, 3, 4] as const) + .combine('scalarType', ['i32', 'f32'] as ScalarKind[]) + .combine('derefType', keysOf(kDerefCases)) + ) + .fn(async t => { + if ( + kDerefCases[t.params.derefType].requires_pointer_composite_access && + !t.hasLanguageFeature('pointer_composite_access') + ) { + return; + } + + const ty = scalarType(t.params.scalarType); + const cases = sparseScalarF32Range().map(e => { + return { input: ty.create(e), expected: ty.create(e) }; + }); + const elemType = ty.kind; + const type = t.params.vectorize ? `vec${t.params.vectorize}<${elemType}>` : elemType; + const shaderBuilder = basicExpressionWithPredeclarationBuilder( + value => `get_dereferenced_value(${value})`, + `struct S { + m : ${type} + } + fn get_dereferenced_value(value: ${type}) -> ${type} { + var a = S(value); + let p = &a; + return ${kDerefCases[t.params.derefType].wgsl}.m; + }` + ); + await run(t, shaderBuilder, [ty], ty, t.params, cases); + });