• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 Valve Corporation
2 // Copyright (c) 2017 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <string>
17 
18 #include "test/opt/pass_fixture.h"
19 #include "test/opt/pass_utils.h"
20 
21 namespace spvtools {
22 namespace opt {
23 namespace {
24 
25 using DeadBranchElimTest = PassTest<::testing::Test>;
26 
TEST_F(DeadBranchElimTest,IfThenElseTrue)27 TEST_F(DeadBranchElimTest, IfThenElseTrue) {
28   // #version 140
29   //
30   // in vec4 BaseColor;
31   //
32   // void main()
33   // {
34   //     vec4 v;
35   //     if (true)
36   //       v = vec4(0.0,0.0,0.0,0.0);
37   //     else
38   //       v = vec4(1.0,1.0,1.0,1.0);
39   //     gl_FragColor = v;
40   // }
41 
42   const std::string predefs =
43       R"(OpCapability Shader
44 %1 = OpExtInstImport "GLSL.std.450"
45 OpMemoryModel Logical GLSL450
46 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
47 OpExecutionMode %main OriginUpperLeft
48 OpSource GLSL 140
49 OpName %main "main"
50 OpName %v "v"
51 OpName %gl_FragColor "gl_FragColor"
52 OpName %BaseColor "BaseColor"
53 %void = OpTypeVoid
54 %7 = OpTypeFunction %void
55 %bool = OpTypeBool
56 %true = OpConstantTrue %bool
57 %float = OpTypeFloat 32
58 %v4float = OpTypeVector %float 4
59 %_ptr_Function_v4float = OpTypePointer Function %v4float
60 %float_0 = OpConstant %float 0
61 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
62 %float_1 = OpConstant %float 1
63 %16 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
64 %_ptr_Output_v4float = OpTypePointer Output %v4float
65 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
66 %_ptr_Input_v4float = OpTypePointer Input %v4float
67 %BaseColor = OpVariable %_ptr_Input_v4float Input
68 )";
69 
70   const std::string before =
71       R"(%main = OpFunction %void None %7
72 %19 = OpLabel
73 %v = OpVariable %_ptr_Function_v4float Function
74 OpSelectionMerge %20 None
75 OpBranchConditional %true %21 %22
76 %21 = OpLabel
77 OpStore %v %14
78 OpBranch %20
79 %22 = OpLabel
80 OpStore %v %16
81 OpBranch %20
82 %20 = OpLabel
83 %23 = OpLoad %v4float %v
84 OpStore %gl_FragColor %23
85 OpReturn
86 OpFunctionEnd
87 )";
88 
89   const std::string after =
90       R"(%main = OpFunction %void None %7
91 %19 = OpLabel
92 %v = OpVariable %_ptr_Function_v4float Function
93 OpBranch %21
94 %21 = OpLabel
95 OpStore %v %14
96 OpBranch %20
97 %20 = OpLabel
98 %23 = OpLoad %v4float %v
99 OpStore %gl_FragColor %23
100 OpReturn
101 OpFunctionEnd
102 )";
103 
104   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
105                                             true, true);
106 }
107 
TEST_F(DeadBranchElimTest,IfThenElseFalse)108 TEST_F(DeadBranchElimTest, IfThenElseFalse) {
109   // #version 140
110   //
111   // in vec4 BaseColor;
112   //
113   // void main()
114   // {
115   //     vec4 v;
116   //     if (false)
117   //       v = vec4(0.0,0.0,0.0,0.0);
118   //     else
119   //       v = vec4(1.0,1.0,1.0,1.0);
120   //     gl_FragColor = v;
121   // }
122 
123   const std::string predefs =
124       R"(OpCapability Shader
125 %1 = OpExtInstImport "GLSL.std.450"
126 OpMemoryModel Logical GLSL450
127 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
128 OpExecutionMode %main OriginUpperLeft
129 OpSource GLSL 140
130 OpName %main "main"
131 OpName %v "v"
132 OpName %gl_FragColor "gl_FragColor"
133 OpName %BaseColor "BaseColor"
134 %void = OpTypeVoid
135 %7 = OpTypeFunction %void
136 %bool = OpTypeBool
137 %false = OpConstantFalse %bool
138 %float = OpTypeFloat 32
139 %v4float = OpTypeVector %float 4
140 %_ptr_Function_v4float = OpTypePointer Function %v4float
141 %float_0 = OpConstant %float 0
142 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
143 %float_1 = OpConstant %float 1
144 %16 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
145 %_ptr_Output_v4float = OpTypePointer Output %v4float
146 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
147 %_ptr_Input_v4float = OpTypePointer Input %v4float
148 %BaseColor = OpVariable %_ptr_Input_v4float Input
149 )";
150 
151   const std::string before =
152       R"(%main = OpFunction %void None %7
153 %19 = OpLabel
154 %v = OpVariable %_ptr_Function_v4float Function
155 OpSelectionMerge %20 None
156 OpBranchConditional %false %21 %22
157 %21 = OpLabel
158 OpStore %v %14
159 OpBranch %20
160 %22 = OpLabel
161 OpStore %v %16
162 OpBranch %20
163 %20 = OpLabel
164 %23 = OpLoad %v4float %v
165 OpStore %gl_FragColor %23
166 OpReturn
167 OpFunctionEnd
168 )";
169 
170   const std::string after =
171       R"(%main = OpFunction %void None %7
172 %19 = OpLabel
173 %v = OpVariable %_ptr_Function_v4float Function
174 OpBranch %22
175 %22 = OpLabel
176 OpStore %v %16
177 OpBranch %20
178 %20 = OpLabel
179 %23 = OpLoad %v4float %v
180 OpStore %gl_FragColor %23
181 OpReturn
182 OpFunctionEnd
183 )";
184 
185   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
186                                             true, true);
187 }
188 
TEST_F(DeadBranchElimTest,IfThenTrue)189 TEST_F(DeadBranchElimTest, IfThenTrue) {
190   // #version 140
191   //
192   // in vec4 BaseColor;
193   //
194   // void main()
195   // {
196   //     vec4 v = BaseColor;
197   //     if (true)
198   //       v = v * vec4(0.5,0.5,0.5,0.5);
199   //     gl_FragColor = v;
200   // }
201 
202   const std::string predefs =
203       R"(OpCapability Shader
204 %1 = OpExtInstImport "GLSL.std.450"
205 OpMemoryModel Logical GLSL450
206 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
207 OpExecutionMode %main OriginUpperLeft
208 OpSource GLSL 140
209 OpName %main "main"
210 OpName %v "v"
211 OpName %BaseColor "BaseColor"
212 OpName %gl_FragColor "gl_FragColor"
213 %void = OpTypeVoid
214 %7 = OpTypeFunction %void
215 %float = OpTypeFloat 32
216 %v4float = OpTypeVector %float 4
217 %_ptr_Function_v4float = OpTypePointer Function %v4float
218 %_ptr_Input_v4float = OpTypePointer Input %v4float
219 %BaseColor = OpVariable %_ptr_Input_v4float Input
220 %bool = OpTypeBool
221 %true = OpConstantTrue %bool
222 %float_0_5 = OpConstant %float 0.5
223 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
224 %_ptr_Output_v4float = OpTypePointer Output %v4float
225 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
226 )";
227 
228   const std::string before =
229       R"(%main = OpFunction %void None %7
230 %17 = OpLabel
231 %v = OpVariable %_ptr_Function_v4float Function
232 %18 = OpLoad %v4float %BaseColor
233 OpStore %v %18
234 OpSelectionMerge %19 None
235 OpBranchConditional %true %20 %19
236 %20 = OpLabel
237 %21 = OpLoad %v4float %v
238 %22 = OpFMul %v4float %21 %15
239 OpStore %v %22
240 OpBranch %19
241 %19 = OpLabel
242 %23 = OpLoad %v4float %v
243 OpStore %gl_FragColor %23
244 OpReturn
245 OpFunctionEnd
246 )";
247 
248   const std::string after =
249       R"(%main = OpFunction %void None %7
250 %17 = OpLabel
251 %v = OpVariable %_ptr_Function_v4float Function
252 %18 = OpLoad %v4float %BaseColor
253 OpStore %v %18
254 OpBranch %20
255 %20 = OpLabel
256 %21 = OpLoad %v4float %v
257 %22 = OpFMul %v4float %21 %15
258 OpStore %v %22
259 OpBranch %19
260 %19 = OpLabel
261 %23 = OpLoad %v4float %v
262 OpStore %gl_FragColor %23
263 OpReturn
264 OpFunctionEnd
265 )";
266 
267   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
268                                             true, true);
269 }
270 
TEST_F(DeadBranchElimTest,IfThenFalse)271 TEST_F(DeadBranchElimTest, IfThenFalse) {
272   // #version 140
273   //
274   // in vec4 BaseColor;
275   //
276   // void main()
277   // {
278   //     vec4 v = BaseColor;
279   //     if (false)
280   //       v = v * vec4(0.5,0.5,0.5,0.5);
281   //     gl_FragColor = v;
282   // }
283 
284   const std::string predefs =
285       R"(OpCapability Shader
286 %1 = OpExtInstImport "GLSL.std.450"
287 OpMemoryModel Logical GLSL450
288 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
289 OpExecutionMode %main OriginUpperLeft
290 OpSource GLSL 140
291 OpName %main "main"
292 OpName %v "v"
293 OpName %BaseColor "BaseColor"
294 OpName %gl_FragColor "gl_FragColor"
295 %void = OpTypeVoid
296 %7 = OpTypeFunction %void
297 %float = OpTypeFloat 32
298 %v4float = OpTypeVector %float 4
299 %_ptr_Function_v4float = OpTypePointer Function %v4float
300 %_ptr_Input_v4float = OpTypePointer Input %v4float
301 %BaseColor = OpVariable %_ptr_Input_v4float Input
302 %bool = OpTypeBool
303 %false = OpConstantFalse %bool
304 %float_0_5 = OpConstant %float 0.5
305 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
306 %_ptr_Output_v4float = OpTypePointer Output %v4float
307 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
308 )";
309 
310   const std::string before =
311       R"(%main = OpFunction %void None %7
312 %17 = OpLabel
313 %v = OpVariable %_ptr_Function_v4float Function
314 %18 = OpLoad %v4float %BaseColor
315 OpStore %v %18
316 OpSelectionMerge %19 None
317 OpBranchConditional %false %20 %19
318 %20 = OpLabel
319 %21 = OpLoad %v4float %v
320 %22 = OpFMul %v4float %21 %15
321 OpStore %v %22
322 OpBranch %19
323 %19 = OpLabel
324 %23 = OpLoad %v4float %v
325 OpStore %gl_FragColor %23
326 OpReturn
327 OpFunctionEnd
328 )";
329 
330   const std::string after =
331       R"(%main = OpFunction %void None %7
332 %17 = OpLabel
333 %v = OpVariable %_ptr_Function_v4float Function
334 %18 = OpLoad %v4float %BaseColor
335 OpStore %v %18
336 OpBranch %19
337 %19 = OpLabel
338 %23 = OpLoad %v4float %v
339 OpStore %gl_FragColor %23
340 OpReturn
341 OpFunctionEnd
342 )";
343 
344   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
345                                             true, true);
346 }
347 
TEST_F(DeadBranchElimTest,IfThenElsePhiTrue)348 TEST_F(DeadBranchElimTest, IfThenElsePhiTrue) {
349   // Test handling of phi in merge block after dead branch elimination.
350   // Note: The SPIR-V has had store/load elimination and phi insertion
351   //
352   // #version 140
353   //
354   // void main()
355   // {
356   //     vec4 v;
357   //     if (true)
358   //       v = vec4(0.0,0.0,0.0,0.0);
359   //     else
360   //       v = vec4(1.0,1.0,1.0,1.0);
361   //     gl_FragColor = v;
362   // }
363 
364   const std::string predefs =
365       R"(OpCapability Shader
366 %1 = OpExtInstImport "GLSL.std.450"
367 OpMemoryModel Logical GLSL450
368 OpEntryPoint Fragment %main "main" %gl_FragColor
369 OpExecutionMode %main OriginUpperLeft
370 OpSource GLSL 140
371 OpName %main "main"
372 OpName %gl_FragColor "gl_FragColor"
373 %void = OpTypeVoid
374 %5 = OpTypeFunction %void
375 %bool = OpTypeBool
376 %true = OpConstantTrue %bool
377 %float = OpTypeFloat 32
378 %v4float = OpTypeVector %float 4
379 %_ptr_Function_v4float = OpTypePointer Function %v4float
380 %float_0 = OpConstant %float 0
381 %12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
382 %float_1 = OpConstant %float 1
383 %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
384 %_ptr_Output_v4float = OpTypePointer Output %v4float
385 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
386 %_ptr_Input_v4float = OpTypePointer Input %v4float
387 )";
388 
389   const std::string before =
390       R"(%main = OpFunction %void None %5
391 %17 = OpLabel
392 OpSelectionMerge %18 None
393 OpBranchConditional %true %19 %20
394 %19 = OpLabel
395 OpBranch %18
396 %20 = OpLabel
397 OpBranch %18
398 %18 = OpLabel
399 %21 = OpPhi %v4float %12 %19 %14 %20
400 OpStore %gl_FragColor %21
401 OpReturn
402 OpFunctionEnd
403 )";
404 
405   const std::string after =
406       R"(%main = OpFunction %void None %5
407 %17 = OpLabel
408 OpBranch %19
409 %19 = OpLabel
410 OpBranch %18
411 %18 = OpLabel
412 OpStore %gl_FragColor %12
413 OpReturn
414 OpFunctionEnd
415 )";
416 
417   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
418                                             true, true);
419 }
420 
TEST_F(DeadBranchElimTest,IfThenElsePhiFalse)421 TEST_F(DeadBranchElimTest, IfThenElsePhiFalse) {
422   // Test handling of phi in merge block after dead branch elimination.
423   // Note: The SPIR-V has had store/load elimination and phi insertion
424   //
425   // #version 140
426   //
427   // void main()
428   // {
429   //     vec4 v;
430   //     if (true)
431   //       v = vec4(0.0,0.0,0.0,0.0);
432   //     else
433   //       v = vec4(1.0,1.0,1.0,1.0);
434   //     gl_FragColor = v;
435   // }
436 
437   const std::string predefs =
438       R"(OpCapability Shader
439 %1 = OpExtInstImport "GLSL.std.450"
440 OpMemoryModel Logical GLSL450
441 OpEntryPoint Fragment %main "main" %gl_FragColor
442 OpExecutionMode %main OriginUpperLeft
443 OpSource GLSL 140
444 OpName %main "main"
445 OpName %gl_FragColor "gl_FragColor"
446 %void = OpTypeVoid
447 %5 = OpTypeFunction %void
448 %bool = OpTypeBool
449 %false = OpConstantFalse %bool
450 %float = OpTypeFloat 32
451 %v4float = OpTypeVector %float 4
452 %_ptr_Function_v4float = OpTypePointer Function %v4float
453 %float_0 = OpConstant %float 0
454 %12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
455 %float_1 = OpConstant %float 1
456 %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
457 %_ptr_Output_v4float = OpTypePointer Output %v4float
458 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
459 %_ptr_Input_v4float = OpTypePointer Input %v4float
460 )";
461 
462   const std::string before =
463       R"(%main = OpFunction %void None %5
464 %17 = OpLabel
465 OpSelectionMerge %18 None
466 OpBranchConditional %false %19 %20
467 %19 = OpLabel
468 OpBranch %18
469 %20 = OpLabel
470 OpBranch %18
471 %18 = OpLabel
472 %21 = OpPhi %v4float %12 %19 %14 %20
473 OpStore %gl_FragColor %21
474 OpReturn
475 OpFunctionEnd
476 )";
477 
478   const std::string after =
479       R"(%main = OpFunction %void None %5
480 %17 = OpLabel
481 OpBranch %20
482 %20 = OpLabel
483 OpBranch %18
484 %18 = OpLabel
485 OpStore %gl_FragColor %14
486 OpReturn
487 OpFunctionEnd
488 )";
489 
490   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
491                                             true, true);
492 }
493 
TEST_F(DeadBranchElimTest,CompoundIfThenElseFalse)494 TEST_F(DeadBranchElimTest, CompoundIfThenElseFalse) {
495   // #version 140
496   //
497   // layout(std140) uniform U_t
498   // {
499   //     bool g_B ;
500   // } ;
501   //
502   // void main()
503   // {
504   //     vec4 v;
505   //     if (false) {
506   //       if (g_B)
507   //         v = vec4(0.0,0.0,0.0,0.0);
508   //       else
509   //         v = vec4(1.0,1.0,1.0,1.0);
510   //     } else {
511   //       if (g_B)
512   //         v = vec4(1.0,1.0,1.0,1.0);
513   //       else
514   //         v = vec4(0.0,0.0,0.0,0.0);
515   //     }
516   //     gl_FragColor = v;
517   // }
518 
519   const std::string predefs =
520       R"(OpCapability Shader
521 %1 = OpExtInstImport "GLSL.std.450"
522 OpMemoryModel Logical GLSL450
523 OpEntryPoint Fragment %main "main" %gl_FragColor
524 OpExecutionMode %main OriginUpperLeft
525 OpSource GLSL 140
526 OpName %main "main"
527 OpName %U_t "U_t"
528 OpMemberName %U_t 0 "g_B"
529 OpName %_ ""
530 OpName %v "v"
531 OpName %gl_FragColor "gl_FragColor"
532 OpMemberDecorate %U_t 0 Offset 0
533 OpDecorate %U_t Block
534 OpDecorate %_ DescriptorSet 0
535 %void = OpTypeVoid
536 %8 = OpTypeFunction %void
537 %bool = OpTypeBool
538 %false = OpConstantFalse %bool
539 %uint = OpTypeInt 32 0
540 %U_t = OpTypeStruct %uint
541 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
542 %_ = OpVariable %_ptr_Uniform_U_t Uniform
543 %int = OpTypeInt 32 1
544 %int_0 = OpConstant %int 0
545 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
546 %uint_0 = OpConstant %uint 0
547 %float = OpTypeFloat 32
548 %v4float = OpTypeVector %float 4
549 %_ptr_Function_v4float = OpTypePointer Function %v4float
550 %float_0 = OpConstant %float 0
551 %21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
552 %float_1 = OpConstant %float 1
553 %23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
554 %_ptr_Output_v4float = OpTypePointer Output %v4float
555 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
556 )";
557 
558   const std::string before =
559       R"(%main = OpFunction %void None %8
560 %25 = OpLabel
561 %v = OpVariable %_ptr_Function_v4float Function
562 OpSelectionMerge %26 None
563 OpBranchConditional %false %27 %28
564 %27 = OpLabel
565 %29 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
566 %30 = OpLoad %uint %29
567 %31 = OpINotEqual %bool %30 %uint_0
568 OpSelectionMerge %32 None
569 OpBranchConditional %31 %33 %34
570 %33 = OpLabel
571 OpStore %v %21
572 OpBranch %32
573 %34 = OpLabel
574 OpStore %v %23
575 OpBranch %32
576 %32 = OpLabel
577 OpBranch %26
578 %28 = OpLabel
579 %35 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
580 %36 = OpLoad %uint %35
581 %37 = OpINotEqual %bool %36 %uint_0
582 OpSelectionMerge %38 None
583 OpBranchConditional %37 %39 %40
584 %39 = OpLabel
585 OpStore %v %23
586 OpBranch %38
587 %40 = OpLabel
588 OpStore %v %21
589 OpBranch %38
590 %38 = OpLabel
591 OpBranch %26
592 %26 = OpLabel
593 %41 = OpLoad %v4float %v
594 OpStore %gl_FragColor %41
595 OpReturn
596 OpFunctionEnd
597 )";
598 
599   const std::string after =
600       R"(%main = OpFunction %void None %8
601 %25 = OpLabel
602 %v = OpVariable %_ptr_Function_v4float Function
603 OpBranch %28
604 %28 = OpLabel
605 %35 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
606 %36 = OpLoad %uint %35
607 %37 = OpINotEqual %bool %36 %uint_0
608 OpSelectionMerge %38 None
609 OpBranchConditional %37 %39 %40
610 %40 = OpLabel
611 OpStore %v %21
612 OpBranch %38
613 %39 = OpLabel
614 OpStore %v %23
615 OpBranch %38
616 %38 = OpLabel
617 OpBranch %26
618 %26 = OpLabel
619 %41 = OpLoad %v4float %v
620 OpStore %gl_FragColor %41
621 OpReturn
622 OpFunctionEnd
623 )";
624 
625   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
626                                             true, true);
627 }
628 
TEST_F(DeadBranchElimTest,PreventOrphanMerge)629 TEST_F(DeadBranchElimTest, PreventOrphanMerge) {
630   const std::string predefs =
631       R"(OpCapability Shader
632 %1 = OpExtInstImport "GLSL.std.450"
633 OpMemoryModel Logical GLSL450
634 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
635 OpExecutionMode %main OriginUpperLeft
636 OpSource GLSL 140
637 OpName %main "main"
638 OpName %v "v"
639 OpName %BaseColor "BaseColor"
640 OpName %gl_FragColor "gl_FragColor"
641 %void = OpTypeVoid
642 %7 = OpTypeFunction %void
643 %float = OpTypeFloat 32
644 %v4float = OpTypeVector %float 4
645 %_ptr_Function_v4float = OpTypePointer Function %v4float
646 %_ptr_Input_v4float = OpTypePointer Input %v4float
647 %BaseColor = OpVariable %_ptr_Input_v4float Input
648 %bool = OpTypeBool
649 %true = OpConstantTrue %bool
650 %float_0_5 = OpConstant %float 0.5
651 %_ptr_Output_v4float = OpTypePointer Output %v4float
652 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
653 )";
654 
655   const std::string before =
656       R"(%main = OpFunction %void None %7
657 %16 = OpLabel
658 %v = OpVariable %_ptr_Function_v4float Function
659 %17 = OpLoad %v4float %BaseColor
660 OpStore %v %17
661 OpSelectionMerge %18 None
662 OpBranchConditional %true %19 %20
663 %19 = OpLabel
664 OpKill
665 %20 = OpLabel
666 %21 = OpLoad %v4float %v
667 %22 = OpVectorTimesScalar %v4float %21 %float_0_5
668 OpStore %v %22
669 OpBranch %18
670 %18 = OpLabel
671 %23 = OpLoad %v4float %v
672 OpStore %gl_FragColor %23
673 OpReturn
674 OpFunctionEnd
675 )";
676 
677   const std::string after =
678       R"(%main = OpFunction %void None %7
679 %16 = OpLabel
680 %v = OpVariable %_ptr_Function_v4float Function
681 %17 = OpLoad %v4float %BaseColor
682 OpStore %v %17
683 OpBranch %19
684 %19 = OpLabel
685 OpKill
686 OpFunctionEnd
687 )";
688 
689   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
690                                             true, true);
691 }
692 
TEST_F(DeadBranchElimTest,HandleOrphanMerge)693 TEST_F(DeadBranchElimTest, HandleOrphanMerge) {
694   const std::string predefs =
695       R"(OpCapability Shader
696 %1 = OpExtInstImport "GLSL.std.450"
697 OpMemoryModel Logical GLSL450
698 OpEntryPoint Fragment %main "main" %gl_FragColor
699 OpExecutionMode %main OriginUpperLeft
700 OpSource GLSL 140
701 OpName %main "main"
702 OpName %foo_ "foo("
703 OpName %gl_FragColor "gl_FragColor"
704 OpDecorate %gl_FragColor Location 0
705 %void = OpTypeVoid
706 %6 = OpTypeFunction %void
707 %float = OpTypeFloat 32
708 %v4float = OpTypeVector %float 4
709 %9 = OpTypeFunction %v4float
710 %bool = OpTypeBool
711 %true = OpConstantTrue %bool
712 %float_0 = OpConstant %float 0
713 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
714 %float_1 = OpConstant %float 1
715 %15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
716 %_ptr_Output_v4float = OpTypePointer Output %v4float
717 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
718 %main = OpFunction %void None %6
719 %17 = OpLabel
720 %18 = OpFunctionCall %v4float %foo_
721 OpStore %gl_FragColor %18
722 OpReturn
723 OpFunctionEnd
724 )";
725 
726   const std::string before =
727       R"(%foo_ = OpFunction %v4float None %9
728 %19 = OpLabel
729 OpSelectionMerge %20 None
730 OpBranchConditional %true %21 %22
731 %21 = OpLabel
732 OpReturnValue %13
733 %22 = OpLabel
734 OpReturnValue %15
735 %20 = OpLabel
736 %23 = OpUndef %v4float
737 OpReturnValue %23
738 OpFunctionEnd
739 )";
740 
741   const std::string after =
742       R"(%foo_ = OpFunction %v4float None %9
743 %19 = OpLabel
744 OpBranch %21
745 %21 = OpLabel
746 OpReturnValue %13
747 OpFunctionEnd
748 )";
749 
750   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
751                                             true, true);
752 }
753 
TEST_F(DeadBranchElimTest,KeepContinueTargetWhenKillAfterMerge)754 TEST_F(DeadBranchElimTest, KeepContinueTargetWhenKillAfterMerge) {
755   // #version 450
756   // void main() {
757   //   bool c;
758   //   bool d;
759   //   while(c) {
760   //     if(d) {
761   //      continue;
762   //     }
763   //     if(false) {
764   //      continue;
765   //     }
766   //     discard;
767   //   }
768   // }
769 
770   const std::string predefs =
771       R"(OpCapability Shader
772 %1 = OpExtInstImport "GLSL.std.450"
773 OpMemoryModel Logical GLSL450
774 OpEntryPoint Fragment %main "main"
775 OpExecutionMode %main OriginUpperLeft
776 OpSource GLSL 450
777 OpName %main "main"
778 OpName %c "c"
779 OpName %d "d"
780 %void = OpTypeVoid
781 %6 = OpTypeFunction %void
782 %bool = OpTypeBool
783 %_ptr_Function_bool = OpTypePointer Function %bool
784 %false = OpConstantFalse %bool
785 )";
786 
787   const std::string before =
788       R"(%main = OpFunction %void None %6
789 %10 = OpLabel
790 %c = OpVariable %_ptr_Function_bool Function
791 %d = OpVariable %_ptr_Function_bool Function
792 OpBranch %11
793 %11 = OpLabel
794 OpLoopMerge %12 %13 None
795 OpBranch %14
796 %14 = OpLabel
797 %15 = OpLoad %bool %c
798 OpBranchConditional %15 %16 %12
799 %16 = OpLabel
800 %17 = OpLoad %bool %d
801 OpSelectionMerge %18 None
802 OpBranchConditional %17 %19 %18
803 %19 = OpLabel
804 OpBranch %13
805 %18 = OpLabel
806 OpSelectionMerge %20 None
807 OpBranchConditional %false %21 %20
808 %21 = OpLabel
809 OpBranch %13
810 %20 = OpLabel
811 OpKill
812 %13 = OpLabel
813 OpBranch %11
814 %12 = OpLabel
815 OpReturn
816 OpFunctionEnd
817 )";
818 
819   const std::string after =
820       R"(%main = OpFunction %void None %6
821 %10 = OpLabel
822 %c = OpVariable %_ptr_Function_bool Function
823 %d = OpVariable %_ptr_Function_bool Function
824 OpBranch %11
825 %11 = OpLabel
826 OpLoopMerge %12 %13 None
827 OpBranch %14
828 %14 = OpLabel
829 %15 = OpLoad %bool %c
830 OpBranchConditional %15 %16 %12
831 %16 = OpLabel
832 %17 = OpLoad %bool %d
833 OpSelectionMerge %18 None
834 OpBranchConditional %17 %19 %18
835 %19 = OpLabel
836 OpBranch %13
837 %18 = OpLabel
838 OpBranch %20
839 %20 = OpLabel
840 OpKill
841 %13 = OpLabel
842 OpBranch %11
843 %12 = OpLabel
844 OpReturn
845 OpFunctionEnd
846 )";
847 
848   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
849                                             true, true);
850 }
851 
TEST_F(DeadBranchElimTest,DecorateDeleted)852 TEST_F(DeadBranchElimTest, DecorateDeleted) {
853   // Note: SPIR-V hand-edited to add decoration
854   // #version 140
855   //
856   // in vec4 BaseColor;
857   //
858   // void main()
859   // {
860   //     vec4 v = BaseColor;
861   //     if (false)
862   //       v = v * vec4(0.5,0.5,0.5,0.5);
863   //     gl_FragColor = v;
864   // }
865 
866   const std::string predefs_before =
867       R"(OpCapability Shader
868 %1 = OpExtInstImport "GLSL.std.450"
869 OpMemoryModel Logical GLSL450
870 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
871 OpExecutionMode %main OriginUpperLeft
872 OpSource GLSL 140
873 OpName %main "main"
874 OpName %v "v"
875 OpName %BaseColor "BaseColor"
876 OpName %gl_FragColor "gl_FragColor"
877 OpDecorate %22 RelaxedPrecision
878 %void = OpTypeVoid
879 %7 = OpTypeFunction %void
880 %float = OpTypeFloat 32
881 %v4float = OpTypeVector %float 4
882 %_ptr_Function_v4float = OpTypePointer Function %v4float
883 %_ptr_Input_v4float = OpTypePointer Input %v4float
884 %BaseColor = OpVariable %_ptr_Input_v4float Input
885 %bool = OpTypeBool
886 %false = OpConstantFalse %bool
887 %float_0_5 = OpConstant %float 0.5
888 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
889 %_ptr_Output_v4float = OpTypePointer Output %v4float
890 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
891 )";
892 
893   const std::string predefs_after =
894       R"(OpCapability Shader
895 %1 = OpExtInstImport "GLSL.std.450"
896 OpMemoryModel Logical GLSL450
897 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
898 OpExecutionMode %main OriginUpperLeft
899 OpSource GLSL 140
900 OpName %main "main"
901 OpName %v "v"
902 OpName %BaseColor "BaseColor"
903 OpName %gl_FragColor "gl_FragColor"
904 %void = OpTypeVoid
905 %8 = OpTypeFunction %void
906 %float = OpTypeFloat 32
907 %v4float = OpTypeVector %float 4
908 %_ptr_Function_v4float = OpTypePointer Function %v4float
909 %_ptr_Input_v4float = OpTypePointer Input %v4float
910 %BaseColor = OpVariable %_ptr_Input_v4float Input
911 %bool = OpTypeBool
912 %false = OpConstantFalse %bool
913 %float_0_5 = OpConstant %float 0.5
914 %16 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
915 %_ptr_Output_v4float = OpTypePointer Output %v4float
916 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
917 )";
918 
919   const std::string before =
920       R"(%main = OpFunction %void None %7
921 %17 = OpLabel
922 %v = OpVariable %_ptr_Function_v4float Function
923 %18 = OpLoad %v4float %BaseColor
924 OpStore %v %18
925 OpSelectionMerge %19 None
926 OpBranchConditional %false %20 %19
927 %20 = OpLabel
928 %21 = OpLoad %v4float %v
929 %22 = OpFMul %v4float %21 %15
930 OpStore %v %22
931 OpBranch %19
932 %19 = OpLabel
933 %23 = OpLoad %v4float %v
934 OpStore %gl_FragColor %23
935 OpReturn
936 OpFunctionEnd
937 )";
938 
939   const std::string after =
940       R"(%main = OpFunction %void None %8
941 %18 = OpLabel
942 %v = OpVariable %_ptr_Function_v4float Function
943 %19 = OpLoad %v4float %BaseColor
944 OpStore %v %19
945 OpBranch %20
946 %20 = OpLabel
947 %23 = OpLoad %v4float %v
948 OpStore %gl_FragColor %23
949 OpReturn
950 OpFunctionEnd
951 )";
952 
953   SinglePassRunAndCheck<DeadBranchElimPass>(predefs_before + before,
954                                             predefs_after + after, true, true);
955 }
956 
TEST_F(DeadBranchElimTest,LoopInDeadBranch)957 TEST_F(DeadBranchElimTest, LoopInDeadBranch) {
958   // #version 450
959   //
960   // layout(location = 0) in vec4 BaseColor;
961   // layout(location = 0) out vec4 OutColor;
962   //
963   // void main()
964   // {
965   //     vec4 v = BaseColor;
966   //     if (false)
967   //       for (int i=0; i<3; i++)
968   //         v = v * 0.5;
969   //     OutColor = v;
970   // }
971 
972   const std::string predefs =
973       R"(OpCapability Shader
974 %1 = OpExtInstImport "GLSL.std.450"
975 OpMemoryModel Logical GLSL450
976 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
977 OpExecutionMode %main OriginUpperLeft
978 OpSource GLSL 450
979 OpName %main "main"
980 OpName %v "v"
981 OpName %BaseColor "BaseColor"
982 OpName %i "i"
983 OpName %OutColor "OutColor"
984 OpDecorate %BaseColor Location 0
985 OpDecorate %OutColor Location 0
986 %void = OpTypeVoid
987 %8 = OpTypeFunction %void
988 %float = OpTypeFloat 32
989 %v4float = OpTypeVector %float 4
990 %_ptr_Function_v4float = OpTypePointer Function %v4float
991 %_ptr_Input_v4float = OpTypePointer Input %v4float
992 %BaseColor = OpVariable %_ptr_Input_v4float Input
993 %bool = OpTypeBool
994 %false = OpConstantFalse %bool
995 %int = OpTypeInt 32 1
996 %_ptr_Function_int = OpTypePointer Function %int
997 %int_0 = OpConstant %int 0
998 %int_3 = OpConstant %int 3
999 %float_0_5 = OpConstant %float 0.5
1000 %int_1 = OpConstant %int 1
1001 %_ptr_Output_v4float = OpTypePointer Output %v4float
1002 %OutColor = OpVariable %_ptr_Output_v4float Output
1003 )";
1004 
1005   const std::string before =
1006       R"(%main = OpFunction %void None %8
1007 %22 = OpLabel
1008 %v = OpVariable %_ptr_Function_v4float Function
1009 %i = OpVariable %_ptr_Function_int Function
1010 %23 = OpLoad %v4float %BaseColor
1011 OpStore %v %23
1012 OpSelectionMerge %24 None
1013 OpBranchConditional %false %25 %24
1014 %25 = OpLabel
1015 OpStore %i %int_0
1016 OpBranch %26
1017 %26 = OpLabel
1018 OpLoopMerge %27 %28 None
1019 OpBranch %29
1020 %29 = OpLabel
1021 %30 = OpLoad %int %i
1022 %31 = OpSLessThan %bool %30 %int_3
1023 OpBranchConditional %31 %32 %27
1024 %32 = OpLabel
1025 %33 = OpLoad %v4float %v
1026 %34 = OpVectorTimesScalar %v4float %33 %float_0_5
1027 OpStore %v %34
1028 OpBranch %28
1029 %28 = OpLabel
1030 %35 = OpLoad %int %i
1031 %36 = OpIAdd %int %35 %int_1
1032 OpStore %i %36
1033 OpBranch %26
1034 %27 = OpLabel
1035 OpBranch %24
1036 %24 = OpLabel
1037 %37 = OpLoad %v4float %v
1038 OpStore %OutColor %37
1039 OpReturn
1040 OpFunctionEnd
1041 )";
1042 
1043   const std::string after =
1044       R"(%main = OpFunction %void None %8
1045 %22 = OpLabel
1046 %v = OpVariable %_ptr_Function_v4float Function
1047 %i = OpVariable %_ptr_Function_int Function
1048 %23 = OpLoad %v4float %BaseColor
1049 OpStore %v %23
1050 OpBranch %24
1051 %24 = OpLabel
1052 %37 = OpLoad %v4float %v
1053 OpStore %OutColor %37
1054 OpReturn
1055 OpFunctionEnd
1056 )";
1057 
1058   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
1059                                             true, true);
1060 }
1061 
TEST_F(DeadBranchElimTest,SwitchLiveCase)1062 TEST_F(DeadBranchElimTest, SwitchLiveCase) {
1063   // #version 450
1064   //
1065   // layout (location=0) in vec4 BaseColor;
1066   // layout (location=0) out vec4 OutColor;
1067   //
1068   // void main()
1069   // {
1070   //     switch (1) {
1071   //       case 0:
1072   //         OutColor = vec4(0.0,0.0,0.0,0.0);
1073   //         break;
1074   //       case 1:
1075   //         OutColor = vec4(0.125,0.125,0.125,0.125);
1076   //         break;
1077   //       case 2:
1078   //         OutColor = vec4(0.25,0.25,0.25,0.25);
1079   //         break;
1080   //       default:
1081   //         OutColor = vec4(1.0,1.0,1.0,1.0);
1082   //     }
1083   // }
1084 
1085   const std::string predefs =
1086       R"(OpCapability Shader
1087 %1 = OpExtInstImport "GLSL.std.450"
1088 OpMemoryModel Logical GLSL450
1089 OpEntryPoint Fragment %main "main" %OutColor %BaseColor
1090 OpExecutionMode %main OriginUpperLeft
1091 OpSource GLSL 450
1092 OpName %main "main"
1093 OpName %OutColor "OutColor"
1094 OpName %BaseColor "BaseColor"
1095 OpDecorate %OutColor Location 0
1096 OpDecorate %BaseColor Location 0
1097 %void = OpTypeVoid
1098 %6 = OpTypeFunction %void
1099 %int = OpTypeInt 32 1
1100 %int_1 = OpConstant %int 1
1101 %float = OpTypeFloat 32
1102 %v4float = OpTypeVector %float 4
1103 %_ptr_Output_v4float = OpTypePointer Output %v4float
1104 %OutColor = OpVariable %_ptr_Output_v4float Output
1105 %float_0 = OpConstant %float 0
1106 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1107 %float_0_125 = OpConstant %float 0.125
1108 %15 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
1109 %float_0_25 = OpConstant %float 0.25
1110 %17 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
1111 %float_1 = OpConstant %float 1
1112 %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1113 %_ptr_Input_v4float = OpTypePointer Input %v4float
1114 %BaseColor = OpVariable %_ptr_Input_v4float Input
1115 )";
1116 
1117   const std::string before =
1118       R"(%main = OpFunction %void None %6
1119 %21 = OpLabel
1120 OpSelectionMerge %22 None
1121 OpSwitch %int_1 %23 0 %24 1 %25 2 %26
1122 %23 = OpLabel
1123 OpStore %OutColor %19
1124 OpBranch %22
1125 %24 = OpLabel
1126 OpStore %OutColor %13
1127 OpBranch %22
1128 %25 = OpLabel
1129 OpStore %OutColor %15
1130 OpBranch %22
1131 %26 = OpLabel
1132 OpStore %OutColor %17
1133 OpBranch %22
1134 %22 = OpLabel
1135 OpReturn
1136 OpFunctionEnd
1137 )";
1138 
1139   const std::string after =
1140       R"(%main = OpFunction %void None %6
1141 %21 = OpLabel
1142 OpBranch %25
1143 %25 = OpLabel
1144 OpStore %OutColor %15
1145 OpBranch %22
1146 %22 = OpLabel
1147 OpReturn
1148 OpFunctionEnd
1149 )";
1150 
1151   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
1152                                             true, true);
1153 }
1154 
TEST_F(DeadBranchElimTest,SwitchLiveDefault)1155 TEST_F(DeadBranchElimTest, SwitchLiveDefault) {
1156   // #version 450
1157   //
1158   // layout (location=0) in vec4 BaseColor;
1159   // layout (location=0) out vec4 OutColor;
1160   //
1161   // void main()
1162   // {
1163   //     switch (7) {
1164   //       case 0:
1165   //         OutColor = vec4(0.0,0.0,0.0,0.0);
1166   //         break;
1167   //       case 1:
1168   //         OutColor = vec4(0.125,0.125,0.125,0.125);
1169   //         break;
1170   //       case 2:
1171   //         OutColor = vec4(0.25,0.25,0.25,0.25);
1172   //         break;
1173   //       default:
1174   //         OutColor = vec4(1.0,1.0,1.0,1.0);
1175   //     }
1176   // }
1177 
1178   const std::string predefs =
1179       R"(OpCapability Shader
1180 %1 = OpExtInstImport "GLSL.std.450"
1181 OpMemoryModel Logical GLSL450
1182 OpEntryPoint Fragment %main "main" %OutColor %BaseColor
1183 OpExecutionMode %main OriginUpperLeft
1184 OpSource GLSL 450
1185 OpName %main "main"
1186 OpName %OutColor "OutColor"
1187 OpName %BaseColor "BaseColor"
1188 OpDecorate %OutColor Location 0
1189 OpDecorate %BaseColor Location 0
1190 %void = OpTypeVoid
1191 %6 = OpTypeFunction %void
1192 %int = OpTypeInt 32 1
1193 %int_7 = OpConstant %int 7
1194 %float = OpTypeFloat 32
1195 %v4float = OpTypeVector %float 4
1196 %_ptr_Output_v4float = OpTypePointer Output %v4float
1197 %OutColor = OpVariable %_ptr_Output_v4float Output
1198 %float_0 = OpConstant %float 0
1199 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1200 %float_0_125 = OpConstant %float 0.125
1201 %15 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
1202 %float_0_25 = OpConstant %float 0.25
1203 %17 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
1204 %float_1 = OpConstant %float 1
1205 %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1206 %_ptr_Input_v4float = OpTypePointer Input %v4float
1207 %BaseColor = OpVariable %_ptr_Input_v4float Input
1208 )";
1209 
1210   const std::string before =
1211       R"(%main = OpFunction %void None %6
1212 %21 = OpLabel
1213 OpSelectionMerge %22 None
1214 OpSwitch %int_7 %23 0 %24 1 %25 2 %26
1215 %23 = OpLabel
1216 OpStore %OutColor %19
1217 OpBranch %22
1218 %24 = OpLabel
1219 OpStore %OutColor %13
1220 OpBranch %22
1221 %25 = OpLabel
1222 OpStore %OutColor %15
1223 OpBranch %22
1224 %26 = OpLabel
1225 OpStore %OutColor %17
1226 OpBranch %22
1227 %22 = OpLabel
1228 OpReturn
1229 OpFunctionEnd
1230 )";
1231 
1232   const std::string after =
1233       R"(%main = OpFunction %void None %6
1234 %21 = OpLabel
1235 OpBranch %23
1236 %23 = OpLabel
1237 OpStore %OutColor %19
1238 OpBranch %22
1239 %22 = OpLabel
1240 OpReturn
1241 OpFunctionEnd
1242 )";
1243 
1244   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
1245                                             true, true);
1246 }
1247 
TEST_F(DeadBranchElimTest,SwitchLiveCaseBreakFromLoop)1248 TEST_F(DeadBranchElimTest, SwitchLiveCaseBreakFromLoop) {
1249   // This sample does not directly translate to GLSL/HLSL as
1250   // direct breaks from a loop cannot be made from a switch.
1251   // This construct is currently formed by inlining a function
1252   // containing early returns from the cases of a switch. The
1253   // function is wrapped in a one-trip loop and returns are
1254   // translated to branches to the loop's merge block.
1255 
1256   const std::string predefs =
1257       R"(OpCapability Shader
1258 %1 = OpExtInstImport "GLSL.std.450"
1259 OpMemoryModel Logical GLSL450
1260 OpEntryPoint Fragment %main "main" %OutColor %BaseColor
1261 OpExecutionMode %main OriginUpperLeft
1262 OpSource GLSL 450
1263 OpName %main "main"
1264 OpName %oc "oc"
1265 OpName %OutColor "OutColor"
1266 OpName %BaseColor "BaseColor"
1267 OpDecorate %OutColor Location 0
1268 OpDecorate %BaseColor Location 0
1269 %void = OpTypeVoid
1270 %7 = OpTypeFunction %void
1271 %bool = OpTypeBool
1272 %true = OpConstantTrue %bool
1273 %false = OpConstantFalse %bool
1274 %int = OpTypeInt 32 1
1275 %int_1 = OpConstant %int 1
1276 %float = OpTypeFloat 32
1277 %v4float = OpTypeVector %float 4
1278 %_ptr_Function_v4float = OpTypePointer Function %v4float
1279 %float_0 = OpConstant %float 0
1280 %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1281 %float_0_125 = OpConstant %float 0.125
1282 %19 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
1283 %float_0_25 = OpConstant %float 0.25
1284 %21 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
1285 %float_1 = OpConstant %float 1
1286 %23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1287 %_ptr_Output_v4float = OpTypePointer Output %v4float
1288 %OutColor = OpVariable %_ptr_Output_v4float Output
1289 %_ptr_Input_v4float = OpTypePointer Input %v4float
1290 %BaseColor = OpVariable %_ptr_Input_v4float Input
1291 )";
1292 
1293   const std::string before =
1294       R"(%main = OpFunction %void None %7
1295 %26 = OpLabel
1296 %oc = OpVariable %_ptr_Function_v4float Function
1297 OpBranch %27
1298 %27 = OpLabel
1299 OpLoopMerge %28 %29 None
1300 OpBranch %30
1301 %30 = OpLabel
1302 OpSelectionMerge %31 None
1303 OpSwitch %int_1 %31 0 %32 1 %33 2 %34
1304 %32 = OpLabel
1305 OpStore %oc %17
1306 OpBranch %28
1307 %33 = OpLabel
1308 OpStore %oc %19
1309 OpBranch %28
1310 %34 = OpLabel
1311 OpStore %oc %21
1312 OpBranch %28
1313 %31 = OpLabel
1314 OpStore %oc %23
1315 OpBranch %28
1316 %29 = OpLabel
1317 OpBranchConditional %false %27 %28
1318 %28 = OpLabel
1319 %35 = OpLoad %v4float %oc
1320 OpStore %OutColor %35
1321 OpReturn
1322 OpFunctionEnd
1323 )";
1324 
1325   const std::string after =
1326       R"(%main = OpFunction %void None %7
1327 %26 = OpLabel
1328 %oc = OpVariable %_ptr_Function_v4float Function
1329 OpBranch %27
1330 %27 = OpLabel
1331 OpLoopMerge %28 %29 None
1332 OpBranch %30
1333 %30 = OpLabel
1334 OpBranch %33
1335 %33 = OpLabel
1336 OpStore %oc %19
1337 OpBranch %28
1338 %29 = OpLabel
1339 OpBranch %27
1340 %28 = OpLabel
1341 %35 = OpLoad %v4float %oc
1342 OpStore %OutColor %35
1343 OpReturn
1344 OpFunctionEnd
1345 )";
1346 
1347   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
1348                                             true, true);
1349 }
1350 
TEST_F(DeadBranchElimTest,LeaveContinueBackedge)1351 TEST_F(DeadBranchElimTest, LeaveContinueBackedge) {
1352   const std::string text = R"(
1353 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1354 ; CHECK: [[continue]] = OpLabel
1355 ; CHECK-NEXT: OpBranchConditional {{%\w+}} {{%\w+}} [[merge]]
1356 ; CHECK-NEXT: [[merge]] = OpLabel
1357 ; CHECK-NEXT: OpReturn
1358 OpCapability Kernel
1359 OpCapability Linkage
1360 OpMemoryModel Logical OpenCL
1361 %bool = OpTypeBool
1362 %false = OpConstantFalse %bool
1363 %void = OpTypeVoid
1364 %funcTy = OpTypeFunction %void
1365 %func = OpFunction %void None %funcTy
1366 %1 = OpLabel
1367 OpBranch %2
1368 %2 = OpLabel
1369 OpLoopMerge %3 %4 None
1370 OpBranch %4
1371 %4 = OpLabel
1372 ; Be careful we don't remove the backedge to %2 despite never taking it.
1373 OpBranchConditional %false %2 %3
1374 %3 = OpLabel
1375 OpReturn
1376 OpFunctionEnd
1377 )";
1378 
1379   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1380 }
TEST_F(DeadBranchElimTest,LeaveContinueBackedgeExtraBlock)1381 TEST_F(DeadBranchElimTest, LeaveContinueBackedgeExtraBlock) {
1382   const std::string text = R"(
1383 ; CHECK: OpBranch [[header:%\w+]]
1384 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1385 ; CHECK-NEXT: OpBranch [[continue]]
1386 ; CHECK-NEXT: [[continue]] = OpLabel
1387 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[extra:%\w+]] [[merge]]
1388 ; CHECK-NEXT: [[extra]] = OpLabel
1389 ; CHECK-NEXT: OpBranch [[header]]
1390 ; CHECK-NEXT: [[merge]] = OpLabel
1391 ; CHECK-NEXT: OpReturn
1392 OpCapability Kernel
1393 OpCapability Linkage
1394 OpMemoryModel Logical OpenCL
1395 %bool = OpTypeBool
1396 %false = OpConstantFalse %bool
1397 %void = OpTypeVoid
1398 %funcTy = OpTypeFunction %void
1399 %func = OpFunction %void None %funcTy
1400 %1 = OpLabel
1401 OpBranch %2
1402 %2 = OpLabel
1403 OpLoopMerge %3 %4 None
1404 OpBranch %4
1405 %4 = OpLabel
1406 ; Be careful we don't remove the backedge to %2 despite never taking it.
1407 OpBranchConditional %false %5 %3
1408 ; This block remains live despite being unreachable.
1409 %5 = OpLabel
1410 OpBranch %2
1411 %3 = OpLabel
1412 OpReturn
1413 OpFunctionEnd
1414 )";
1415 
1416   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1417 }
1418 
TEST_F(DeadBranchElimTest,RemovePhiWithUnreachableContinue)1419 TEST_F(DeadBranchElimTest, RemovePhiWithUnreachableContinue) {
1420   const std::string text = R"(
1421 ; CHECK: [[entry:%\w+]] = OpLabel
1422 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1423 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1424 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
1425 ; CHECK-NEXT: [[ret]] = OpLabel
1426 ; CHECK-NEXT: OpReturn
1427 ; CHECK: [[continue]] = OpLabel
1428 ; CHECK-NEXT: OpBranch [[header]]
1429 ; CHECK: [[merge]] = OpLabel
1430 ; CHECK-NEXT: OpUnreachable
1431 OpCapability Kernel
1432 OpCapability Linkage
1433 OpMemoryModel Logical OpenCL
1434 OpName %func "func"
1435 OpDecorate %func LinkageAttributes "func" Export
1436 %bool = OpTypeBool
1437 %false = OpConstantFalse %bool
1438 %true = OpConstantTrue %bool
1439 %void = OpTypeVoid
1440 %funcTy = OpTypeFunction %void
1441 %func = OpFunction %void None %funcTy
1442 %1 = OpLabel
1443 OpBranch %2
1444 %2 = OpLabel
1445 %phi = OpPhi %bool %false %1 %true %continue
1446 OpLoopMerge %merge %continue None
1447 OpBranch %3
1448 %3 = OpLabel
1449 OpReturn
1450 %continue = OpLabel
1451 OpBranch %2
1452 %merge = OpLabel
1453 OpReturn
1454 OpFunctionEnd
1455 )";
1456 
1457   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1458 }
1459 
TEST_F(DeadBranchElimTest,UnreachableLoopMergeAndContinueTargets)1460 TEST_F(DeadBranchElimTest, UnreachableLoopMergeAndContinueTargets) {
1461   const std::string text = R"(
1462 ; CHECK: [[undef:%\w+]] = OpUndef %bool
1463 ; CHECK: OpSelectionMerge [[header:%\w+]]
1464 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_lab:%\w+]] [[else_lab:%\w+]]
1465 ; CHECK: OpPhi %bool %false [[if_lab]] %false [[else_lab]] [[undef]] [[continue:%\w+]]
1466 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
1467 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
1468 ; CHECK-NEXT: [[ret]] = OpLabel
1469 ; CHECK-NEXT: OpReturn
1470 ; CHECK: [[continue]] = OpLabel
1471 ; CHECK-NEXT: OpBranch [[header]]
1472 ; CHECK: [[merge]] = OpLabel
1473 ; CHECK-NEXT: OpUnreachable
1474 OpCapability Kernel
1475 OpCapability Linkage
1476 OpMemoryModel Logical OpenCL
1477 OpName %func "func"
1478 OpDecorate %func LinkageAttributes "func" Export
1479 %bool = OpTypeBool
1480 %false = OpConstantFalse %bool
1481 %true = OpConstantTrue %bool
1482 %void = OpTypeVoid
1483 %funcTy = OpTypeFunction %void
1484 %func = OpFunction %void None %funcTy
1485 %1 = OpLabel
1486 %c = OpUndef %bool
1487 OpSelectionMerge %2 None
1488 OpBranchConditional %c %if %else
1489 %if = OpLabel
1490 OpBranch %2
1491 %else = OpLabel
1492 OpBranch %2
1493 %2 = OpLabel
1494 %phi = OpPhi %bool %false %if %false %else %true %continue
1495 OpLoopMerge %merge %continue None
1496 OpBranch %3
1497 %3 = OpLabel
1498 OpReturn
1499 %continue = OpLabel
1500 OpBranch %2
1501 %merge = OpLabel
1502 OpReturn
1503 OpFunctionEnd
1504 )";
1505 
1506   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1507 }
TEST_F(DeadBranchElimTest,EarlyReconvergence)1508 TEST_F(DeadBranchElimTest, EarlyReconvergence) {
1509   const std::string text = R"(
1510 ; CHECK-NOT: OpBranchConditional
1511 ; CHECK: [[logical:%\w+]] = OpLogicalOr
1512 ; CHECK-NOT: OpPhi
1513 ; CHECK: OpLogicalAnd {{%\w+}} {{%\w+}} [[logical]]
1514 OpCapability Shader
1515 OpMemoryModel Logical GLSL450
1516 OpEntryPoint Fragment %func "func"
1517 OpExecutionMode %func OriginUpperLeft
1518 %void = OpTypeVoid
1519 %bool = OpTypeBool
1520 %false = OpConstantFalse %bool
1521 %true = OpConstantTrue %bool
1522 %func_ty = OpTypeFunction %void
1523 %func = OpFunction %void None %func_ty
1524 %1 = OpLabel
1525 OpSelectionMerge %2 None
1526 OpBranchConditional %false %3 %4
1527 %3 = OpLabel
1528 %12 = OpLogicalNot %bool %true
1529 OpBranch %2
1530 %4 = OpLabel
1531 OpSelectionMerge %14 None
1532 OpBranchConditional %false %5 %6
1533 %5 = OpLabel
1534 %10 = OpLogicalAnd %bool %true %false
1535 OpBranch %7
1536 %6 = OpLabel
1537 %11 = OpLogicalOr %bool %true %false
1538 OpBranch %7
1539 %7 = OpLabel
1540 ; This phi is in a block preceeding the merge %14!
1541 %8 = OpPhi %bool %10 %5 %11 %6
1542 OpBranch %14
1543 %14 = OpLabel
1544 OpBranch %2
1545 %2 = OpLabel
1546 %9 = OpPhi %bool %12 %3 %8 %14
1547 %13 = OpLogicalAnd %bool %true %9
1548 OpReturn
1549 OpFunctionEnd
1550 )";
1551 
1552   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1553 }
1554 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksFloating)1555 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloating) {
1556   const std::string text = R"(
1557 ; CHECK: OpFunction
1558 ; CHECK-NEXT: OpLabel
1559 ; CHECK-NEXT: OpReturn
1560 ; CHECK-NEXT: OpFunctionEnd
1561 OpCapability Kernel
1562 OpCapability Linkage
1563 OpMemoryModel Logical OpenCL
1564 OpName %func "func"
1565 OpDecorate %func LinkageAttributes "func" Export
1566 %void = OpTypeVoid
1567 %1 = OpTypeFunction %void
1568 %func = OpFunction %void None %1
1569 %2 = OpLabel
1570 OpReturn
1571 %3 = OpLabel
1572 OpReturn
1573 OpFunctionEnd
1574 )";
1575 
1576   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1577 }
1578 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksFloatingJoin)1579 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloatingJoin) {
1580   const std::string text = R"(
1581 ; CHECK: OpFunction
1582 ; CHECK-NEXT: OpFunctionParameter
1583 ; CHECK-NEXT: OpLabel
1584 ; CHECK-NEXT: OpReturn
1585 ; CHECK-NEXT: OpFunctionEnd
1586 OpCapability Kernel
1587 OpCapability Linkage
1588 OpMemoryModel Logical OpenCL
1589 OpName %func "func"
1590 OpDecorate %func LinkageAttributes "func" Export
1591 %void = OpTypeVoid
1592 %bool = OpTypeBool
1593 %false = OpConstantFalse %bool
1594 %true = OpConstantTrue %bool
1595 %1 = OpTypeFunction %void %bool
1596 %func = OpFunction %void None %1
1597 %bool_param = OpFunctionParameter %bool
1598 %2 = OpLabel
1599 OpReturn
1600 %3 = OpLabel
1601 OpSelectionMerge %6 None
1602 OpBranchConditional %bool_param %4 %5
1603 %4 = OpLabel
1604 OpBranch %6
1605 %5 = OpLabel
1606 OpBranch %6
1607 %6 = OpLabel
1608 %7 = OpPhi %bool %true %4 %false %6
1609 OpReturn
1610 OpFunctionEnd
1611 )";
1612 
1613   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1614 }
1615 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksDeadPhi)1616 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksDeadPhi) {
1617   const std::string text = R"(
1618 ; CHECK: OpFunction
1619 ; CHECK-NEXT: OpFunctionParameter
1620 ; CHECK-NEXT: OpLabel
1621 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1622 ; CHECK-NEXT: [[label]] = OpLabel
1623 ; CHECK-NEXT: OpLogicalNot %bool %true
1624 ; CHECK-NEXT: OpReturn
1625 ; CHECK-NEXT: OpFunctionEnd
1626 OpCapability Kernel
1627 OpCapability Linkage
1628 OpMemoryModel Logical OpenCL
1629 OpName %func "func"
1630 OpDecorate %func LinkageAttributes "func" Export
1631 %void = OpTypeVoid
1632 %bool = OpTypeBool
1633 %false = OpConstantFalse %bool
1634 %true = OpConstantTrue %bool
1635 %1 = OpTypeFunction %void %bool
1636 %func = OpFunction %void None %1
1637 %bool_param = OpFunctionParameter %bool
1638 %2 = OpLabel
1639 OpBranch %3
1640 %4 = OpLabel
1641 OpBranch %3
1642 %3 = OpLabel
1643 %5 = OpPhi %bool %true %2 %false %4
1644 %6 = OpLogicalNot %bool %5
1645 OpReturn
1646 OpFunctionEnd
1647 )";
1648 
1649   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1650 }
1651 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksPartiallyDeadPhi)1652 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksPartiallyDeadPhi) {
1653   const std::string text = R"(
1654 ; CHECK: OpFunction
1655 ; CHECK-NEXT: [[param:%\w+]] = OpFunctionParameter
1656 ; CHECK-NEXT: OpLabel
1657 ; CHECK-NEXT: OpBranchConditional [[param]] [[merge:%\w+]] [[br:%\w+]]
1658 ; CHECK-NEXT: [[merge]] = OpLabel
1659 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %bool %true %2 %false [[br]]
1660 ; CHECK-NEXT: OpLogicalNot %bool [[phi]]
1661 ; CHECK-NEXT: OpReturn
1662 ; CHECK-NEXT: [[br]] = OpLabel
1663 ; CHECK-NEXT: OpBranch [[merge]]
1664 ; CHECK-NEXT: OpFunctionEnd
1665 OpCapability Kernel
1666 OpCapability Linkage
1667 OpMemoryModel Logical OpenCL
1668 OpName %func "func"
1669 OpDecorate %func LinkageAttributes "func" Export
1670 %void = OpTypeVoid
1671 %bool = OpTypeBool
1672 %false = OpConstantFalse %bool
1673 %true = OpConstantTrue %bool
1674 %1 = OpTypeFunction %void %bool
1675 %func = OpFunction %void None %1
1676 %bool_param = OpFunctionParameter %bool
1677 %2 = OpLabel
1678 OpBranchConditional %bool_param %3 %7
1679 %7 = OpLabel
1680 OpBranch %3
1681 %4 = OpLabel
1682 OpBranch %3
1683 %3 = OpLabel
1684 %5 = OpPhi %bool %true %2 %false %7 %false %4
1685 %6 = OpLogicalNot %bool %5
1686 OpReturn
1687 OpFunctionEnd
1688 )";
1689 
1690   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1691   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1692 }
1693 
TEST_F(DeadBranchElimTest,LiveHeaderDeadPhi)1694 TEST_F(DeadBranchElimTest, LiveHeaderDeadPhi) {
1695   const std::string text = R"(
1696 ; CHECK: OpLabel
1697 ; CHECK-NOT: OpBranchConditional
1698 ; CHECK-NOT: OpPhi
1699 ; CHECK: OpLogicalNot %bool %false
1700 OpCapability Kernel
1701 OpCapability Linkage
1702 OpMemoryModel Logical OpenCL
1703 OpName %func "func"
1704 OpDecorate %func LinkageAttributes "func" Export
1705 %void = OpTypeVoid
1706 %bool = OpTypeBool
1707 %true = OpConstantTrue %bool
1708 %false = OpConstantFalse %bool
1709 %func_ty = OpTypeFunction %void
1710 %func = OpFunction %void None %func_ty
1711 %1 = OpLabel
1712 OpSelectionMerge %3 None
1713 OpBranchConditional %true %2 %3
1714 %2 = OpLabel
1715 OpBranch %3
1716 %3 = OpLabel
1717 %5 = OpPhi %bool %true %3 %false %2
1718 %6 = OpLogicalNot %bool %5
1719 OpReturn
1720 OpFunctionEnd
1721 )";
1722 
1723   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1724 }
1725 
TEST_F(DeadBranchElimTest,ExtraBackedgeBlocksLive)1726 TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksLive) {
1727   const std::string text = R"(
1728 ; CHECK: [[entry:%\w+]] = OpLabel
1729 ; CHECK-NOT: OpSelectionMerge
1730 ; CHECK: OpBranch [[header:%\w+]]
1731 ; CHECK-NEXT: [[header]] = OpLabel
1732 ; CHECK-NEXT: OpPhi %bool %true [[entry]] %false [[backedge:%\w+]]
1733 ; CHECK-NEXT: OpLoopMerge
1734 OpCapability Kernel
1735 OpCapability Linkage
1736 OpMemoryModel Logical OpenCL
1737 OpName %func "func"
1738 OpDecorate %func LinkageAttributes "func" Export
1739 %void = OpTypeVoid
1740 %bool = OpTypeBool
1741 %true = OpConstantTrue %bool
1742 %false = OpConstantFalse %bool
1743 %func_ty = OpTypeFunction %void %bool
1744 %func = OpFunction %void None %func_ty
1745 %param = OpFunctionParameter %bool
1746 %entry = OpLabel
1747 OpSelectionMerge %if_merge None
1748 ; This dead branch is included to ensure the pass does work.
1749 OpBranchConditional %false %if_merge %loop_header
1750 %loop_header = OpLabel
1751 ; Both incoming edges are live, so the phi should be untouched.
1752 %phi = OpPhi %bool %true %entry %false %backedge
1753 OpLoopMerge %loop_merge %continue None
1754 OpBranchConditional %param %loop_merge %continue
1755 %continue = OpLabel
1756 OpBranch %backedge
1757 %backedge = OpLabel
1758 OpBranch %loop_header
1759 %loop_merge = OpLabel
1760 OpBranch %if_merge
1761 %if_merge = OpLabel
1762 OpReturn
1763 OpFunctionEnd
1764 )";
1765 
1766   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1767 }
1768 
TEST_F(DeadBranchElimTest,ExtraBackedgeBlocksUnreachable)1769 TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksUnreachable) {
1770   const std::string text = R"(
1771 ; CHECK: [[entry:%\w+]] = OpLabel
1772 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1773 ; CHECK-NEXT: [[header]] = OpLabel
1774 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1775 ; CHECK-NEXT: OpBranch [[merge]]
1776 ; CHECK-NEXT: [[merge]] = OpLabel
1777 ; CHECK-NEXT: OpReturn
1778 ; CHECK-NEXT: [[continue]] = OpLabel
1779 ; CHECK-NEXT: OpBranch [[header]]
1780 OpCapability Kernel
1781 OpCapability Linkage
1782 OpMemoryModel Logical OpenCL
1783 OpName %func "func"
1784 OpDecorate %func LinkageAttributes "func" Export
1785 %void = OpTypeVoid
1786 %bool = OpTypeBool
1787 %true = OpConstantTrue %bool
1788 %false = OpConstantFalse %bool
1789 %func_ty = OpTypeFunction %void %bool
1790 %func = OpFunction %void None %func_ty
1791 %param = OpFunctionParameter %bool
1792 %entry = OpLabel
1793 OpBranch %loop_header
1794 %loop_header = OpLabel
1795 ; Since the continue is unreachable, %backedge will be removed. The phi will
1796 ; instead require an edge from %continue.
1797 %phi = OpPhi %bool %true %entry %false %backedge
1798 OpLoopMerge %merge %continue None
1799 OpBranch %merge
1800 %continue = OpLabel
1801 OpBranch %backedge
1802 %backedge = OpLabel
1803 OpBranch %loop_header
1804 %merge = OpLabel
1805 OpReturn
1806 OpFunctionEnd
1807 )";
1808 
1809   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1810 }
1811 
TEST_F(DeadBranchElimTest,NoUnnecessaryChanges)1812 TEST_F(DeadBranchElimTest, NoUnnecessaryChanges) {
1813   const std::string text = R"(
1814 OpCapability Shader
1815 OpMemoryModel Logical GLSL450
1816 OpEntryPoint Fragment %func "func"
1817 %void = OpTypeVoid
1818 %bool = OpTypeBool
1819 %true = OpConstantTrue %bool
1820 %undef = OpUndef %bool
1821 %functy = OpTypeFunction %void
1822 %func = OpFunction %void None %functy
1823 %1 = OpLabel
1824 OpBranch %2
1825 %2 = OpLabel
1826 OpLoopMerge %4 %5 None
1827 OpBranch %6
1828 %6 = OpLabel
1829 OpReturn
1830 %5 = OpLabel
1831 OpBranch %2
1832 %4 = OpLabel
1833 OpUnreachable
1834 OpFunctionEnd
1835 )";
1836 
1837   auto result = SinglePassRunToBinary<DeadBranchElimPass>(text, true);
1838   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
1839 }
1840 
TEST_F(DeadBranchElimTest,ExtraBackedgePartiallyDead)1841 TEST_F(DeadBranchElimTest, ExtraBackedgePartiallyDead) {
1842   const std::string text = R"(
1843 ; CHECK: OpLabel
1844 ; CHECK: [[header:%\w+]] = OpLabel
1845 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1846 ; CHECK: [[merge]] = OpLabel
1847 ; CHECK: [[continue]] = OpLabel
1848 ; CHECK: OpBranch [[extra:%\w+]]
1849 ; CHECK: [[extra]] = OpLabel
1850 ; CHECK-NOT: OpSelectionMerge
1851 ; CHECK-NEXT: OpBranch [[else:%\w+]]
1852 ; CHECK-NEXT: [[else]] = OpLabel
1853 ; CHECK-NEXT: OpLogicalOr
1854 ; CHECK-NEXT: OpBranch [[backedge:%\w+]]
1855 ; CHECK-NEXT: [[backedge:%\w+]] = OpLabel
1856 ; CHECK-NEXT: OpBranch [[header]]
1857 OpCapability Kernel
1858 OpCapability Linkage
1859 OpMemoryModel Logical OpenCL
1860 OpName %func "func"
1861 OpDecorate %func LinkageAttributes "func" Export
1862 %void = OpTypeVoid
1863 %bool = OpTypeBool
1864 %true = OpConstantTrue %bool
1865 %false = OpConstantFalse %bool
1866 %func_ty = OpTypeFunction %void %bool
1867 %func = OpFunction %void None %func_ty
1868 %param = OpFunctionParameter %bool
1869 %entry = OpLabel
1870 OpBranch %loop_header
1871 %loop_header = OpLabel
1872 OpLoopMerge %loop_merge %continue None
1873 OpBranchConditional %param %loop_merge %continue
1874 %continue = OpLabel
1875 OpBranch %extra
1876 %extra = OpLabel
1877 OpSelectionMerge %backedge None
1878 OpBranchConditional %false %then %else
1879 %then = OpLabel
1880 %and = OpLogicalAnd %bool %true %false
1881 OpBranch %backedge
1882 %else = OpLabel
1883 %or = OpLogicalOr %bool %true %false
1884 OpBranch %backedge
1885 %backedge = OpLabel
1886 OpBranch %loop_header
1887 %loop_merge = OpLabel
1888 OpReturn
1889 OpFunctionEnd
1890 )";
1891 
1892   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1893 }
1894 
TEST_F(DeadBranchElimTest,UnreachableContinuePhiInMerge)1895 TEST_F(DeadBranchElimTest, UnreachableContinuePhiInMerge) {
1896   const std::string text = R"(
1897 ; CHECK: [[entry:%\w+]] = OpLabel
1898 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1899 ; CHECK-NEXT: [[header]] = OpLabel
1900 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1901 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1902 ; CHECK-NEXT: [[label]] = OpLabel
1903 ; CHECK-NEXT: [[fadd:%\w+]] = OpFAdd
1904 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1905 ; CHECK-NEXT: [[label]] = OpLabel
1906 ; CHECK-NEXT: OpBranch [[merge]]
1907 ; CHECK-NEXT: [[continue]] = OpLabel
1908 ; CHECK-NEXT: OpBranch [[header]]
1909 ; CHECK-NEXT: [[merge]] = OpLabel
1910 ; CHECK-NEXT: OpStore {{%\w+}} [[fadd]]
1911                OpCapability Shader
1912           %1 = OpExtInstImport "GLSL.std.450"
1913                OpMemoryModel Logical GLSL450
1914                OpEntryPoint Fragment %main "main" %o
1915                OpExecutionMode %main OriginUpperLeft
1916                OpSource GLSL 430
1917                OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
1918                OpSourceExtension "GL_GOOGLE_include_directive"
1919                OpName %main "main"
1920                OpName %o "o"
1921                OpName %S "S"
1922                OpMemberName %S 0 "a"
1923                OpName %U_t "U_t"
1924                OpMemberName %U_t 0 "g_F"
1925                OpMemberName %U_t 1 "g_F2"
1926                OpDecorate %o Location 0
1927                OpMemberDecorate %S 0 Offset 0
1928                OpMemberDecorate %U_t 0 Volatile
1929                OpMemberDecorate %U_t 0 Offset 0
1930                OpMemberDecorate %U_t 1 Offset 4
1931                OpDecorate %U_t BufferBlock
1932        %void = OpTypeVoid
1933           %7 = OpTypeFunction %void
1934       %float = OpTypeFloat 32
1935 %_ptr_Function_float = OpTypePointer Function %float
1936     %float_0 = OpConstant %float 0
1937         %int = OpTypeInt 32 1
1938 %_ptr_Function_int = OpTypePointer Function %int
1939       %int_0 = OpConstant %int 0
1940      %int_10 = OpConstant %int 10
1941        %bool = OpTypeBool
1942        %true = OpConstantTrue %bool
1943     %float_1 = OpConstant %float 1
1944     %float_5 = OpConstant %float 5
1945       %int_1 = OpConstant %int 1
1946 %_ptr_Output_float = OpTypePointer Output %float
1947           %o = OpVariable %_ptr_Output_float Output
1948           %S = OpTypeStruct %float
1949         %U_t = OpTypeStruct %S %S
1950 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
1951        %main = OpFunction %void None %7
1952          %22 = OpLabel
1953                OpBranch %23
1954          %23 = OpLabel
1955          %24 = OpPhi %float %float_0 %22 %25 %26
1956          %27 = OpPhi %int %int_0 %22 %28 %26
1957                OpLoopMerge %29 %26 None
1958                OpBranch %40
1959          %40 = OpLabel
1960          %25 = OpFAdd %float %24 %float_1
1961                OpSelectionMerge %30 None
1962                OpBranchConditional %true %31 %30
1963          %31 = OpLabel
1964                OpBranch %29
1965          %30 = OpLabel
1966                OpBranch %26
1967          %26 = OpLabel
1968          %28 = OpIAdd %int %27 %int_1
1969          %32 = OpSLessThan %bool %27 %int_10
1970 ; continue block branches to the header or another none dead block.
1971                OpBranchConditional %32 %23 %29
1972          %29 = OpLabel
1973          %33 = OpPhi %float %24 %26 %25 %31
1974                OpStore %o %33
1975                OpReturn
1976                OpFunctionEnd
1977 )";
1978 
1979   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1980 }
1981 
TEST_F(DeadBranchElimTest,NonStructuredIf)1982 TEST_F(DeadBranchElimTest, NonStructuredIf) {
1983   const std::string text = R"(
1984 ; CHECK-NOT: OpBranchConditional
1985 OpCapability Kernel
1986 OpCapability Linkage
1987 OpMemoryModel Logical OpenCL
1988 OpDecorate %func LinkageAttributes "func" Export
1989 %void = OpTypeVoid
1990 %bool = OpTypeBool
1991 %true = OpConstantTrue %bool
1992 %functy = OpTypeFunction %void
1993 %func = OpFunction %void None %functy
1994 %entry = OpLabel
1995 OpBranchConditional %true %then %else
1996 %then = OpLabel
1997 OpBranch %final
1998 %else = OpLabel
1999 OpBranch %final
2000 %final = OpLabel
2001 OpReturn
2002 OpFunctionEnd
2003 )";
2004 
2005   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2006 }
2007 
TEST_F(DeadBranchElimTest,ReorderBlocks)2008 TEST_F(DeadBranchElimTest, ReorderBlocks) {
2009   const std::string text = R"(
2010 ; CHECK: OpLabel
2011 ; CHECK: OpBranch [[label:%\w+]]
2012 ; CHECK: [[label:%\w+]] = OpLabel
2013 ; CHECK-NEXT: OpLogicalNot
2014 ; CHECK-NEXT: OpBranch [[label:%\w+]]
2015 ; CHECK: [[label]] = OpLabel
2016 ; CHECK-NEXT: OpReturn
2017 OpCapability Shader
2018 OpMemoryModel Logical GLSL450
2019 OpEntryPoint Fragment %func "func"
2020 OpExecutionMode %func OriginUpperLeft
2021 %void = OpTypeVoid
2022 %bool = OpTypeBool
2023 %true = OpConstantTrue %bool
2024 %func_ty = OpTypeFunction %void
2025 %func = OpFunction %void None %func_ty
2026 %1 = OpLabel
2027 OpSelectionMerge %3 None
2028 OpBranchConditional %true %2 %3
2029 %3 = OpLabel
2030 OpReturn
2031 %2 = OpLabel
2032 %not = OpLogicalNot %bool %true
2033 OpBranch %3
2034 OpFunctionEnd
2035 )";
2036 
2037   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2038 }
2039 
TEST_F(DeadBranchElimTest,ReorderBlocksMultiple)2040 TEST_F(DeadBranchElimTest, ReorderBlocksMultiple) {
2041   // Checks are not important. The validation post optimization is the
2042   // important part.
2043   const std::string text = R"(
2044 ; CHECK: OpLabel
2045 OpCapability Shader
2046 OpMemoryModel Logical GLSL450
2047 OpEntryPoint Fragment %func "func"
2048 OpExecutionMode %func OriginUpperLeft
2049 %void = OpTypeVoid
2050 %bool = OpTypeBool
2051 %true = OpConstantTrue %bool
2052 %func_ty = OpTypeFunction %void
2053 %func = OpFunction %void None %func_ty
2054 %1 = OpLabel
2055 OpSelectionMerge %3 None
2056 OpBranchConditional %true %2 %3
2057 %3 = OpLabel
2058 OpReturn
2059 %2 = OpLabel
2060 OpBranch %4
2061 %4 = OpLabel
2062 OpBranch %3
2063 OpFunctionEnd
2064 )";
2065 
2066   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2067 }
2068 
TEST_F(DeadBranchElimTest,ReorderBlocksMultiple2)2069 TEST_F(DeadBranchElimTest, ReorderBlocksMultiple2) {
2070   // Checks are not important. The validation post optimization is the
2071   // important part.
2072   const std::string text = R"(
2073 ; CHECK: OpLabel
2074 OpCapability Shader
2075 OpMemoryModel Logical GLSL450
2076 OpEntryPoint Fragment %func "func"
2077 OpExecutionMode %func OriginUpperLeft
2078 %void = OpTypeVoid
2079 %bool = OpTypeBool
2080 %true = OpConstantTrue %bool
2081 %func_ty = OpTypeFunction %void
2082 %func = OpFunction %void None %func_ty
2083 %1 = OpLabel
2084 OpSelectionMerge %3 None
2085 OpBranchConditional %true %2 %3
2086 %3 = OpLabel
2087 OpBranch %5
2088 %5 = OpLabel
2089 OpReturn
2090 %2 = OpLabel
2091 OpBranch %4
2092 %4 = OpLabel
2093 OpBranch %3
2094 OpFunctionEnd
2095 )";
2096 
2097   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2098 }
2099 
TEST_F(DeadBranchElimTest,SelectionMergeWithEarlyExit1)2100 TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit1) {
2101   // Checks  that if a selection merge construct contains a conditional branch
2102   // to the merge node, then the OpSelectionMerge instruction is positioned
2103   // correctly.
2104   const std::string predefs = R"(
2105 OpCapability Shader
2106 %1 = OpExtInstImport "GLSL.std.450"
2107 OpMemoryModel Logical GLSL450
2108 OpEntryPoint Fragment %main "main"
2109 OpExecutionMode %main OriginUpperLeft
2110 OpSource GLSL 140
2111 %void = OpTypeVoid
2112 %func_type = OpTypeFunction %void
2113 %bool = OpTypeBool
2114 %true = OpConstantTrue %bool
2115 %undef_bool = OpUndef %bool
2116 )";
2117 
2118   const std::string body =
2119       R"(
2120 ; CHECK: OpFunction
2121 ; CHECK-NEXT: OpLabel
2122 ; CHECK-NEXT: OpBranch [[taken_branch:%\w+]]
2123 ; CHECK-NEXT: [[taken_branch]] = OpLabel
2124 ; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
2125 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[merge]] {{%\w+}}
2126 %main = OpFunction %void None %func_type
2127 %entry_bb = OpLabel
2128 OpSelectionMerge %outer_merge None
2129 OpBranchConditional %true %bb1 %bb3
2130 %bb1 = OpLabel
2131 OpBranchConditional %undef_bool %outer_merge %bb2
2132 %bb2 = OpLabel
2133 OpBranch %outer_merge
2134 %bb3 = OpLabel
2135 OpBranch %outer_merge
2136 %outer_merge = OpLabel
2137 OpReturn
2138 OpFunctionEnd
2139 )";
2140 
2141   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2142 }
2143 
TEST_F(DeadBranchElimTest,SelectionMergeWithEarlyExit2)2144 TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit2) {
2145   // Checks  that if a selection merge construct contains a conditional branch
2146   // to the merge node, then the OpSelectionMerge instruction is positioned
2147   // correctly.
2148   const std::string predefs = R"(
2149 OpCapability Shader
2150 %1 = OpExtInstImport "GLSL.std.450"
2151 OpMemoryModel Logical GLSL450
2152 OpEntryPoint Fragment %main "main"
2153 OpExecutionMode %main OriginUpperLeft
2154 OpSource GLSL 140
2155 %void = OpTypeVoid
2156 %func_type = OpTypeFunction %void
2157 %bool = OpTypeBool
2158 %true = OpConstantTrue %bool
2159 %undef_bool = OpUndef %bool
2160 )";
2161 
2162   const std::string body =
2163       R"(
2164 ; CHECK: OpFunction
2165 ; CHECK-NEXT: OpLabel
2166 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2167 ; CHECK-NEXT: [[bb1]] = OpLabel
2168 ; CHECK-NEXT: OpSelectionMerge [[inner_merge:%\w+]]
2169 ; CHECK: [[inner_merge]] = OpLabel
2170 ; CHECK-NEXT: OpSelectionMerge [[outer_merge:%\w+]]
2171 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[outer_merge]:%\w+]] {{%\w+}}
2172 ; CHECK: [[outer_merge]] = OpLabel
2173 ; CHECK-NEXT: OpReturn
2174 %main = OpFunction %void None %func_type
2175 %entry_bb = OpLabel
2176 OpSelectionMerge %outer_merge None
2177 OpBranchConditional %true %bb1 %bb5
2178 %bb1 = OpLabel
2179 OpSelectionMerge %inner_merge None
2180 OpBranchConditional %undef_bool %bb2 %bb3
2181 %bb2 = OpLabel
2182 OpBranch %inner_merge
2183 %bb3 = OpLabel
2184 OpBranch %inner_merge
2185 %inner_merge = OpLabel
2186 OpBranchConditional %undef_bool %outer_merge %bb4
2187 %bb4 = OpLabel
2188 OpBranch %outer_merge
2189 %bb5 = OpLabel
2190 OpBranch %outer_merge
2191 %outer_merge = OpLabel
2192 OpReturn
2193 OpFunctionEnd
2194 )";
2195 
2196   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2197 }
2198 
TEST_F(DeadBranchElimTest,SelectionMergeWithConditionalExit)2199 TEST_F(DeadBranchElimTest, SelectionMergeWithConditionalExit) {
2200   // Checks that if a selection merge construct contains a conditional branch
2201   // to the merge node, then we keep the OpSelectionMerge on that branch.
2202   const std::string predefs = R"(
2203 OpCapability Shader
2204 %1 = OpExtInstImport "GLSL.std.450"
2205 OpMemoryModel Logical GLSL450
2206 OpEntryPoint Fragment %main "main"
2207 OpExecutionMode %main OriginUpperLeft
2208 OpSource GLSL 140
2209 %void = OpTypeVoid
2210 %func_type = OpTypeFunction %void
2211 %bool = OpTypeBool
2212 %true = OpConstantTrue %bool
2213 %uint = OpTypeInt 32 0
2214 %undef_int = OpUndef %uint
2215 )";
2216 
2217   const std::string body =
2218       R"(
2219 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2220 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2221 ; CHECK: [[bb1]] = OpLabel
2222 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2223 ; CHECK: [[bb2]] = OpLabel
2224 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2225 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 1 [[bb3:%\w+]]
2226 ; CHECK: [[bb3]] = OpLabel
2227 ; CHECK-NEXT: OpBranch [[sel_merge]]
2228 ; CHECK: [[sel_merge]] = OpLabel
2229 ; CHECK-NEXT: OpBranch [[loop_merge]]
2230 ; CHECK: [[loop_merge]] = OpLabel
2231 ; CHECK-NEXT: OpReturn
2232 %main = OpFunction %void None %func_type
2233 %entry_bb = OpLabel
2234 OpBranch %loop_header
2235 %loop_header = OpLabel
2236 OpLoopMerge %loop_merge %cont None
2237 OpBranch %bb1
2238 %bb1 = OpLabel
2239 OpSelectionMerge %sel_merge None
2240 OpBranchConditional %true %bb2 %bb4
2241 %bb2 = OpLabel
2242 OpSwitch %undef_int %sel_merge 1 %bb3
2243 %bb3 = OpLabel
2244 OpBranch %sel_merge
2245 %bb4 = OpLabel
2246 OpBranch %sel_merge
2247 %sel_merge = OpLabel
2248 OpBranch %loop_merge
2249 %cont = OpLabel
2250 OpBranch %loop_header
2251 %loop_merge = OpLabel
2252 OpReturn
2253 OpFunctionEnd
2254 )";
2255 
2256   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2257 }
2258 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop)2259 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop) {
2260   // Checks  that if a selection merge construct contains a conditional branch
2261   // to a loop surrounding the selection merge, then we do not keep the
2262   // OpSelectionMerge instruction.
2263   const std::string predefs = R"(
2264 OpCapability Shader
2265 %1 = OpExtInstImport "GLSL.std.450"
2266 OpMemoryModel Logical GLSL450
2267 OpEntryPoint Fragment %main "main"
2268 OpExecutionMode %main OriginUpperLeft
2269 OpSource GLSL 140
2270 %void = OpTypeVoid
2271 %func_type = OpTypeFunction %void
2272 %bool = OpTypeBool
2273 %true = OpConstantTrue %bool
2274 %undef_bool = OpUndef %bool
2275 )";
2276 
2277   const std::string body =
2278       R"(
2279 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2280 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2281 ; CHECK: [[bb1]] = OpLabel
2282 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2283 ; CHECK: [[bb2]] = OpLabel
2284 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_merge]]
2285 ; CHECK: [[bb3]] = OpLabel
2286 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2287 ; CHECK: [[sel_merge]] = OpLabel
2288 ; CHECK-NEXT: OpBranch [[loop_merge]]
2289 ; CHECK: [[loop_merge]] = OpLabel
2290 ; CHECK-NEXT: OpReturn
2291 %main = OpFunction %void None %func_type
2292 %entry_bb = OpLabel
2293 OpBranch %loop_header
2294 %loop_header = OpLabel
2295 OpLoopMerge %loop_merge %cont None
2296 OpBranch %bb1
2297 %bb1 = OpLabel
2298 OpSelectionMerge %sel_merge None
2299 OpBranchConditional %true %bb2 %bb4
2300 %bb2 = OpLabel
2301 OpBranchConditional %undef_bool %bb3 %loop_merge
2302 %bb3 = OpLabel
2303 OpBranch %sel_merge
2304 %bb4 = OpLabel
2305 OpBranch %sel_merge
2306 %sel_merge = OpLabel
2307 OpBranch %loop_merge
2308 %cont = OpLabel
2309 OpBranch %loop_header
2310 %loop_merge = OpLabel
2311 OpReturn
2312 OpFunctionEnd
2313 )";
2314 
2315   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2316 }
2317 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue)2318 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue) {
2319   // Checks  that if a selection merge construct contains a conditional branch
2320   // to continue of a loop surrounding the selection merge, then we do not keep
2321   // the OpSelectionMerge instruction.
2322   const std::string predefs = R"(
2323 OpCapability Shader
2324 %1 = OpExtInstImport "GLSL.std.450"
2325 OpMemoryModel Logical GLSL450
2326 OpEntryPoint Fragment %main "main"
2327 OpExecutionMode %main OriginUpperLeft
2328 OpSource GLSL 140
2329 %void = OpTypeVoid
2330 %func_type = OpTypeFunction %void
2331 %bool = OpTypeBool
2332 %true = OpConstantTrue %bool
2333 %undef_bool = OpUndef %bool
2334 )";
2335 
2336   const std::string body =
2337       R"(;
2338 ; CHECK: OpLabel
2339 ; CHECK: [[loop_header:%\w+]] = OpLabel
2340 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2341 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2342 ; CHECK: [[bb1]] = OpLabel
2343 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2344 ; CHECK: [[bb2]] = OpLabel
2345 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]]
2346 ; CHECK: [[bb3]] = OpLabel
2347 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2348 ; CHECK: [[sel_merge]] = OpLabel
2349 ; CHECK-NEXT: OpBranch [[loop_merge]]
2350 ; CHECK: [[loop_cont]] = OpLabel
2351 ; CHECK-NEXT: OpBranch [[loop_header]]
2352 ; CHECK: [[loop_merge]] = OpLabel
2353 ; CHECK-NEXT: OpReturn
2354 %main = OpFunction %void None %func_type
2355 %entry_bb = OpLabel
2356 OpBranch %loop_header
2357 %loop_header = OpLabel
2358 OpLoopMerge %loop_merge %cont None
2359 OpBranch %bb1
2360 %bb1 = OpLabel
2361 OpSelectionMerge %sel_merge None
2362 OpBranchConditional %true %bb2 %bb4
2363 %bb2 = OpLabel
2364 OpBranchConditional %undef_bool %bb3 %cont
2365 %bb3 = OpLabel
2366 OpBranch %sel_merge
2367 %bb4 = OpLabel
2368 OpBranch %sel_merge
2369 %sel_merge = OpLabel
2370 OpBranch %loop_merge
2371 %cont = OpLabel
2372 OpBranch %loop_header
2373 %loop_merge = OpLabel
2374 OpReturn
2375 OpFunctionEnd
2376 )";
2377 
2378   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2379 }
2380 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop2)2381 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop2) {
2382   // Same as |SelectionMergeWithExitToLoop|, except the switch goes to the loop
2383   // merge or the selection merge.  In this case, we do not need an
2384   // OpSelectionMerge either.
2385   const std::string predefs = R"(
2386 OpCapability Shader
2387 %1 = OpExtInstImport "GLSL.std.450"
2388 OpMemoryModel Logical GLSL450
2389 OpEntryPoint Fragment %main "main"
2390 OpExecutionMode %main OriginUpperLeft
2391 OpSource GLSL 140
2392 %void = OpTypeVoid
2393 %func_type = OpTypeFunction %void
2394 %bool = OpTypeBool
2395 %true = OpConstantTrue %bool
2396 %undef_bool = OpUndef %bool
2397 )";
2398 
2399   const std::string body =
2400       R"(
2401 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2402 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2403 ; CHECK: [[bb1]] = OpLabel
2404 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2405 ; CHECK: [[bb2]] = OpLabel
2406 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_merge]]
2407 ; CHECK: [[sel_merge]] = OpLabel
2408 ; CHECK-NEXT: OpBranch [[loop_merge]]
2409 ; CHECK: [[loop_merge]] = OpLabel
2410 ; CHECK-NEXT: OpReturn
2411 %main = OpFunction %void None %func_type
2412 %entry_bb = OpLabel
2413 OpBranch %loop_header
2414 %loop_header = OpLabel
2415 OpLoopMerge %loop_merge %cont None
2416 OpBranch %bb1
2417 %bb1 = OpLabel
2418 OpSelectionMerge %sel_merge None
2419 OpBranchConditional %true %bb2 %bb4
2420 %bb2 = OpLabel
2421 OpBranchConditional %undef_bool %sel_merge %loop_merge
2422 %bb4 = OpLabel
2423 OpBranch %sel_merge
2424 %sel_merge = OpLabel
2425 OpBranch %loop_merge
2426 %cont = OpLabel
2427 OpBranch %loop_header
2428 %loop_merge = OpLabel
2429 OpReturn
2430 OpFunctionEnd
2431 )";
2432 
2433   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2434 }
2435 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue2)2436 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue2) {
2437   // Same as |SelectionMergeWithExitToLoopContinue|, except the branch goes to
2438   // the loop continue or the selection merge.  In this case, we do not need an
2439   // OpSelectionMerge either.
2440   const std::string predefs = R"(
2441 OpCapability Shader
2442 %1 = OpExtInstImport "GLSL.std.450"
2443 OpMemoryModel Logical GLSL450
2444 OpEntryPoint Fragment %main "main"
2445 OpExecutionMode %main OriginUpperLeft
2446 OpSource GLSL 140
2447 %void = OpTypeVoid
2448 %func_type = OpTypeFunction %void
2449 %bool = OpTypeBool
2450 %true = OpConstantTrue %bool
2451 %undef_bool = OpUndef %bool
2452 )";
2453 
2454   const std::string body =
2455       R"(
2456 ; CHECK: OpLabel
2457 ; CHECK: [[loop_header:%\w+]] = OpLabel
2458 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2459 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2460 ; CHECK: [[bb1]] = OpLabel
2461 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2462 ; CHECK: [[bb2]] = OpLabel
2463 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_cont]]
2464 ; CHECK: [[sel_merge]] = OpLabel
2465 ; CHECK-NEXT: OpBranch [[loop_merge]]
2466 ; CHECK: [[loop_cont]] = OpLabel
2467 ; CHECK: OpBranch [[loop_header]]
2468 ; CHECK: [[loop_merge]] = OpLabel
2469 ; CHECK-NEXT: OpReturn
2470 %main = OpFunction %void None %func_type
2471 %entry_bb = OpLabel
2472 OpBranch %loop_header
2473 %loop_header = OpLabel
2474 OpLoopMerge %loop_merge %cont None
2475 OpBranch %bb1
2476 %bb1 = OpLabel
2477 OpSelectionMerge %sel_merge None
2478 OpBranchConditional %true %bb2 %bb4
2479 %bb2 = OpLabel
2480 OpBranchConditional %undef_bool %sel_merge %cont
2481 %bb4 = OpLabel
2482 OpBranch %sel_merge
2483 %sel_merge = OpLabel
2484 OpBranch %loop_merge
2485 %cont = OpLabel
2486 OpBranch %loop_header
2487 %loop_merge = OpLabel
2488 OpReturn
2489 OpFunctionEnd
2490 )";
2491 
2492   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2493 }
2494 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop3)2495 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop3) {
2496   // Checks that if a selection merge construct contains a conditional branch
2497   // to the merge of a surrounding loop, the selection merge, and another block
2498   // inside the selection merge, then we must keep the OpSelectionMerge
2499   // instruction on that branch.
2500   const std::string predefs = R"(
2501 OpCapability Shader
2502 %1 = OpExtInstImport "GLSL.std.450"
2503 OpMemoryModel Logical GLSL450
2504 OpEntryPoint Fragment %main "main"
2505 OpExecutionMode %main OriginUpperLeft
2506 OpSource GLSL 140
2507 %void = OpTypeVoid
2508 %func_type = OpTypeFunction %void
2509 %bool = OpTypeBool
2510 %true = OpConstantTrue %bool
2511 %uint = OpTypeInt 32 0
2512 %undef_int = OpUndef %uint
2513 )";
2514 
2515   const std::string body =
2516       R"(
2517 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2518 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2519 ; CHECK: [[bb1]] = OpLabel
2520 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2521 ; CHECK: [[bb2]] = OpLabel
2522 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2523 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_merge]] 1 [[bb3:%\w+]]
2524 ; CHECK: [[bb3]] = OpLabel
2525 ; CHECK-NEXT: OpBranch [[sel_merge]]
2526 ; CHECK: [[sel_merge]] = OpLabel
2527 ; CHECK-NEXT: OpBranch [[loop_merge]]
2528 ; CHECK: [[loop_merge]] = OpLabel
2529 ; CHECK-NEXT: OpReturn
2530 %main = OpFunction %void None %func_type
2531 %entry_bb = OpLabel
2532 OpBranch %loop_header
2533 %loop_header = OpLabel
2534 OpLoopMerge %loop_merge %cont None
2535 OpBranch %bb1
2536 %bb1 = OpLabel
2537 OpSelectionMerge %sel_merge None
2538 OpBranchConditional %true %bb2 %bb4
2539 %bb2 = OpLabel
2540 OpSwitch %undef_int %sel_merge 0 %loop_merge 1 %bb3
2541 %bb3 = OpLabel
2542 OpBranch %sel_merge
2543 %bb4 = OpLabel
2544 OpBranch %sel_merge
2545 %sel_merge = OpLabel
2546 OpBranch %loop_merge
2547 %cont = OpLabel
2548 OpBranch %loop_header
2549 %loop_merge = OpLabel
2550 OpReturn
2551 OpFunctionEnd
2552 )";
2553 
2554   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2555 }
2556 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue3)2557 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue3) {
2558   // Checks that if a selection merge construct contains a conditional branch
2559   // to the merge of a surrounding loop, the selection merge, and another block
2560   // inside the selection merge, then we must keep the OpSelectionMerge
2561   // instruction on that branch.
2562   const std::string predefs = R"(
2563 OpCapability Shader
2564 %1 = OpExtInstImport "GLSL.std.450"
2565 OpMemoryModel Logical GLSL450
2566 OpEntryPoint Fragment %main "main"
2567 OpExecutionMode %main OriginUpperLeft
2568 OpSource GLSL 140
2569 %void = OpTypeVoid
2570 %func_type = OpTypeFunction %void
2571 %bool = OpTypeBool
2572 %true = OpConstantTrue %bool
2573 %uint = OpTypeInt 32 0
2574 %undef_int = OpUndef %uint
2575 )";
2576 
2577   const std::string body =
2578       R"(
2579 ; CHECK: OpLabel
2580 ; CHECK: [[loop_header:%\w+]] = OpLabel
2581 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_continue:%\w+]]
2582 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2583 ; CHECK: [[bb1]] = OpLabel
2584 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2585 ; CHECK: [[bb2]] = OpLabel
2586 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2587 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_continue]] 1 [[bb3:%\w+]]
2588 ; CHECK: [[bb3]] = OpLabel
2589 ; CHECK-NEXT: OpBranch [[sel_merge]]
2590 ; CHECK: [[sel_merge]] = OpLabel
2591 ; CHECK-NEXT: OpBranch [[loop_merge]]
2592 ; CHECK: [[loop_continue]] = OpLabel
2593 ; CHECK-NEXT: OpBranch [[loop_header]]
2594 ; CHECK: [[loop_merge]] = OpLabel
2595 ; CHECK-NEXT: OpReturn
2596 %main = OpFunction %void None %func_type
2597 %entry_bb = OpLabel
2598 OpBranch %loop_header
2599 %loop_header = OpLabel
2600 OpLoopMerge %loop_merge %cont None
2601 OpBranch %bb1
2602 %bb1 = OpLabel
2603 OpSelectionMerge %sel_merge None
2604 OpBranchConditional %true %bb2 %bb4
2605 %bb2 = OpLabel
2606 OpSwitch %undef_int %sel_merge 0 %cont 1 %bb3
2607 %bb3 = OpLabel
2608 OpBranch %sel_merge
2609 %bb4 = OpLabel
2610 OpBranch %sel_merge
2611 %sel_merge = OpLabel
2612 OpBranch %loop_merge
2613 %cont = OpLabel
2614 OpBranch %loop_header
2615 %loop_merge = OpLabel
2616 OpReturn
2617 OpFunctionEnd
2618 )";
2619 
2620   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2621 }
2622 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop4)2623 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop4) {
2624   // Same as |SelectionMergeWithExitToLoop|, except the branch in the selection
2625   // construct is an |OpSwitch| instead of an |OpConditionalBranch|.  The
2626   // OpSelectionMerge instruction is not needed in this case either.
2627   const std::string predefs = R"(
2628 OpCapability Shader
2629 %1 = OpExtInstImport "GLSL.std.450"
2630 OpMemoryModel Logical GLSL450
2631 OpEntryPoint Fragment %main "main"
2632 OpExecutionMode %main OriginUpperLeft
2633 OpSource GLSL 140
2634 %void = OpTypeVoid
2635 %func_type = OpTypeFunction %void
2636 %bool = OpTypeBool
2637 %true = OpConstantTrue %bool
2638 %uint = OpTypeInt 32 0
2639 %undef_int = OpUndef %uint
2640 )";
2641 
2642   const std::string body =
2643       R"(
2644 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2645 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2646 ; CHECK: [[bb1]] = OpLabel
2647 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2648 ; CHECK: [[bb2]] = OpLabel
2649 ; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_merge]] 1 [[bb3:%\w+]]
2650 ; CHECK: [[bb3]] = OpLabel
2651 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2652 ; CHECK: [[sel_merge]] = OpLabel
2653 ; CHECK-NEXT: OpBranch [[loop_merge]]
2654 ; CHECK: [[loop_merge]] = OpLabel
2655 ; CHECK-NEXT: OpReturn
2656 %main = OpFunction %void None %func_type
2657 %entry_bb = OpLabel
2658 OpBranch %loop_header
2659 %loop_header = OpLabel
2660 OpLoopMerge %loop_merge %cont None
2661 OpBranch %bb1
2662 %bb1 = OpLabel
2663 OpSelectionMerge %sel_merge None
2664 OpBranchConditional %true %bb2 %bb4
2665 %bb2 = OpLabel
2666 OpSwitch %undef_int %bb3 0 %loop_merge 1 %bb3
2667 %bb3 = OpLabel
2668 OpBranch %sel_merge
2669 %bb4 = OpLabel
2670 OpBranch %sel_merge
2671 %sel_merge = OpLabel
2672 OpBranch %loop_merge
2673 %cont = OpLabel
2674 OpBranch %loop_header
2675 %loop_merge = OpLabel
2676 OpReturn
2677 OpFunctionEnd
2678 )";
2679 
2680   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2681 }
2682 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue4)2683 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue4) {
2684   // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the
2685   // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|.
2686   // The OpSelectionMerge instruction is not needed in this case either.
2687   const std::string predefs = R"(
2688 OpCapability Shader
2689 %1 = OpExtInstImport "GLSL.std.450"
2690 OpMemoryModel Logical GLSL450
2691 OpEntryPoint Fragment %main "main"
2692 OpExecutionMode %main OriginUpperLeft
2693 OpSource GLSL 140
2694 %void = OpTypeVoid
2695 %func_type = OpTypeFunction %void
2696 %bool = OpTypeBool
2697 %true = OpConstantTrue %bool
2698 %uint = OpTypeInt 32 0
2699 %undef_int = OpUndef %uint
2700 )";
2701 
2702   const std::string body =
2703       R"(
2704 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2705 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2706 ; CHECK: [[bb1]] = OpLabel
2707 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2708 ; CHECK: [[bb2]] = OpLabel
2709 ; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_cont]] 1 [[bb3:%\w+]]
2710 ; CHECK: [[bb3]] = OpLabel
2711 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2712 ; CHECK: [[sel_merge]] = OpLabel
2713 ; CHECK-NEXT: OpBranch [[loop_merge]]
2714 ; CHECK: [[loop_merge]] = OpLabel
2715 ; CHECK-NEXT: OpReturn
2716 %main = OpFunction %void None %func_type
2717 %entry_bb = OpLabel
2718 OpBranch %loop_header
2719 %loop_header = OpLabel
2720 OpLoopMerge %loop_merge %cont None
2721 OpBranch %bb1
2722 %bb1 = OpLabel
2723 OpSelectionMerge %sel_merge None
2724 OpBranchConditional %true %bb2 %bb4
2725 %bb2 = OpLabel
2726 OpSwitch %undef_int %bb3 0 %cont 1 %bb3
2727 %bb3 = OpLabel
2728 OpBranch %sel_merge
2729 %bb4 = OpLabel
2730 OpBranch %sel_merge
2731 %sel_merge = OpLabel
2732 OpBranch %loop_merge
2733 %cont = OpLabel
2734 OpBranch %loop_header
2735 %loop_merge = OpLabel
2736 OpReturn
2737 OpFunctionEnd
2738 )";
2739 
2740   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2741 }
2742 
TEST_F(DeadBranchElimTest,SelectionMergeSameAsLoopContinue)2743 TEST_F(DeadBranchElimTest, SelectionMergeSameAsLoopContinue) {
2744   // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the
2745   // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|.
2746   // The OpSelectionMerge instruction is not needed in this case either.
2747   const std::string predefs = R"(
2748 OpCapability Shader
2749 %1 = OpExtInstImport "GLSL.std.450"
2750 OpMemoryModel Logical GLSL450
2751 OpEntryPoint Fragment %main "main"
2752 OpExecutionMode %main OriginUpperLeft
2753 OpSource GLSL 140
2754 %void = OpTypeVoid
2755 %func_type = OpTypeFunction %void
2756 %bool = OpTypeBool
2757 %true = OpConstantTrue %bool
2758 %uint = OpTypeInt 32 0
2759 %undef_bool = OpUndef %bool
2760 )";
2761 
2762   const std::string body =
2763       R"(
2764 ; CHECK: OpLabel
2765 ; CHECK: [[loop_header:%\w+]] = OpLabel
2766 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2767 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2768 ; CHECK: [[bb1]] = OpLabel
2769 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2770 ; CHECK: [[bb2]] = OpLabel
2771 ; CHECK-NEXT: OpSelectionMerge [[loop_cont]]
2772 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]]
2773 ; CHECK: [[bb3]] = OpLabel
2774 ; CHECK-NEXT: OpBranch [[loop_cont]]
2775 ; CHECK: [[loop_cont]] = OpLabel
2776 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[loop_header]] [[loop_merge]]
2777 ; CHECK: [[loop_merge]] = OpLabel
2778 ; CHECK-NEXT: OpReturn
2779 %main = OpFunction %void None %func_type
2780 %entry_bb = OpLabel
2781 OpBranch %loop_header
2782 %loop_header = OpLabel
2783 OpLoopMerge %loop_merge %cont None
2784 OpBranch %bb1
2785 %bb1 = OpLabel
2786 OpSelectionMerge %cont None
2787 OpBranchConditional %true %bb2 %bb4
2788 %bb2 = OpLabel
2789 OpBranchConditional %undef_bool %bb3 %cont
2790 %bb3 = OpLabel
2791 OpBranch %cont
2792 %bb4 = OpLabel
2793 OpBranch %cont
2794 %cont = OpLabel
2795 OpBranchConditional %undef_bool %loop_header %loop_merge
2796 %loop_merge = OpLabel
2797 OpReturn
2798 OpFunctionEnd
2799 )";
2800 
2801   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2802 }
2803 
TEST_F(DeadBranchElimTest,SelectionMergeWithNestedLoop)2804 TEST_F(DeadBranchElimTest, SelectionMergeWithNestedLoop) {
2805   const std::string body =
2806       R"(
2807 ; CHECK: OpSelectionMerge [[merge1:%\w+]]
2808 ; CHECK: [[merge1]] = OpLabel
2809 ; CHECK-NEXT: OpBranch [[preheader:%\w+]]
2810 ; CHECK: [[preheader]] = OpLabel
2811 ; CHECK-NOT: OpLabel
2812 ; CHECK: OpBranch [[header:%\w+]]
2813 ; CHECK: [[header]] = OpLabel
2814 ; CHECK-NOT: OpLabel
2815 ; CHECK: OpLoopMerge [[merge2:%\w+]]
2816 ; CHECK: [[merge2]] = OpLabel
2817 ; CHECK-NEXT: OpUnreachable
2818                  OpCapability Shader
2819             %1 = OpExtInstImport "GLSL.std.450"
2820                  OpMemoryModel Logical GLSL450
2821                  OpEntryPoint Fragment %main "main"
2822                  OpExecutionMode %main OriginUpperLeft
2823                  OpSource ESSL 310
2824                  OpName %main "main"
2825                  OpName %h "h"
2826                  OpName %i "i"
2827          %void = OpTypeVoid
2828             %3 = OpTypeFunction %void
2829          %bool = OpTypeBool
2830   %_ptr_Function_bool = OpTypePointer Function %bool
2831          %true = OpConstantTrue %bool
2832           %int = OpTypeInt 32 1
2833   %_ptr_Function_int = OpTypePointer Function %int
2834         %int_1 = OpConstant %int 1
2835         %int_0 = OpConstant %int 0
2836            %27 = OpUndef %bool
2837          %main = OpFunction %void None %3
2838             %5 = OpLabel
2839             %h = OpVariable %_ptr_Function_bool Function
2840             %i = OpVariable %_ptr_Function_int Function
2841                  OpSelectionMerge %11 None
2842                  OpBranchConditional %27 %10 %11
2843            %10 = OpLabel
2844                  OpBranch %11
2845            %11 = OpLabel
2846                  OpSelectionMerge %14 None
2847                  OpBranchConditional %true %13 %14
2848            %13 = OpLabel
2849                  OpStore %i %int_1
2850                  OpBranch %19
2851            %19 = OpLabel
2852                  OpLoopMerge %21 %22 None
2853                  OpBranch %23
2854            %23 = OpLabel
2855            %26 = OpSGreaterThan %bool %int_1 %int_0
2856                  OpBranchConditional %true %20 %21
2857            %20 = OpLabel
2858                  OpBranch %22
2859            %22 = OpLabel
2860                  OpBranch %19
2861            %21 = OpLabel
2862                  OpBranch %14
2863            %14 = OpLabel
2864                  OpReturn
2865                  OpFunctionEnd
2866 )";
2867 
2868   SinglePassRunAndMatch<DeadBranchElimPass>(body, true);
2869 }
2870 
2871 // TODO(greg-lunarg): Add tests to verify handling of these cases:
2872 //
2873 //    More complex control flow
2874 //    Others?
2875 
2876 }  // namespace
2877 }  // namespace opt
2878 }  // namespace spvtools
2879