Skip to content

Commit 87af698

Browse files
committed
uniformity: test uniformity when a loop body only returns
Consider: loop { s1 continuing { s2 } } If the statement behaviour of s1 is exactly {Return}, then the statement behaviour of the entire loop is {Return}. In particular, nonuniformity effects do not leak out from s2 to the context after or outside of the whole loop. See the WGSL spec fix for gpuweb/gpuweb#5100 Test three new statement scenarios, each where s1 starts with `return;`, but varying where a collective operation is placed: - immediately after the return statement - in the continuing block of the same loop - immediately after the loop Fixed: #4476
1 parent 494e318 commit 87af698

File tree

1 file changed

+52
-3
lines changed

1 file changed

+52
-3
lines changed

src/webgpu/shader/validation/uniformity/uniformity.spec.ts

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,16 @@ function generateOp(op: string): string {
185185
}
186186
}
187187

188-
const kStatementKinds = ['if', 'for', 'while', 'switch', 'break-if'] as const;
188+
const kStatementKinds = [
189+
'if',
190+
'for',
191+
'while',
192+
'switch',
193+
'break-if',
194+
'loop-return-only-inside',
195+
'loop-return-only-continuing',
196+
'loop-return-only-after',
197+
] as const;
189198
type kStatementType = (typeof kStatementKinds)[number];
190199

191200
function generateConditionalStatement(
@@ -236,6 +245,36 @@ function generateConditionalStatement(
236245
}
237246
`;
238247
}
248+
case 'loop-return-only-inside': {
249+
// The loop body only returns. The uniformity of the operation
250+
// is immaterial. Check analysis inside the loop body, after
251+
// the unconditional return.
252+
return `loop {
253+
return;
254+
if ${generateCondition(condition)} { ${generateOp(op)} }
255+
}
256+
`;
257+
}
258+
case 'loop-return-only-continuing': {
259+
// The loop body only returns. The uniformity of the operation
260+
// is immaterial. Check analysis in the continuing block.
261+
return `loop {
262+
return;
263+
continuing {
264+
if ${generateCondition(condition)} { ${generateOp(op)} }
265+
}
266+
}
267+
`;
268+
}
269+
case 'loop-return-only-after': {
270+
// The loop body only returns. The uniformity of the operation
271+
// is immaterial. Check analysis after the loop.
272+
return `loop {
273+
return;
274+
}
275+
if ${generateCondition(condition)} { ${generateOp(op)} }
276+
`;
277+
}
239278
}
240279

241280
return code;
@@ -297,7 +336,12 @@ g.test('basics')
297336

298337
code += `\n}\n`;
299338

300-
t.expectCompileResult(t.params.expectation || t.params.op.startsWith('control_case'), code);
339+
t.expectCompileResult(
340+
t.params.expectation ||
341+
t.params.op.startsWith('control_case') ||
342+
t.params.statement.startsWith('loop-return-only'),
343+
code
344+
);
301345
});
302346

303347
const kSubgroupOps = [
@@ -384,7 +428,12 @@ g.test('basics,subgroups')
384428

385429
code += `\n}\n`;
386430

387-
t.expectCompileResult(t.params.expectation || t.params.op.startsWith('control_case'), code);
431+
t.expectCompileResult(
432+
t.params.expectation ||
433+
t.params.op.startsWith('control_case') ||
434+
t.params.statement.startsWith('loop-return-only'),
435+
code
436+
);
388437
});
389438

390439
const kFragmentBuiltinValues = [

0 commit comments

Comments
 (0)