@@ -185,60 +185,296 @@ 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-always-break-op-inside' , 
195+   'loop-always-return-op-inside' , 
196+   'loop-always-break-op-continuing' , 
197+   'loop-always-return-op-continuing' , 
198+   'loop-always-break-op-after' , 
199+   'loop-always-return-op-after' , 
200+   'for-with-cond-always-break-op-inside' , 
201+   'for-with-cond-always-return-op-inside' , 
202+   'for-with-cond-always-break-op-after' , 
203+   'for-with-cond-always-return-op-after' , 
204+   'for-without-cond-always-break-op-inside' , 
205+   'for-without-cond-always-return-op-inside' , 
206+   'for-without-cond-always-break-op-after' , 
207+   'for-without-cond-always-return-op-after' , 
208+   'while-always-break-op-inside' , 
209+   'while-always-return-op-inside' , 
210+   'while-always-break-op-after' , 
211+   'while-always-return-op-after' , 
212+ ]  as  const ; 
189213type  kStatementType  =  ( typeof  kStatementKinds ) [ number ] ; 
190214
215+ type  kSnippetInfo  =  { 
216+   // A WGSL code sippet that embeds a condition and operation-operation-under-test 
217+   // in a larger construct. 
218+   code : string ; 
219+   // Is the operation-under-test sensitive to the uniformity of the condition? 
220+   sensitive : boolean ; 
221+ } ; 
191222function  generateConditionalStatement ( 
192223  statement : kStatementType , 
193-   condition : string , 
194-   op : string 
195- ) : string  { 
196-   const  code  =  `` ; 
224+   condition_name : string , 
225+   op_name : string 
226+ ) : kSnippetInfo  { 
227+   const  cond  =  generateCondition ( condition_name ) ; 
228+   const  uniform_cond  =  generateCondition ( 'uniform_storage_ro' ) ; 
229+   const  op  =  generateOp ( op_name ) ; 
197230  switch  ( statement )  { 
198231    case  'if' : { 
199-       return  `if ${ generateCondition ( condition ) }  
200-         ${ generateOp ( op ) }  
201-       } 
202-       ` ; 
232+       return  { 
233+         sensitive : true , 
234+         code : ` 
235+           if ${ cond }  
236+             ${ op }  
237+           }` , 
238+       } ; 
203239    } 
204240    case  'for' : { 
205-       return  `for (; ${ generateCondition ( condition ) }  
206-         ${ generateOp ( op ) }  
207-       } 
208-       ` ; 
241+       return  { 
242+         sensitive : true , 
243+         code : ` 
244+           for (; ${ cond }  
245+             ${ op }  
246+           }` , 
247+       } ; 
209248    } 
210249    case  'while' : { 
211-       return  `while ${ generateCondition ( condition ) }  
212-         ${ generateOp ( op ) }  
213-       } 
214-       ` ; 
250+       return  { 
251+         sensitive : true , 
252+         code : ` 
253+           while ${ cond }  
254+             ${ op }  
255+           }` , 
256+       } ; 
215257    } 
216258    case  'switch' : { 
217-       return  `switch u32(${ generateCondition ( condition ) }  
218-         case 0: { 
219-           ${ generateOp ( op ) }  
220-         } 
221-         default: { } 
222-       } 
223-       ` ; 
259+       return  { 
260+         sensitive : true , 
261+         code : ` 
262+           switch u32(${ cond }  
263+             case 0: { 
264+               ${ op }  
265+             } 
266+             default: { } 
267+           }` , 
268+       } ; 
224269    } 
225270    case  'break-if' : { 
226271      // The initial 'if' prevents the loop from being infinite.  Its condition 
227272      // is uniform, to ensure the first iteration of the the body executes 
228273      // uniformly. The uniformity of the second iteration depends entirely on 
229274      // the uniformity of the break-if condition. 
230-       return  `loop { 
231-         if ${ generateCondition ( 'uniform_storage_ro' ) }  
232-         ${ generateOp ( op ) }  
233-         continuing { 
234-           break if ${ generateCondition ( condition ) }  
235-         } 
236-       } 
237-       ` ; 
275+       return  { 
276+         sensitive : true , 
277+         code : ` 
278+           loop { 
279+             if ${ uniform_cond }  
280+             ${ op }  
281+             continuing { 
282+               break if ${ cond }  
283+             } 
284+           }` , 
285+       } ; 
286+     } 
287+     case  'loop-always-break-op-inside' : { 
288+       return  { 
289+         sensitive : false ,  // The op is unreachable. 
290+         code : ` 
291+           loop { 
292+             break; 
293+             if ${ cond } ${ op }  
294+           }` , 
295+       } ; 
296+     } 
297+     case  'loop-always-return-op-inside' : { 
298+       return  { 
299+         sensitive : false ,  // The op is unreachable. 
300+         code : ` 
301+           loop { 
302+             return; 
303+             if ${ cond } ${ op }  
304+           }` , 
305+       } ; 
306+     } 
307+     case  'loop-always-break-op-continuing' : { 
308+       return  { 
309+         sensitive : false ,  // The op is unreachable. 
310+         code : ` 
311+           loop { 
312+             break; 
313+             continuing { 
314+               if ${ cond } ${ op }  
315+             } 
316+           }` , 
317+       } ; 
318+     } 
319+     case  'loop-always-return-op-continuing' : { 
320+       return  { 
321+         sensitive : false ,  // The op is unreachable. 
322+         code : ` 
323+           loop { 
324+             return; 
325+             continuing { 
326+               if ${ cond } ${ op }  
327+             } 
328+           }` , 
329+       } ; 
330+     } 
331+     case  'loop-always-break-op-after' : { 
332+       return  { 
333+         sensitive : true , 
334+         code : ` 
335+           loop { 
336+             break; 
337+           } 
338+           if ${ cond } ${ op }  , 
339+       } ; 
340+     } 
341+     case  'loop-always-return-op-after' : { 
342+       return  { 
343+         sensitive : false ,  // The op is unreachable. 
344+         code : ` 
345+           loop { 
346+             return; 
347+           } 
348+           if ${ cond } ${ op }  , 
349+       } ; 
350+     } 
351+     case  'for-with-cond-always-break-op-inside' : { 
352+       return  { 
353+         sensitive : false ,  // The op is unreachable. 
354+         code : ` 
355+           for ( ;${ uniform_cond }  
356+             break; 
357+             if ${ cond } ${ op }  
358+           }` , 
359+       } ; 
360+     } 
361+     case  'for-with-cond-always-return-op-inside' : { 
362+       return  { 
363+         sensitive : false ,  // The op is unreachable. 
364+         code : ` 
365+           for ( ;${ uniform_cond }  
366+             return; 
367+             if ${ cond } ${ op }  
368+           }` , 
369+       } ; 
370+     } 
371+     case  'for-with-cond-always-break-op-after' : { 
372+       return  { 
373+         sensitive : true , 
374+         code : ` 
375+           for ( ;${ uniform_cond }  
376+             break; 
377+           } 
378+           if ${ cond } ${ op }  , 
379+       } ; 
380+     } 
381+     case  'for-with-cond-always-return-op-after' : { 
382+       return  { 
383+         // Desugars to a loop with a conditional break, 
384+         // before reaching the loop. 
385+         sensitive : true , 
386+         code : ` 
387+           for ( ;${ uniform_cond }  
388+             return; 
389+           } 
390+           if ${ cond } ${ op }  , 
391+       } ; 
392+     } 
393+     case  'for-without-cond-always-break-op-inside' : { 
394+       return  { 
395+         sensitive : false ,  // The op is unreachable. 
396+         code : ` 
397+           for ( ; ; ) { 
398+             break; 
399+             if ${ cond } ${ op }  
400+           }` , 
401+       } ; 
402+     } 
403+     case  'for-without-cond-always-return-op-inside' : { 
404+       return  { 
405+         sensitive : false ,  // The op is unreachable. 
406+         code : ` 
407+           for ( ; ; ) { 
408+             return; 
409+             if ${ cond } ${ op }  
410+           }` , 
411+       } ; 
412+     } 
413+     case  'for-without-cond-always-break-op-after' : { 
414+       return  { 
415+         sensitive : true , 
416+         code : ` 
417+           for ( ; ; ) { 
418+             break; 
419+           } 
420+           if ${ cond } ${ op }  , 
421+       } ; 
422+     } 
423+     case  'for-without-cond-always-return-op-after' : { 
424+       return  { 
425+         // Desugars to a loop without a conditional break. 
426+         // So the op is unreachable. 
427+         sensitive : false , 
428+         code : ` 
429+           for ( ; ; ) { 
430+             return; 
431+           } 
432+           if ${ cond } ${ op }  , 
433+       } ; 
434+     } 
435+     case  'while-always-break-op-inside' : { 
436+       return  { 
437+         sensitive : false ,  // The op is unreachable. 
438+         code : ` 
439+           while (${ uniform_cond }  
440+             break; 
441+             if ${ cond } ${ op }  
442+           }` , 
443+       } ; 
444+     } 
445+     case  'while-always-return-op-inside' : { 
446+       return  { 
447+         sensitive : false ,  // The op is unreachable. 
448+         code : ` 
449+           while (${ uniform_cond }  
450+             return; 
451+             if ${ cond } ${ op }  
452+           }` , 
453+       } ; 
454+     } 
455+     case  'while-always-break-op-after' : { 
456+       return  { 
457+         sensitive : true , 
458+         code : ` 
459+           while (${ uniform_cond }  
460+             break; 
461+           } 
462+           if ${ cond } ${ op }  , 
463+       } ; 
464+     } 
465+     case  'while-always-return-op-after' : { 
466+       return  { 
467+         // Desugars to a loop with a conditional break, 
468+         // before reaching the loop. 
469+         sensitive : true , 
470+         code : ` 
471+           while (${ uniform_cond }  
472+             return; 
473+           } 
474+           if ${ cond } ${ op }  , 
475+       } ; 
238476    } 
239477  } 
240- 
241-   return  code ; 
242478} 
243479
244480g . test ( 'basics' ) 
@@ -293,11 +529,15 @@ g.test('basics')
293529    ` ; 
294530
295531    // Simple control statement containing the op. 
296-     code  +=  generateConditionalStatement ( t . params . statement ,  t . params . cond ,  t . params . op ) ; 
532+     const  snippet  =  generateConditionalStatement ( t . params . statement ,  t . params . cond ,  t . params . op ) ; 
533+     code  +=  snippet . code ; 
297534
298535    code  +=  `\n}\n` ; 
299536
300-     t . expectCompileResult ( t . params . expectation  ||  t . params . op . startsWith ( 'control_case' ) ,  code ) ; 
537+     t . expectCompileResult ( 
538+       t . params . expectation  ||  t . params . op . startsWith ( 'control_case' )  ||  ! snippet . sensitive , 
539+       code 
540+     ) ; 
301541  } ) ; 
302542
303543const  kSubgroupOps  =  [ 
@@ -380,11 +620,15 @@ g.test('basics,subgroups')
380620    ` ; 
381621
382622    // Simple control statement containing the op. 
383-     code  +=  generateConditionalStatement ( t . params . statement ,  t . params . cond ,  t . params . op ) ; 
623+     const  snippet  =  generateConditionalStatement ( t . params . statement ,  t . params . cond ,  t . params . op ) ; 
624+     code  +=  snippet . code ; 
384625
385626    code  +=  `\n}\n` ; 
386627
387-     t . expectCompileResult ( t . params . expectation  ||  t . params . op . startsWith ( 'control_case' ) ,  code ) ; 
628+     t . expectCompileResult ( 
629+       t . params . expectation  ||  t . params . op . startsWith ( 'control_case' )  ||  ! snippet . sensitive , 
630+       code 
631+     ) ; 
388632  } ) ; 
389633
390634const  kFragmentBuiltinValues  =  [ 
0 commit comments