From d961efb1f1e3028e0c2b22215e56757c1dafb474 Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Wed, 24 Jan 2024 09:50:31 -0500 Subject: [PATCH] Add break-if validation tests (#3305) This CL adds a break-if validation set of tests. The one break-if tests in the `break` test file is moved over to the `break-if` test file. Fixes #1672 --- src/webgpu/listing_meta.json | 2 + .../shader/validation/parse/break.spec.ts | 4 - .../shader/validation/parse/break_if.spec.ts | 137 ++++++++++++++++++ 3 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 src/webgpu/shader/validation/parse/break_if.spec.ts diff --git a/src/webgpu/listing_meta.json b/src/webgpu/listing_meta.json index 5ae16b0a35c0..4497993899e1 100644 --- a/src/webgpu/listing_meta.json +++ b/src/webgpu/listing_meta.json @@ -2094,6 +2094,8 @@ "webgpu:shader,execution,expression,call,builtin,bitcast:ai_to_f32:*": { "subcaseMS": 0 }, "webgpu:shader,execution,expression,call,builtin,bitcast:ai_to_vec2f16:*": { "subcaseMS": 0 }, "webgpu:shader,execution,expression,call,builtin,bitcast:vec2ai_to_vec4f16:*": { "subcaseMS": 0 }, + "webgpu:shader,validation,parse,break_if:placement:*": { "subcaseMS": 0 }, + "webgpu:shader,validation,parse,break_if:non_bool_param:*": { "subcaseMS": 0 }, "webgpu:shader,validation,expression,call,builtin,arrayLength:bool_type:*": { "subcaseMS": 0 }, "webgpu:shader,validation,expression,call,builtin,arrayLength:type:*": { "subcaseMS": 0 }, "webgpu:shader,validation,expression,call,builtin,arrayLength:access_mode:*": { "subcaseMS": 0 }, diff --git a/src/webgpu/shader/validation/parse/break.spec.ts b/src/webgpu/shader/validation/parse/break.spec.ts index 7c0f067140a2..46074ba5d086 100644 --- a/src/webgpu/shader/validation/parse/break.spec.ts +++ b/src/webgpu/shader/validation/parse/break.spec.ts @@ -15,10 +15,6 @@ const kTests = { src: 'loop { if true { break; } }', pass: true, }, - continuing_break_if: { - src: 'loop { continuing { break if (true); } }', - pass: true, - }, while_break: { src: 'while true { break; }', pass: true, diff --git a/src/webgpu/shader/validation/parse/break_if.spec.ts b/src/webgpu/shader/validation/parse/break_if.spec.ts new file mode 100644 index 000000000000..41d448437e45 --- /dev/null +++ b/src/webgpu/shader/validation/parse/break_if.spec.ts @@ -0,0 +1,137 @@ +export const description = `Validation tests for break if`; + +import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { keysOf } from '../../../../common/util/data_tables.js'; +import { ShaderValidationTest } from '../shader_validation_test.js'; + +export const g = makeTestGroup(ShaderValidationTest); + +const kTests = { + loop_break: { + src: 'loop { break if true; }', + pass: false, + }, + loop_if_break: { + src: 'loop { if true { break if false; } }', + pass: false, + }, + continuing_break_if: { + src: 'loop { continuing { break if true; } }', + pass: true, + }, + continuing_break_if_parens: { + src: 'loop { continuing { break if (true); } }', + pass: true, + }, + continuing_break_if_not_last: { + src: 'loop { continuing { break if (true); let a = 4;} }', + pass: false, + }, + while_break: { + src: 'while true { break if true; }', + pass: false, + }, + while_if_break: { + src: 'while true { if true { break if true; } }', + pass: false, + }, + for_break: { + src: 'for (;;) { break if true; }', + pass: false, + }, + for_if_break: { + src: 'for (;;) { if true { break if true; } }', + pass: false, + }, + switch_case_break: { + src: 'switch(1) { default: { break if true; } }', + pass: false, + }, + switch_case_if_break: { + src: 'switch(1) { default: { if true { break if true; } } }', + pass: false, + }, + break: { + src: 'break if true;', + pass: false, + }, + return_break: { + src: 'return break if true;', + pass: false, + }, + if_break: { + src: 'if true { break if true; }', + pass: false, + }, + continuing_if_break: { + src: 'loop { continuing { if (true) { break if true; } } }', + pass: false, + }, + switch_break: { + src: 'switch(1) { break if true; }', + pass: false, + }, +}; + +g.test('placement') + .desc('Test that break if placement is validated correctly') + .params(u => u.combine('stmt', keysOf(kTests))) + .fn(t => { + const code = ` +@vertex +fn vtx() -> @builtin(position) vec4f { + ${kTests[t.params.stmt].src} + return vec4f(1); +} + `; + t.expectCompileResult(kTests[t.params.stmt].pass, code); + }); + +const vec_types = [2, 3, 4] + .map(i => ['i32', 'u32', 'f32', 'f16'].map(j => `vec${i}<${j}>`)) + .reduce((a, c) => a.concat(c), []); +const f32_matrix_types = [2, 3, 4] + .map(i => [2, 3, 4].map(j => `mat${i}x${j}f`)) + .reduce((a, c) => a.concat(c), []); +const f16_matrix_types = [2, 3, 4] + .map(i => [2, 3, 4].map(j => `mat${i}x${j}`)) + .reduce((a, c) => a.concat(c), []); + +g.test('non_bool_param') + .desc('Test that break if fails with a non-bool parameter') + .params(u => + u.combine('type', [ + 'f32', + 'f16', + 'i32', + 'u32', + 'S', + ...vec_types, + ...f32_matrix_types, + ...f16_matrix_types, + ]) + ) + .beforeAllSubcases(t => { + if (t.params.type.includes('f16')) { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(t => { + const code = ` +struct S { + a: i32, +} + +@vertex +fn vtx() -> @builtin(position) vec4f { + var v: ${t.params.type}; + + loop { + continuing { + break if v; + } + } + return vec4f(1); +}`; + t.expectCompileResult(t.params.type === 'bool', code); + });