Skip to content

Commit f81cf7a

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, where the continuing block in the loop has a break-if. This case requires the analysis to avoid using a Next behaviour from the overall loop. - immediately after the loop Fixed: #4476
1 parent e34f99a commit f81cf7a

File tree

1 file changed

+65
-3
lines changed

1 file changed

+65
-3
lines changed

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

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,17 @@ 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-break-if-then-after',
197+
'loop-return-only-after',
198+
] as const;
189199
type kStatementType = (typeof kStatementKinds)[number];
190200

191201
function generateConditionalStatement(
@@ -236,6 +246,48 @@ function generateConditionalStatement(
236246
}
237247
`;
238248
}
249+
case 'loop-return-only-inside': {
250+
// The loop body only returns. The uniformity of the operation
251+
// is immaterial. Check analysis inside the loop body, after
252+
// the unconditional return.
253+
return `loop {
254+
return;
255+
if ${generateCondition(condition)} { ${generateOp(op)} }
256+
}
257+
`;
258+
}
259+
case 'loop-return-only-continuing': {
260+
// The loop body only returns. The uniformity of the operation
261+
// is immaterial. Check analysis in the continuing block.
262+
return `loop {
263+
return;
264+
continuing {
265+
if ${generateCondition(condition)} { ${generateOp(op)} }
266+
}
267+
}
268+
`;
269+
}
270+
case 'loop-return-only-break-if-then-after': {
271+
// The loop body only returns. The uniformity of the operation
272+
// is immaterial.
273+
return `loop {
274+
return;
275+
continuing {
276+
break if true;
277+
}
278+
}
279+
if ${generateCondition(condition)} { ${generateOp(op)} }
280+
`;
281+
}
282+
case 'loop-return-only-after': {
283+
// The loop body only returns. The uniformity of the operation
284+
// is immaterial. Check analysis after the loop.
285+
return `loop {
286+
return;
287+
}
288+
if ${generateCondition(condition)} { ${generateOp(op)} }
289+
`;
290+
}
239291
}
240292

241293
return code;
@@ -297,7 +349,12 @@ g.test('basics')
297349

298350
code += `\n}\n`;
299351

300-
t.expectCompileResult(t.params.expectation || t.params.op.startsWith('control_case'), code);
352+
t.expectCompileResult(
353+
t.params.expectation ||
354+
t.params.op.startsWith('control_case') ||
355+
t.params.statement.startsWith('loop-return-only'),
356+
code
357+
);
301358
});
302359

303360
const kSubgroupOps = [
@@ -384,7 +441,12 @@ g.test('basics,subgroups')
384441

385442
code += `\n}\n`;
386443

387-
t.expectCompileResult(t.params.expectation || t.params.op.startsWith('control_case'), code);
444+
t.expectCompileResult(
445+
t.params.expectation ||
446+
t.params.op.startsWith('control_case') ||
447+
t.params.statement.startsWith('loop-return-only'),
448+
code
449+
);
388450
});
389451

390452
const kFragmentBuiltinValues = [

0 commit comments

Comments
 (0)