Skip to content

Commit

Permalink
shader/validation: Validate var initializers (#3353)
Browse files Browse the repository at this point in the history
Test that:
- initializers are accepted iff the address space allows
- private initializers must be const or override expressions

Issue #1570
  • Loading branch information
jrprice authored Jan 31, 2024
1 parent 6a03fa0 commit 6957d1b
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/webgpu/listing_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -1741,6 +1741,9 @@
"webgpu:shader,validation,decl,var:module_scope_types:*": { "subcaseMS": 1.000 },
"webgpu:shader,validation,decl,var:function_scope_types:*": { "subcaseMS": 1.000 },
"webgpu:shader,validation,decl,var:function_addrspace_at_module_scope:*": { "subcaseMS": 1.000 },
"webgpu:shader,validation,decl,var:module_scope_initializers:*": { "subcaseMS": 1.000 },
"webgpu:shader,validation,decl,var:handle_initializer:*": { "subcaseMS": 1.000 },
"webgpu:shader,validation,decl,var:initializer_kind:*": { "subcaseMS": 1.000 },
"webgpu:shader,validation,decl,var_access_mode:explicit_access_mode:*": { "subcaseMS": 1.373 },
"webgpu:shader,validation,decl,var_access_mode:implicit_access_mode:*": { "subcaseMS": 1.000 },
"webgpu:shader,validation,decl,var_access_mode:read_access:*": { "subcaseMS": 1.177 },
Expand Down
90 changes: 90 additions & 0 deletions src/webgpu/shader/validation/decl/var.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,96 @@ g.test('function_scope_types')
t.expectCompileResult(shouldPass, wgsl);
});

g.test('module_scope_initializers')
.desc('Test that initializers are only supported on address spaces that allow them.')
.params(u =>
u
.combine('initializer', [false, true])
.combine('kind', ['private', 'storage_ro', 'storage_rw', 'uniform', 'workgroup'])
)
.fn(t => {
let decl = '<>';
switch (t.params.kind) {
case 'private':
decl = 'var<private> foo : ';
break;
case 'storage_ro':
decl = '@group(0) @binding(0) var<storage, read> foo : ';
break;
case 'storage_rw':
decl = '@group(0) @binding(0) var<storage, read_write> foo : ';
break;
case 'uniform':
decl = '@group(0) @binding(0) var<uniform> foo : ';
break;
case 'workgroup':
decl = 'var<workgroup> foo : ';
break;
}

const wgsl = `${decl} u32${t.params.initializer ? ' = 42u' : ''};`;
t.expectCompileResult(t.params.kind === 'private' || !t.params.initializer, wgsl);
});

g.test('handle_initializer')
.desc('Test that initializers are not allowed for handle types')
.params(u =>
u.combine('initializer', [false, true]).combine('type', ['sampler', 'texture_2d<f32>'])
)
.fn(t => {
const wgsl = `
@group(0) @binding(0) var foo : ${t.params.type};
@group(0) @binding(1) var bar : ${t.params.type}${t.params.initializer ? ' = foo' : ''};`;
t.expectCompileResult(!t.params.initializer, wgsl);
});

// A list of u32 initializers and their validity for the private address space.
const kInitializers = {
'u32()': true,
'42u': true,
'u32(sqrt(42.0))': true,
'user_func()': false,
my_const_42u: true,
my_override_42u: true,
another_private_var: false,
'vec4u(1, 2, 3, 4)[my_const_42u / 20]': true,
'vec4u(1, 2, 3, 4)[my_override_42u / 20]': true,
'vec4u(1, 2, 3, 4)[another_private_var / 20]': false,
};

g.test('initializer_kind')
.desc(
'Test that initializers must be const-expression or override-expression for the private address space.'
)
.params(u =>
u.combine('initializer', keysOf(kInitializers)).combine('addrspace', ['private', 'function'])
)
.fn(t => {
let wgsl = `
const my_const_42u = 42u;
override my_override_42u : u32;
var<private> another_private_var = 42u;
fn user_func() -> u32 {
return 42u;
}
`;

if (t.params.addrspace === 'private') {
wgsl += `
var<private> foo : u32 = ${t.params.initializer};`;
} else {
wgsl += `
fn foo() {
var bar : u32 = ${t.params.initializer};
}`;
}
t.expectCompileResult(
t.params.addrspace === 'function' || kInitializers[t.params.initializer],
wgsl
);
});

g.test('function_addrspace_at_module_scope')
.desc('Test that the function address space is not allowed at module scope.')
.params(u => u.combine('addrspace', ['private', 'function']))
Expand Down

0 comments on commit 6957d1b

Please sign in to comment.