• 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 }
1381 
TEST_F(DeadBranchElimTest,LeaveContinueBackedgeExtraBlock)1382 TEST_F(DeadBranchElimTest, LeaveContinueBackedgeExtraBlock) {
1383   const std::string text = R"(
1384 ; CHECK: OpBranch [[header:%\w+]]
1385 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1386 ; CHECK-NEXT: OpBranch [[continue]]
1387 ; CHECK-NEXT: [[continue]] = OpLabel
1388 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[extra:%\w+]] [[merge]]
1389 ; CHECK-NEXT: [[extra]] = OpLabel
1390 ; CHECK-NEXT: OpBranch [[header]]
1391 ; CHECK-NEXT: [[merge]] = OpLabel
1392 ; CHECK-NEXT: OpReturn
1393 OpCapability Kernel
1394 OpCapability Linkage
1395 OpMemoryModel Logical OpenCL
1396 %bool = OpTypeBool
1397 %false = OpConstantFalse %bool
1398 %void = OpTypeVoid
1399 %funcTy = OpTypeFunction %void
1400 %func = OpFunction %void None %funcTy
1401 %1 = OpLabel
1402 OpBranch %2
1403 %2 = OpLabel
1404 OpLoopMerge %3 %4 None
1405 OpBranch %4
1406 %4 = OpLabel
1407 ; Be careful we don't remove the backedge to %2 despite never taking it.
1408 OpBranchConditional %false %5 %3
1409 ; This block remains live despite being unreachable.
1410 %5 = OpLabel
1411 OpBranch %2
1412 %3 = OpLabel
1413 OpReturn
1414 OpFunctionEnd
1415 )";
1416 
1417   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1418 }
1419 
TEST_F(DeadBranchElimTest,RemovePhiWithUnreachableContinue)1420 TEST_F(DeadBranchElimTest, RemovePhiWithUnreachableContinue) {
1421   const std::string text = R"(
1422 ; CHECK: [[entry:%\w+]] = OpLabel
1423 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1424 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1425 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
1426 ; CHECK-NEXT: [[ret]] = OpLabel
1427 ; CHECK-NEXT: OpReturn
1428 ; CHECK: [[continue]] = OpLabel
1429 ; CHECK-NEXT: OpBranch [[header]]
1430 ; CHECK: [[merge]] = OpLabel
1431 ; CHECK-NEXT: OpUnreachable
1432 OpCapability Kernel
1433 OpCapability Linkage
1434 OpMemoryModel Logical OpenCL
1435 OpName %func "func"
1436 OpDecorate %func LinkageAttributes "func" Export
1437 %bool = OpTypeBool
1438 %false = OpConstantFalse %bool
1439 %true = OpConstantTrue %bool
1440 %void = OpTypeVoid
1441 %funcTy = OpTypeFunction %void
1442 %func = OpFunction %void None %funcTy
1443 %1 = OpLabel
1444 OpBranch %2
1445 %2 = OpLabel
1446 %phi = OpPhi %bool %false %1 %true %continue
1447 OpLoopMerge %merge %continue None
1448 OpBranch %3
1449 %3 = OpLabel
1450 OpReturn
1451 %continue = OpLabel
1452 OpBranch %2
1453 %merge = OpLabel
1454 OpReturn
1455 OpFunctionEnd
1456 )";
1457 
1458   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1459 }
1460 
TEST_F(DeadBranchElimTest,UnreachableLoopMergeAndContinueTargets)1461 TEST_F(DeadBranchElimTest, UnreachableLoopMergeAndContinueTargets) {
1462   const std::string text = R"(
1463 ; CHECK: [[undef:%\w+]] = OpUndef %bool
1464 ; CHECK: OpSelectionMerge [[header:%\w+]]
1465 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_lab:%\w+]] [[else_lab:%\w+]]
1466 ; CHECK: OpPhi %bool %false [[if_lab]] %false [[else_lab]] [[undef]] [[continue:%\w+]]
1467 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
1468 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
1469 ; CHECK-NEXT: [[ret]] = OpLabel
1470 ; CHECK-NEXT: OpReturn
1471 ; CHECK: [[continue]] = OpLabel
1472 ; CHECK-NEXT: OpBranch [[header]]
1473 ; CHECK: [[merge]] = OpLabel
1474 ; CHECK-NEXT: OpUnreachable
1475 OpCapability Kernel
1476 OpCapability Linkage
1477 OpMemoryModel Logical OpenCL
1478 OpName %func "func"
1479 OpDecorate %func LinkageAttributes "func" Export
1480 %bool = OpTypeBool
1481 %false = OpConstantFalse %bool
1482 %true = OpConstantTrue %bool
1483 %void = OpTypeVoid
1484 %funcTy = OpTypeFunction %void
1485 %func = OpFunction %void None %funcTy
1486 %1 = OpLabel
1487 %c = OpUndef %bool
1488 OpSelectionMerge %2 None
1489 OpBranchConditional %c %if %else
1490 %if = OpLabel
1491 OpBranch %2
1492 %else = OpLabel
1493 OpBranch %2
1494 %2 = OpLabel
1495 %phi = OpPhi %bool %false %if %false %else %true %continue
1496 OpLoopMerge %merge %continue None
1497 OpBranch %3
1498 %3 = OpLabel
1499 OpReturn
1500 %continue = OpLabel
1501 OpBranch %2
1502 %merge = OpLabel
1503 OpReturn
1504 OpFunctionEnd
1505 )";
1506 
1507   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1508 }
TEST_F(DeadBranchElimTest,EarlyReconvergence)1509 TEST_F(DeadBranchElimTest, EarlyReconvergence) {
1510   const std::string text = R"(
1511 ; CHECK-NOT: OpBranchConditional
1512 ; CHECK: [[logical:%\w+]] = OpLogicalOr
1513 ; CHECK-NOT: OpPhi
1514 ; CHECK: OpLogicalAnd {{%\w+}} {{%\w+}} [[logical]]
1515 OpCapability Shader
1516 OpMemoryModel Logical GLSL450
1517 OpEntryPoint Fragment %func "func"
1518 OpExecutionMode %func OriginUpperLeft
1519 %void = OpTypeVoid
1520 %bool = OpTypeBool
1521 %false = OpConstantFalse %bool
1522 %true = OpConstantTrue %bool
1523 %func_ty = OpTypeFunction %void
1524 %func = OpFunction %void None %func_ty
1525 %1 = OpLabel
1526 OpSelectionMerge %2 None
1527 OpBranchConditional %false %3 %4
1528 %3 = OpLabel
1529 %12 = OpLogicalNot %bool %true
1530 OpBranch %2
1531 %4 = OpLabel
1532 OpSelectionMerge %14 None
1533 OpBranchConditional %false %5 %6
1534 %5 = OpLabel
1535 %10 = OpLogicalAnd %bool %true %false
1536 OpBranch %7
1537 %6 = OpLabel
1538 %11 = OpLogicalOr %bool %true %false
1539 OpBranch %7
1540 %7 = OpLabel
1541 ; This phi is in a block preceeding the merge %14!
1542 %8 = OpPhi %bool %10 %5 %11 %6
1543 OpBranch %14
1544 %14 = OpLabel
1545 OpBranch %2
1546 %2 = OpLabel
1547 %9 = OpPhi %bool %12 %3 %8 %14
1548 %13 = OpLogicalAnd %bool %true %9
1549 OpReturn
1550 OpFunctionEnd
1551 )";
1552 
1553   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1554 }
1555 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksFloating)1556 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloating) {
1557   const std::string text = R"(
1558 ; CHECK: OpFunction
1559 ; CHECK-NEXT: OpLabel
1560 ; CHECK-NEXT: OpReturn
1561 ; CHECK-NEXT: OpFunctionEnd
1562 OpCapability Kernel
1563 OpCapability Linkage
1564 OpMemoryModel Logical OpenCL
1565 OpName %func "func"
1566 OpDecorate %func LinkageAttributes "func" Export
1567 %void = OpTypeVoid
1568 %1 = OpTypeFunction %void
1569 %func = OpFunction %void None %1
1570 %2 = OpLabel
1571 OpReturn
1572 %3 = OpLabel
1573 OpReturn
1574 OpFunctionEnd
1575 )";
1576 
1577   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1578 }
1579 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksFloatingJoin)1580 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloatingJoin) {
1581   const std::string text = R"(
1582 ; CHECK: OpFunction
1583 ; CHECK-NEXT: OpFunctionParameter
1584 ; CHECK-NEXT: OpLabel
1585 ; CHECK-NEXT: OpReturn
1586 ; CHECK-NEXT: OpFunctionEnd
1587 OpCapability Kernel
1588 OpCapability Linkage
1589 OpMemoryModel Logical OpenCL
1590 OpName %func "func"
1591 OpDecorate %func LinkageAttributes "func" Export
1592 %void = OpTypeVoid
1593 %bool = OpTypeBool
1594 %false = OpConstantFalse %bool
1595 %true = OpConstantTrue %bool
1596 %1 = OpTypeFunction %void %bool
1597 %func = OpFunction %void None %1
1598 %bool_param = OpFunctionParameter %bool
1599 %2 = OpLabel
1600 OpReturn
1601 %3 = OpLabel
1602 OpSelectionMerge %6 None
1603 OpBranchConditional %bool_param %4 %5
1604 %4 = OpLabel
1605 OpBranch %6
1606 %5 = OpLabel
1607 OpBranch %6
1608 %6 = OpLabel
1609 %7 = OpPhi %bool %true %4 %false %6
1610 OpReturn
1611 OpFunctionEnd
1612 )";
1613 
1614   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1615 }
1616 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksDeadPhi)1617 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksDeadPhi) {
1618   const std::string text = R"(
1619 ; CHECK: OpFunction
1620 ; CHECK-NEXT: OpFunctionParameter
1621 ; CHECK-NEXT: OpLabel
1622 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1623 ; CHECK-NEXT: [[label]] = OpLabel
1624 ; CHECK-NEXT: OpLogicalNot %bool %true
1625 ; CHECK-NEXT: OpReturn
1626 ; CHECK-NEXT: OpFunctionEnd
1627 OpCapability Kernel
1628 OpCapability Linkage
1629 OpMemoryModel Logical OpenCL
1630 OpName %func "func"
1631 OpDecorate %func LinkageAttributes "func" Export
1632 %void = OpTypeVoid
1633 %bool = OpTypeBool
1634 %false = OpConstantFalse %bool
1635 %true = OpConstantTrue %bool
1636 %1 = OpTypeFunction %void %bool
1637 %func = OpFunction %void None %1
1638 %bool_param = OpFunctionParameter %bool
1639 %2 = OpLabel
1640 OpBranch %3
1641 %4 = OpLabel
1642 OpBranch %3
1643 %3 = OpLabel
1644 %5 = OpPhi %bool %true %2 %false %4
1645 %6 = OpLogicalNot %bool %5
1646 OpReturn
1647 OpFunctionEnd
1648 )";
1649 
1650   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1651 }
1652 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksPartiallyDeadPhi)1653 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksPartiallyDeadPhi) {
1654   const std::string text = R"(
1655 ; CHECK: OpFunction
1656 ; CHECK-NEXT: [[param:%\w+]] = OpFunctionParameter
1657 ; CHECK-NEXT: OpLabel
1658 ; CHECK-NEXT: OpBranchConditional [[param]] [[merge:%\w+]] [[br:%\w+]]
1659 ; CHECK-NEXT: [[merge]] = OpLabel
1660 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %bool %true %2 %false [[br]]
1661 ; CHECK-NEXT: OpLogicalNot %bool [[phi]]
1662 ; CHECK-NEXT: OpReturn
1663 ; CHECK-NEXT: [[br]] = OpLabel
1664 ; CHECK-NEXT: OpBranch [[merge]]
1665 ; CHECK-NEXT: OpFunctionEnd
1666 OpCapability Kernel
1667 OpCapability Linkage
1668 OpMemoryModel Logical OpenCL
1669 OpName %func "func"
1670 OpDecorate %func LinkageAttributes "func" Export
1671 %void = OpTypeVoid
1672 %bool = OpTypeBool
1673 %false = OpConstantFalse %bool
1674 %true = OpConstantTrue %bool
1675 %1 = OpTypeFunction %void %bool
1676 %func = OpFunction %void None %1
1677 %bool_param = OpFunctionParameter %bool
1678 %2 = OpLabel
1679 OpBranchConditional %bool_param %3 %7
1680 %7 = OpLabel
1681 OpBranch %3
1682 %4 = OpLabel
1683 OpBranch %3
1684 %3 = OpLabel
1685 %5 = OpPhi %bool %true %2 %false %7 %false %4
1686 %6 = OpLogicalNot %bool %5
1687 OpReturn
1688 OpFunctionEnd
1689 )";
1690 
1691   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1692   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1693 }
1694 
TEST_F(DeadBranchElimTest,LiveHeaderDeadPhi)1695 TEST_F(DeadBranchElimTest, LiveHeaderDeadPhi) {
1696   const std::string text = R"(
1697 ; CHECK: OpLabel
1698 ; CHECK-NOT: OpBranchConditional
1699 ; CHECK-NOT: OpPhi
1700 ; CHECK: OpLogicalNot %bool %false
1701 OpCapability Kernel
1702 OpCapability Linkage
1703 OpMemoryModel Logical OpenCL
1704 OpName %func "func"
1705 OpDecorate %func LinkageAttributes "func" Export
1706 %void = OpTypeVoid
1707 %bool = OpTypeBool
1708 %true = OpConstantTrue %bool
1709 %false = OpConstantFalse %bool
1710 %func_ty = OpTypeFunction %void
1711 %func = OpFunction %void None %func_ty
1712 %1 = OpLabel
1713 OpSelectionMerge %3 None
1714 OpBranchConditional %true %2 %3
1715 %2 = OpLabel
1716 OpBranch %3
1717 %3 = OpLabel
1718 %5 = OpPhi %bool %true %3 %false %2
1719 %6 = OpLogicalNot %bool %5
1720 OpReturn
1721 OpFunctionEnd
1722 )";
1723 
1724   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1725 }
1726 
TEST_F(DeadBranchElimTest,ExtraBackedgeBlocksLive)1727 TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksLive) {
1728   const std::string text = R"(
1729 ; CHECK: [[entry:%\w+]] = OpLabel
1730 ; CHECK-NOT: OpSelectionMerge
1731 ; CHECK: OpBranch [[header:%\w+]]
1732 ; CHECK-NEXT: [[header]] = OpLabel
1733 ; CHECK-NEXT: OpPhi %bool %true [[entry]] %false [[backedge:%\w+]]
1734 ; CHECK-NEXT: OpLoopMerge
1735 OpCapability Kernel
1736 OpCapability Linkage
1737 OpMemoryModel Logical OpenCL
1738 OpName %func "func"
1739 OpDecorate %func LinkageAttributes "func" Export
1740 %void = OpTypeVoid
1741 %bool = OpTypeBool
1742 %true = OpConstantTrue %bool
1743 %false = OpConstantFalse %bool
1744 %func_ty = OpTypeFunction %void %bool
1745 %func = OpFunction %void None %func_ty
1746 %param = OpFunctionParameter %bool
1747 %entry = OpLabel
1748 OpSelectionMerge %if_merge None
1749 ; This dead branch is included to ensure the pass does work.
1750 OpBranchConditional %false %if_merge %loop_header
1751 %loop_header = OpLabel
1752 ; Both incoming edges are live, so the phi should be untouched.
1753 %phi = OpPhi %bool %true %entry %false %backedge
1754 OpLoopMerge %loop_merge %continue None
1755 OpBranchConditional %param %loop_merge %continue
1756 %continue = OpLabel
1757 OpBranch %backedge
1758 %backedge = OpLabel
1759 OpBranch %loop_header
1760 %loop_merge = OpLabel
1761 OpBranch %if_merge
1762 %if_merge = OpLabel
1763 OpReturn
1764 OpFunctionEnd
1765 )";
1766 
1767   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1768 }
1769 
TEST_F(DeadBranchElimTest,ExtraBackedgeBlocksUnreachable)1770 TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksUnreachable) {
1771   const std::string text = R"(
1772 ; CHECK: [[entry:%\w+]] = OpLabel
1773 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1774 ; CHECK-NEXT: [[header]] = OpLabel
1775 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1776 ; CHECK-NEXT: OpBranch [[merge]]
1777 ; CHECK-NEXT: [[merge]] = OpLabel
1778 ; CHECK-NEXT: OpReturn
1779 ; CHECK-NEXT: [[continue]] = OpLabel
1780 ; CHECK-NEXT: OpBranch [[header]]
1781 OpCapability Kernel
1782 OpCapability Linkage
1783 OpMemoryModel Logical OpenCL
1784 OpName %func "func"
1785 OpDecorate %func LinkageAttributes "func" Export
1786 %void = OpTypeVoid
1787 %bool = OpTypeBool
1788 %true = OpConstantTrue %bool
1789 %false = OpConstantFalse %bool
1790 %func_ty = OpTypeFunction %void %bool
1791 %func = OpFunction %void None %func_ty
1792 %param = OpFunctionParameter %bool
1793 %entry = OpLabel
1794 OpBranch %loop_header
1795 %loop_header = OpLabel
1796 ; Since the continue is unreachable, %backedge will be removed. The phi will
1797 ; instead require an edge from %continue.
1798 %phi = OpPhi %bool %true %entry %false %backedge
1799 OpLoopMerge %merge %continue None
1800 OpBranch %merge
1801 %continue = OpLabel
1802 OpBranch %backedge
1803 %backedge = OpLabel
1804 OpBranch %loop_header
1805 %merge = OpLabel
1806 OpReturn
1807 OpFunctionEnd
1808 )";
1809 
1810   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1811 }
1812 
TEST_F(DeadBranchElimTest,NoUnnecessaryChanges)1813 TEST_F(DeadBranchElimTest, NoUnnecessaryChanges) {
1814   const std::string text = R"(
1815 OpCapability Shader
1816 OpMemoryModel Logical GLSL450
1817 OpEntryPoint Fragment %func "func"
1818 %void = OpTypeVoid
1819 %bool = OpTypeBool
1820 %true = OpConstantTrue %bool
1821 %undef = OpUndef %bool
1822 %functy = OpTypeFunction %void
1823 %func = OpFunction %void None %functy
1824 %1 = OpLabel
1825 OpBranch %2
1826 %2 = OpLabel
1827 OpLoopMerge %4 %5 None
1828 OpBranch %6
1829 %6 = OpLabel
1830 OpReturn
1831 %5 = OpLabel
1832 OpBranch %2
1833 %4 = OpLabel
1834 OpUnreachable
1835 OpFunctionEnd
1836 )";
1837 
1838   auto result = SinglePassRunToBinary<DeadBranchElimPass>(text, true);
1839   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
1840 }
1841 
TEST_F(DeadBranchElimTest,ExtraBackedgePartiallyDead)1842 TEST_F(DeadBranchElimTest, ExtraBackedgePartiallyDead) {
1843   const std::string text = R"(
1844 ; CHECK: OpLabel
1845 ; CHECK: [[header:%\w+]] = OpLabel
1846 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1847 ; CHECK: [[merge]] = OpLabel
1848 ; CHECK: [[continue]] = OpLabel
1849 ; CHECK: OpBranch [[extra:%\w+]]
1850 ; CHECK: [[extra]] = OpLabel
1851 ; CHECK-NOT: OpSelectionMerge
1852 ; CHECK-NEXT: OpBranch [[else:%\w+]]
1853 ; CHECK-NEXT: [[else]] = OpLabel
1854 ; CHECK-NEXT: OpLogicalOr
1855 ; CHECK-NEXT: OpBranch [[backedge:%\w+]]
1856 ; CHECK-NEXT: [[backedge:%\w+]] = OpLabel
1857 ; CHECK-NEXT: OpBranch [[header]]
1858 OpCapability Kernel
1859 OpCapability Linkage
1860 OpMemoryModel Logical OpenCL
1861 OpName %func "func"
1862 OpDecorate %func LinkageAttributes "func" Export
1863 %void = OpTypeVoid
1864 %bool = OpTypeBool
1865 %true = OpConstantTrue %bool
1866 %false = OpConstantFalse %bool
1867 %func_ty = OpTypeFunction %void %bool
1868 %func = OpFunction %void None %func_ty
1869 %param = OpFunctionParameter %bool
1870 %entry = OpLabel
1871 OpBranch %loop_header
1872 %loop_header = OpLabel
1873 OpLoopMerge %loop_merge %continue None
1874 OpBranchConditional %param %loop_merge %continue
1875 %continue = OpLabel
1876 OpBranch %extra
1877 %extra = OpLabel
1878 OpSelectionMerge %backedge None
1879 OpBranchConditional %false %then %else
1880 %then = OpLabel
1881 %and = OpLogicalAnd %bool %true %false
1882 OpBranch %backedge
1883 %else = OpLabel
1884 %or = OpLogicalOr %bool %true %false
1885 OpBranch %backedge
1886 %backedge = OpLabel
1887 OpBranch %loop_header
1888 %loop_merge = OpLabel
1889 OpReturn
1890 OpFunctionEnd
1891 )";
1892 
1893   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1894 }
1895 
TEST_F(DeadBranchElimTest,UnreachableContinuePhiInMerge)1896 TEST_F(DeadBranchElimTest, UnreachableContinuePhiInMerge) {
1897   const std::string text = R"(
1898 ; CHECK: [[entry:%\w+]] = OpLabel
1899 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1900 ; CHECK-NEXT: [[header]] = OpLabel
1901 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1902 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1903 ; CHECK-NEXT: [[label]] = OpLabel
1904 ; CHECK-NEXT: [[fadd:%\w+]] = OpFAdd
1905 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1906 ; CHECK-NEXT: [[label]] = OpLabel
1907 ; CHECK-NEXT: OpBranch [[merge]]
1908 ; CHECK-NEXT: [[continue]] = OpLabel
1909 ; CHECK-NEXT: OpBranch [[header]]
1910 ; CHECK-NEXT: [[merge]] = OpLabel
1911 ; CHECK-NEXT: OpStore {{%\w+}} [[fadd]]
1912                OpCapability Shader
1913           %1 = OpExtInstImport "GLSL.std.450"
1914                OpMemoryModel Logical GLSL450
1915                OpEntryPoint Fragment %main "main" %o
1916                OpExecutionMode %main OriginUpperLeft
1917                OpSource GLSL 430
1918                OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
1919                OpSourceExtension "GL_GOOGLE_include_directive"
1920                OpName %main "main"
1921                OpName %o "o"
1922                OpName %S "S"
1923                OpMemberName %S 0 "a"
1924                OpName %U_t "U_t"
1925                OpMemberName %U_t 0 "g_F"
1926                OpMemberName %U_t 1 "g_F2"
1927                OpDecorate %o Location 0
1928                OpMemberDecorate %S 0 Offset 0
1929                OpMemberDecorate %U_t 0 Volatile
1930                OpMemberDecorate %U_t 0 Offset 0
1931                OpMemberDecorate %U_t 1 Offset 4
1932                OpDecorate %U_t BufferBlock
1933        %void = OpTypeVoid
1934           %7 = OpTypeFunction %void
1935       %float = OpTypeFloat 32
1936 %_ptr_Function_float = OpTypePointer Function %float
1937     %float_0 = OpConstant %float 0
1938         %int = OpTypeInt 32 1
1939 %_ptr_Function_int = OpTypePointer Function %int
1940       %int_0 = OpConstant %int 0
1941      %int_10 = OpConstant %int 10
1942        %bool = OpTypeBool
1943        %true = OpConstantTrue %bool
1944     %float_1 = OpConstant %float 1
1945     %float_5 = OpConstant %float 5
1946       %int_1 = OpConstant %int 1
1947 %_ptr_Output_float = OpTypePointer Output %float
1948           %o = OpVariable %_ptr_Output_float Output
1949           %S = OpTypeStruct %float
1950         %U_t = OpTypeStruct %S %S
1951 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
1952        %main = OpFunction %void None %7
1953          %22 = OpLabel
1954                OpBranch %23
1955          %23 = OpLabel
1956          %24 = OpPhi %float %float_0 %22 %25 %26
1957          %27 = OpPhi %int %int_0 %22 %28 %26
1958                OpLoopMerge %29 %26 None
1959                OpBranch %40
1960          %40 = OpLabel
1961          %25 = OpFAdd %float %24 %float_1
1962                OpSelectionMerge %30 None
1963                OpBranchConditional %true %31 %30
1964          %31 = OpLabel
1965                OpBranch %29
1966          %30 = OpLabel
1967                OpBranch %26
1968          %26 = OpLabel
1969          %28 = OpIAdd %int %27 %int_1
1970          %32 = OpSLessThan %bool %27 %int_10
1971 ; continue block branches to the header or another none dead block.
1972                OpBranchConditional %32 %23 %29
1973          %29 = OpLabel
1974          %33 = OpPhi %float %24 %26 %25 %31
1975                OpStore %o %33
1976                OpReturn
1977                OpFunctionEnd
1978 )";
1979 
1980   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1981 }
1982 
TEST_F(DeadBranchElimTest,NonStructuredIf)1983 TEST_F(DeadBranchElimTest, NonStructuredIf) {
1984   const std::string text = R"(
1985 ; CHECK-NOT: OpBranchConditional
1986 OpCapability Kernel
1987 OpCapability Linkage
1988 OpMemoryModel Logical OpenCL
1989 OpDecorate %func LinkageAttributes "func" Export
1990 %void = OpTypeVoid
1991 %bool = OpTypeBool
1992 %true = OpConstantTrue %bool
1993 %functy = OpTypeFunction %void
1994 %func = OpFunction %void None %functy
1995 %entry = OpLabel
1996 OpBranchConditional %true %then %else
1997 %then = OpLabel
1998 OpBranch %final
1999 %else = OpLabel
2000 OpBranch %final
2001 %final = OpLabel
2002 OpReturn
2003 OpFunctionEnd
2004 )";
2005 
2006   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2007 }
2008 
TEST_F(DeadBranchElimTest,ReorderBlocks)2009 TEST_F(DeadBranchElimTest, ReorderBlocks) {
2010   const std::string text = R"(
2011 ; CHECK: OpLabel
2012 ; CHECK: OpBranch [[label:%\w+]]
2013 ; CHECK: [[label:%\w+]] = OpLabel
2014 ; CHECK-NEXT: OpLogicalNot
2015 ; CHECK-NEXT: OpBranch [[label:%\w+]]
2016 ; CHECK: [[label]] = OpLabel
2017 ; CHECK-NEXT: OpReturn
2018 OpCapability Shader
2019 OpMemoryModel Logical GLSL450
2020 OpEntryPoint Fragment %func "func"
2021 OpExecutionMode %func OriginUpperLeft
2022 %void = OpTypeVoid
2023 %bool = OpTypeBool
2024 %true = OpConstantTrue %bool
2025 %func_ty = OpTypeFunction %void
2026 %func = OpFunction %void None %func_ty
2027 %1 = OpLabel
2028 OpSelectionMerge %3 None
2029 OpBranchConditional %true %2 %3
2030 %3 = OpLabel
2031 OpReturn
2032 %2 = OpLabel
2033 %not = OpLogicalNot %bool %true
2034 OpBranch %3
2035 OpFunctionEnd
2036 )";
2037 
2038   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2039 }
2040 
TEST_F(DeadBranchElimTest,ReorderBlocksMultiple)2041 TEST_F(DeadBranchElimTest, ReorderBlocksMultiple) {
2042   // Checks are not important. The validation post optimization is the
2043   // important part.
2044   const std::string text = R"(
2045 ; CHECK: OpLabel
2046 OpCapability Shader
2047 OpMemoryModel Logical GLSL450
2048 OpEntryPoint Fragment %func "func"
2049 OpExecutionMode %func OriginUpperLeft
2050 %void = OpTypeVoid
2051 %bool = OpTypeBool
2052 %true = OpConstantTrue %bool
2053 %func_ty = OpTypeFunction %void
2054 %func = OpFunction %void None %func_ty
2055 %1 = OpLabel
2056 OpSelectionMerge %3 None
2057 OpBranchConditional %true %2 %3
2058 %3 = OpLabel
2059 OpReturn
2060 %2 = OpLabel
2061 OpBranch %4
2062 %4 = OpLabel
2063 OpBranch %3
2064 OpFunctionEnd
2065 )";
2066 
2067   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2068 }
2069 
TEST_F(DeadBranchElimTest,ReorderBlocksMultiple2)2070 TEST_F(DeadBranchElimTest, ReorderBlocksMultiple2) {
2071   // Checks are not important. The validation post optimization is the
2072   // important part.
2073   const std::string text = R"(
2074 ; CHECK: OpLabel
2075 OpCapability Shader
2076 OpMemoryModel Logical GLSL450
2077 OpEntryPoint Fragment %func "func"
2078 OpExecutionMode %func OriginUpperLeft
2079 %void = OpTypeVoid
2080 %bool = OpTypeBool
2081 %true = OpConstantTrue %bool
2082 %func_ty = OpTypeFunction %void
2083 %func = OpFunction %void None %func_ty
2084 %1 = OpLabel
2085 OpSelectionMerge %3 None
2086 OpBranchConditional %true %2 %3
2087 %3 = OpLabel
2088 OpBranch %5
2089 %5 = OpLabel
2090 OpReturn
2091 %2 = OpLabel
2092 OpBranch %4
2093 %4 = OpLabel
2094 OpBranch %3
2095 OpFunctionEnd
2096 )";
2097 
2098   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2099 }
2100 
TEST_F(DeadBranchElimTest,SelectionMergeWithEarlyExit1)2101 TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit1) {
2102   // Checks  that if a selection merge construct contains a conditional branch
2103   // to the merge node, then the OpSelectionMerge instruction is positioned
2104   // correctly.
2105   const std::string predefs = R"(
2106 OpCapability Shader
2107 %1 = OpExtInstImport "GLSL.std.450"
2108 OpMemoryModel Logical GLSL450
2109 OpEntryPoint Fragment %main "main"
2110 OpExecutionMode %main OriginUpperLeft
2111 OpSource GLSL 140
2112 %void = OpTypeVoid
2113 %func_type = OpTypeFunction %void
2114 %bool = OpTypeBool
2115 %true = OpConstantTrue %bool
2116 %undef_bool = OpUndef %bool
2117 )";
2118 
2119   const std::string body =
2120       R"(
2121 ; CHECK: OpFunction
2122 ; CHECK-NEXT: OpLabel
2123 ; CHECK-NEXT: OpBranch [[taken_branch:%\w+]]
2124 ; CHECK-NEXT: [[taken_branch]] = OpLabel
2125 ; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
2126 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[merge]] {{%\w+}}
2127 %main = OpFunction %void None %func_type
2128 %entry_bb = OpLabel
2129 OpSelectionMerge %outer_merge None
2130 OpBranchConditional %true %bb1 %bb3
2131 %bb1 = OpLabel
2132 OpBranchConditional %undef_bool %outer_merge %bb2
2133 %bb2 = OpLabel
2134 OpBranch %outer_merge
2135 %bb3 = OpLabel
2136 OpBranch %outer_merge
2137 %outer_merge = OpLabel
2138 OpReturn
2139 OpFunctionEnd
2140 )";
2141 
2142   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2143 }
2144 
TEST_F(DeadBranchElimTest,SelectionMergeWithEarlyExit2)2145 TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit2) {
2146   // Checks  that if a selection merge construct contains a conditional branch
2147   // to the merge node, then the OpSelectionMerge instruction is positioned
2148   // correctly.
2149   const std::string predefs = R"(
2150 OpCapability Shader
2151 %1 = OpExtInstImport "GLSL.std.450"
2152 OpMemoryModel Logical GLSL450
2153 OpEntryPoint Fragment %main "main"
2154 OpExecutionMode %main OriginUpperLeft
2155 OpSource GLSL 140
2156 %void = OpTypeVoid
2157 %func_type = OpTypeFunction %void
2158 %bool = OpTypeBool
2159 %true = OpConstantTrue %bool
2160 %undef_bool = OpUndef %bool
2161 )";
2162 
2163   const std::string body =
2164       R"(
2165 ; CHECK: OpFunction
2166 ; CHECK-NEXT: OpLabel
2167 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2168 ; CHECK-NEXT: [[bb1]] = OpLabel
2169 ; CHECK-NEXT: OpSelectionMerge [[inner_merge:%\w+]]
2170 ; CHECK: [[inner_merge]] = OpLabel
2171 ; CHECK-NEXT: OpSelectionMerge [[outer_merge:%\w+]]
2172 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[outer_merge]:%\w+]] {{%\w+}}
2173 ; CHECK: [[outer_merge]] = OpLabel
2174 ; CHECK-NEXT: OpReturn
2175 %main = OpFunction %void None %func_type
2176 %entry_bb = OpLabel
2177 OpSelectionMerge %outer_merge None
2178 OpBranchConditional %true %bb1 %bb5
2179 %bb1 = OpLabel
2180 OpSelectionMerge %inner_merge None
2181 OpBranchConditional %undef_bool %bb2 %bb3
2182 %bb2 = OpLabel
2183 OpBranch %inner_merge
2184 %bb3 = OpLabel
2185 OpBranch %inner_merge
2186 %inner_merge = OpLabel
2187 OpBranchConditional %undef_bool %outer_merge %bb4
2188 %bb4 = OpLabel
2189 OpBranch %outer_merge
2190 %bb5 = OpLabel
2191 OpBranch %outer_merge
2192 %outer_merge = OpLabel
2193 OpReturn
2194 OpFunctionEnd
2195 )";
2196 
2197   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2198 }
2199 
TEST_F(DeadBranchElimTest,SelectionMergeWithConditionalExit)2200 TEST_F(DeadBranchElimTest, SelectionMergeWithConditionalExit) {
2201   // Checks that if a selection merge construct contains a conditional branch
2202   // to the merge node, then we keep the OpSelectionMerge on that branch.
2203   const std::string predefs = R"(
2204 OpCapability Shader
2205 %1 = OpExtInstImport "GLSL.std.450"
2206 OpMemoryModel Logical GLSL450
2207 OpEntryPoint Fragment %main "main"
2208 OpExecutionMode %main OriginUpperLeft
2209 OpSource GLSL 140
2210 %void = OpTypeVoid
2211 %func_type = OpTypeFunction %void
2212 %bool = OpTypeBool
2213 %true = OpConstantTrue %bool
2214 %uint = OpTypeInt 32 0
2215 %undef_int = OpUndef %uint
2216 )";
2217 
2218   const std::string body =
2219       R"(
2220 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2221 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2222 ; CHECK: [[bb1]] = OpLabel
2223 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2224 ; CHECK: [[bb2]] = OpLabel
2225 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2226 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 1 [[bb3:%\w+]]
2227 ; CHECK: [[bb3]] = OpLabel
2228 ; CHECK-NEXT: OpBranch [[sel_merge]]
2229 ; CHECK: [[sel_merge]] = OpLabel
2230 ; CHECK-NEXT: OpBranch [[loop_merge]]
2231 ; CHECK: [[loop_merge]] = OpLabel
2232 ; CHECK-NEXT: OpReturn
2233 %main = OpFunction %void None %func_type
2234 %entry_bb = OpLabel
2235 OpBranch %loop_header
2236 %loop_header = OpLabel
2237 OpLoopMerge %loop_merge %cont None
2238 OpBranch %bb1
2239 %bb1 = OpLabel
2240 OpSelectionMerge %sel_merge None
2241 OpBranchConditional %true %bb2 %bb4
2242 %bb2 = OpLabel
2243 OpSwitch %undef_int %sel_merge 1 %bb3
2244 %bb3 = OpLabel
2245 OpBranch %sel_merge
2246 %bb4 = OpLabel
2247 OpBranch %sel_merge
2248 %sel_merge = OpLabel
2249 OpBranch %loop_merge
2250 %cont = OpLabel
2251 OpBranch %loop_header
2252 %loop_merge = OpLabel
2253 OpReturn
2254 OpFunctionEnd
2255 )";
2256 
2257   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2258 }
2259 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop)2260 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop) {
2261   // Checks  that if a selection merge construct contains a conditional branch
2262   // to a loop surrounding the selection merge, then we do not keep the
2263   // OpSelectionMerge instruction.
2264   const std::string predefs = R"(
2265 OpCapability Shader
2266 %1 = OpExtInstImport "GLSL.std.450"
2267 OpMemoryModel Logical GLSL450
2268 OpEntryPoint Fragment %main "main"
2269 OpExecutionMode %main OriginUpperLeft
2270 OpSource GLSL 140
2271 %void = OpTypeVoid
2272 %func_type = OpTypeFunction %void
2273 %bool = OpTypeBool
2274 %true = OpConstantTrue %bool
2275 %undef_bool = OpUndef %bool
2276 )";
2277 
2278   const std::string body =
2279       R"(
2280 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2281 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2282 ; CHECK: [[bb1]] = OpLabel
2283 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2284 ; CHECK: [[bb2]] = OpLabel
2285 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_merge]]
2286 ; CHECK: [[bb3]] = OpLabel
2287 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2288 ; CHECK: [[sel_merge]] = OpLabel
2289 ; CHECK-NEXT: OpBranch [[loop_merge]]
2290 ; CHECK: [[loop_merge]] = OpLabel
2291 ; CHECK-NEXT: OpReturn
2292 %main = OpFunction %void None %func_type
2293 %entry_bb = OpLabel
2294 OpBranch %loop_header
2295 %loop_header = OpLabel
2296 OpLoopMerge %loop_merge %cont None
2297 OpBranch %bb1
2298 %bb1 = OpLabel
2299 OpSelectionMerge %sel_merge None
2300 OpBranchConditional %true %bb2 %bb4
2301 %bb2 = OpLabel
2302 OpBranchConditional %undef_bool %bb3 %loop_merge
2303 %bb3 = OpLabel
2304 OpBranch %sel_merge
2305 %bb4 = OpLabel
2306 OpBranch %sel_merge
2307 %sel_merge = OpLabel
2308 OpBranch %loop_merge
2309 %cont = OpLabel
2310 OpBranch %loop_header
2311 %loop_merge = OpLabel
2312 OpReturn
2313 OpFunctionEnd
2314 )";
2315 
2316   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2317 }
2318 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue)2319 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue) {
2320   // Checks  that if a selection merge construct contains a conditional branch
2321   // to continue of a loop surrounding the selection merge, then we do not keep
2322   // the OpSelectionMerge instruction.
2323   const std::string predefs = R"(
2324 OpCapability Shader
2325 %1 = OpExtInstImport "GLSL.std.450"
2326 OpMemoryModel Logical GLSL450
2327 OpEntryPoint Fragment %main "main"
2328 OpExecutionMode %main OriginUpperLeft
2329 OpSource GLSL 140
2330 %void = OpTypeVoid
2331 %func_type = OpTypeFunction %void
2332 %bool = OpTypeBool
2333 %true = OpConstantTrue %bool
2334 %undef_bool = OpUndef %bool
2335 )";
2336 
2337   const std::string body =
2338       R"(;
2339 ; CHECK: OpLabel
2340 ; CHECK: [[loop_header:%\w+]] = OpLabel
2341 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2342 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2343 ; CHECK: [[bb1]] = OpLabel
2344 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2345 ; CHECK: [[bb2]] = OpLabel
2346 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]]
2347 ; CHECK: [[bb3]] = OpLabel
2348 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2349 ; CHECK: [[sel_merge]] = OpLabel
2350 ; CHECK-NEXT: OpBranch [[loop_merge]]
2351 ; CHECK: [[loop_cont]] = OpLabel
2352 ; CHECK-NEXT: OpBranch [[loop_header]]
2353 ; CHECK: [[loop_merge]] = OpLabel
2354 ; CHECK-NEXT: OpReturn
2355 %main = OpFunction %void None %func_type
2356 %entry_bb = OpLabel
2357 OpBranch %loop_header
2358 %loop_header = OpLabel
2359 OpLoopMerge %loop_merge %cont None
2360 OpBranch %bb1
2361 %bb1 = OpLabel
2362 OpSelectionMerge %sel_merge None
2363 OpBranchConditional %true %bb2 %bb4
2364 %bb2 = OpLabel
2365 OpBranchConditional %undef_bool %bb3 %cont
2366 %bb3 = OpLabel
2367 OpBranch %sel_merge
2368 %bb4 = OpLabel
2369 OpBranch %sel_merge
2370 %sel_merge = OpLabel
2371 OpBranch %loop_merge
2372 %cont = OpLabel
2373 OpBranch %loop_header
2374 %loop_merge = OpLabel
2375 OpReturn
2376 OpFunctionEnd
2377 )";
2378 
2379   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2380 }
2381 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop2)2382 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop2) {
2383   // Same as |SelectionMergeWithExitToLoop|, except the switch goes to the loop
2384   // merge or the selection merge.  In this case, we do not need an
2385   // OpSelectionMerge either.
2386   const std::string predefs = R"(
2387 OpCapability Shader
2388 %1 = OpExtInstImport "GLSL.std.450"
2389 OpMemoryModel Logical GLSL450
2390 OpEntryPoint Fragment %main "main"
2391 OpExecutionMode %main OriginUpperLeft
2392 OpSource GLSL 140
2393 %void = OpTypeVoid
2394 %func_type = OpTypeFunction %void
2395 %bool = OpTypeBool
2396 %true = OpConstantTrue %bool
2397 %undef_bool = OpUndef %bool
2398 )";
2399 
2400   const std::string body =
2401       R"(
2402 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2403 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2404 ; CHECK: [[bb1]] = OpLabel
2405 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2406 ; CHECK: [[bb2]] = OpLabel
2407 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_merge]]
2408 ; CHECK: [[sel_merge]] = OpLabel
2409 ; CHECK-NEXT: OpBranch [[loop_merge]]
2410 ; CHECK: [[loop_merge]] = OpLabel
2411 ; CHECK-NEXT: OpReturn
2412 %main = OpFunction %void None %func_type
2413 %entry_bb = OpLabel
2414 OpBranch %loop_header
2415 %loop_header = OpLabel
2416 OpLoopMerge %loop_merge %cont None
2417 OpBranch %bb1
2418 %bb1 = OpLabel
2419 OpSelectionMerge %sel_merge None
2420 OpBranchConditional %true %bb2 %bb4
2421 %bb2 = OpLabel
2422 OpBranchConditional %undef_bool %sel_merge %loop_merge
2423 %bb4 = OpLabel
2424 OpBranch %sel_merge
2425 %sel_merge = OpLabel
2426 OpBranch %loop_merge
2427 %cont = OpLabel
2428 OpBranch %loop_header
2429 %loop_merge = OpLabel
2430 OpReturn
2431 OpFunctionEnd
2432 )";
2433 
2434   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2435 }
2436 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue2)2437 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue2) {
2438   // Same as |SelectionMergeWithExitToLoopContinue|, except the branch goes to
2439   // the loop continue or the selection merge.  In this case, we do not need an
2440   // OpSelectionMerge either.
2441   const std::string predefs = R"(
2442 OpCapability Shader
2443 %1 = OpExtInstImport "GLSL.std.450"
2444 OpMemoryModel Logical GLSL450
2445 OpEntryPoint Fragment %main "main"
2446 OpExecutionMode %main OriginUpperLeft
2447 OpSource GLSL 140
2448 %void = OpTypeVoid
2449 %func_type = OpTypeFunction %void
2450 %bool = OpTypeBool
2451 %true = OpConstantTrue %bool
2452 %undef_bool = OpUndef %bool
2453 )";
2454 
2455   const std::string body =
2456       R"(
2457 ; CHECK: OpLabel
2458 ; CHECK: [[loop_header:%\w+]] = OpLabel
2459 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2460 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2461 ; CHECK: [[bb1]] = OpLabel
2462 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2463 ; CHECK: [[bb2]] = OpLabel
2464 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_cont]]
2465 ; CHECK: [[sel_merge]] = OpLabel
2466 ; CHECK-NEXT: OpBranch [[loop_merge]]
2467 ; CHECK: [[loop_cont]] = OpLabel
2468 ; CHECK: OpBranch [[loop_header]]
2469 ; CHECK: [[loop_merge]] = OpLabel
2470 ; CHECK-NEXT: OpReturn
2471 %main = OpFunction %void None %func_type
2472 %entry_bb = OpLabel
2473 OpBranch %loop_header
2474 %loop_header = OpLabel
2475 OpLoopMerge %loop_merge %cont None
2476 OpBranch %bb1
2477 %bb1 = OpLabel
2478 OpSelectionMerge %sel_merge None
2479 OpBranchConditional %true %bb2 %bb4
2480 %bb2 = OpLabel
2481 OpBranchConditional %undef_bool %sel_merge %cont
2482 %bb4 = OpLabel
2483 OpBranch %sel_merge
2484 %sel_merge = OpLabel
2485 OpBranch %loop_merge
2486 %cont = OpLabel
2487 OpBranch %loop_header
2488 %loop_merge = OpLabel
2489 OpReturn
2490 OpFunctionEnd
2491 )";
2492 
2493   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2494 }
2495 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop3)2496 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop3) {
2497   // Checks that if a selection merge construct contains a conditional branch
2498   // to the merge of a surrounding loop, the selection merge, and another block
2499   // inside the selection merge, then we must keep the OpSelectionMerge
2500   // instruction on that branch.
2501   const std::string predefs = R"(
2502 OpCapability Shader
2503 %1 = OpExtInstImport "GLSL.std.450"
2504 OpMemoryModel Logical GLSL450
2505 OpEntryPoint Fragment %main "main"
2506 OpExecutionMode %main OriginUpperLeft
2507 OpSource GLSL 140
2508 %void = OpTypeVoid
2509 %func_type = OpTypeFunction %void
2510 %bool = OpTypeBool
2511 %true = OpConstantTrue %bool
2512 %uint = OpTypeInt 32 0
2513 %undef_int = OpUndef %uint
2514 )";
2515 
2516   const std::string body =
2517       R"(
2518 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2519 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2520 ; CHECK: [[bb1]] = OpLabel
2521 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2522 ; CHECK: [[bb2]] = OpLabel
2523 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2524 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_merge]] 1 [[bb3:%\w+]]
2525 ; CHECK: [[bb3]] = OpLabel
2526 ; CHECK-NEXT: OpBranch [[sel_merge]]
2527 ; CHECK: [[sel_merge]] = OpLabel
2528 ; CHECK-NEXT: OpBranch [[loop_merge]]
2529 ; CHECK: [[loop_merge]] = OpLabel
2530 ; CHECK-NEXT: OpReturn
2531 %main = OpFunction %void None %func_type
2532 %entry_bb = OpLabel
2533 OpBranch %loop_header
2534 %loop_header = OpLabel
2535 OpLoopMerge %loop_merge %cont None
2536 OpBranch %bb1
2537 %bb1 = OpLabel
2538 OpSelectionMerge %sel_merge None
2539 OpBranchConditional %true %bb2 %bb4
2540 %bb2 = OpLabel
2541 OpSwitch %undef_int %sel_merge 0 %loop_merge 1 %bb3
2542 %bb3 = OpLabel
2543 OpBranch %sel_merge
2544 %bb4 = OpLabel
2545 OpBranch %sel_merge
2546 %sel_merge = OpLabel
2547 OpBranch %loop_merge
2548 %cont = OpLabel
2549 OpBranch %loop_header
2550 %loop_merge = OpLabel
2551 OpReturn
2552 OpFunctionEnd
2553 )";
2554 
2555   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2556 }
2557 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue3)2558 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue3) {
2559   // Checks that if a selection merge construct contains a conditional branch
2560   // to the merge of a surrounding loop, the selection merge, and another block
2561   // inside the selection merge, then we must keep the OpSelectionMerge
2562   // instruction on that branch.
2563   const std::string predefs = R"(
2564 OpCapability Shader
2565 %1 = OpExtInstImport "GLSL.std.450"
2566 OpMemoryModel Logical GLSL450
2567 OpEntryPoint Fragment %main "main"
2568 OpExecutionMode %main OriginUpperLeft
2569 OpSource GLSL 140
2570 %void = OpTypeVoid
2571 %func_type = OpTypeFunction %void
2572 %bool = OpTypeBool
2573 %true = OpConstantTrue %bool
2574 %uint = OpTypeInt 32 0
2575 %undef_int = OpUndef %uint
2576 )";
2577 
2578   const std::string body =
2579       R"(
2580 ; CHECK: OpLabel
2581 ; CHECK: [[loop_header:%\w+]] = OpLabel
2582 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_continue:%\w+]]
2583 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2584 ; CHECK: [[bb1]] = OpLabel
2585 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2586 ; CHECK: [[bb2]] = OpLabel
2587 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2588 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_continue]] 1 [[bb3:%\w+]]
2589 ; CHECK: [[bb3]] = OpLabel
2590 ; CHECK-NEXT: OpBranch [[sel_merge]]
2591 ; CHECK: [[sel_merge]] = OpLabel
2592 ; CHECK-NEXT: OpBranch [[loop_merge]]
2593 ; CHECK: [[loop_continue]] = OpLabel
2594 ; CHECK-NEXT: OpBranch [[loop_header]]
2595 ; CHECK: [[loop_merge]] = OpLabel
2596 ; CHECK-NEXT: OpReturn
2597 %main = OpFunction %void None %func_type
2598 %entry_bb = OpLabel
2599 OpBranch %loop_header
2600 %loop_header = OpLabel
2601 OpLoopMerge %loop_merge %cont None
2602 OpBranch %bb1
2603 %bb1 = OpLabel
2604 OpSelectionMerge %sel_merge None
2605 OpBranchConditional %true %bb2 %bb4
2606 %bb2 = OpLabel
2607 OpSwitch %undef_int %sel_merge 0 %cont 1 %bb3
2608 %bb3 = OpLabel
2609 OpBranch %sel_merge
2610 %bb4 = OpLabel
2611 OpBranch %sel_merge
2612 %sel_merge = OpLabel
2613 OpBranch %loop_merge
2614 %cont = OpLabel
2615 OpBranch %loop_header
2616 %loop_merge = OpLabel
2617 OpReturn
2618 OpFunctionEnd
2619 )";
2620 
2621   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2622 }
2623 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop4)2624 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop4) {
2625   // Same as |SelectionMergeWithExitToLoop|, except the branch in the selection
2626   // construct is an |OpSwitch| instead of an |OpConditionalBranch|.  The
2627   // OpSelectionMerge instruction is not needed in this case either.
2628   const std::string predefs = R"(
2629 OpCapability Shader
2630 %1 = OpExtInstImport "GLSL.std.450"
2631 OpMemoryModel Logical GLSL450
2632 OpEntryPoint Fragment %main "main"
2633 OpExecutionMode %main OriginUpperLeft
2634 OpSource GLSL 140
2635 %void = OpTypeVoid
2636 %func_type = OpTypeFunction %void
2637 %bool = OpTypeBool
2638 %true = OpConstantTrue %bool
2639 %uint = OpTypeInt 32 0
2640 %undef_int = OpUndef %uint
2641 )";
2642 
2643   const std::string body =
2644       R"(
2645 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2646 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2647 ; CHECK: [[bb1]] = OpLabel
2648 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2649 ; CHECK: [[bb2]] = OpLabel
2650 ; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_merge]] 1 [[bb3:%\w+]]
2651 ; CHECK: [[bb3]] = OpLabel
2652 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2653 ; CHECK: [[sel_merge]] = OpLabel
2654 ; CHECK-NEXT: OpBranch [[loop_merge]]
2655 ; CHECK: [[loop_merge]] = OpLabel
2656 ; CHECK-NEXT: OpReturn
2657 %main = OpFunction %void None %func_type
2658 %entry_bb = OpLabel
2659 OpBranch %loop_header
2660 %loop_header = OpLabel
2661 OpLoopMerge %loop_merge %cont None
2662 OpBranch %bb1
2663 %bb1 = OpLabel
2664 OpSelectionMerge %sel_merge None
2665 OpBranchConditional %true %bb2 %bb4
2666 %bb2 = OpLabel
2667 OpSwitch %undef_int %bb3 0 %loop_merge 1 %bb3
2668 %bb3 = OpLabel
2669 OpBranch %sel_merge
2670 %bb4 = OpLabel
2671 OpBranch %sel_merge
2672 %sel_merge = OpLabel
2673 OpBranch %loop_merge
2674 %cont = OpLabel
2675 OpBranch %loop_header
2676 %loop_merge = OpLabel
2677 OpReturn
2678 OpFunctionEnd
2679 )";
2680 
2681   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2682 }
2683 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue4)2684 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue4) {
2685   // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the
2686   // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|.
2687   // The OpSelectionMerge instruction is not needed in this case either.
2688   const std::string predefs = R"(
2689 OpCapability Shader
2690 %1 = OpExtInstImport "GLSL.std.450"
2691 OpMemoryModel Logical GLSL450
2692 OpEntryPoint Fragment %main "main"
2693 OpExecutionMode %main OriginUpperLeft
2694 OpSource GLSL 140
2695 %void = OpTypeVoid
2696 %func_type = OpTypeFunction %void
2697 %bool = OpTypeBool
2698 %true = OpConstantTrue %bool
2699 %uint = OpTypeInt 32 0
2700 %undef_int = OpUndef %uint
2701 )";
2702 
2703   const std::string body =
2704       R"(
2705 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2706 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2707 ; CHECK: [[bb1]] = OpLabel
2708 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2709 ; CHECK: [[bb2]] = OpLabel
2710 ; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_cont]] 1 [[bb3:%\w+]]
2711 ; CHECK: [[bb3]] = OpLabel
2712 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2713 ; CHECK: [[sel_merge]] = OpLabel
2714 ; CHECK-NEXT: OpBranch [[loop_merge]]
2715 ; CHECK: [[loop_merge]] = OpLabel
2716 ; CHECK-NEXT: OpReturn
2717 %main = OpFunction %void None %func_type
2718 %entry_bb = OpLabel
2719 OpBranch %loop_header
2720 %loop_header = OpLabel
2721 OpLoopMerge %loop_merge %cont None
2722 OpBranch %bb1
2723 %bb1 = OpLabel
2724 OpSelectionMerge %sel_merge None
2725 OpBranchConditional %true %bb2 %bb4
2726 %bb2 = OpLabel
2727 OpSwitch %undef_int %bb3 0 %cont 1 %bb3
2728 %bb3 = OpLabel
2729 OpBranch %sel_merge
2730 %bb4 = OpLabel
2731 OpBranch %sel_merge
2732 %sel_merge = OpLabel
2733 OpBranch %loop_merge
2734 %cont = OpLabel
2735 OpBranch %loop_header
2736 %loop_merge = OpLabel
2737 OpReturn
2738 OpFunctionEnd
2739 )";
2740 
2741   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2742 }
2743 
TEST_F(DeadBranchElimTest,SelectionMergeSameAsLoopContinue)2744 TEST_F(DeadBranchElimTest, SelectionMergeSameAsLoopContinue) {
2745   // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the
2746   // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|.
2747   // The OpSelectionMerge instruction is not needed in this case either.
2748   const std::string predefs = R"(
2749 OpCapability Shader
2750 %1 = OpExtInstImport "GLSL.std.450"
2751 OpMemoryModel Logical GLSL450
2752 OpEntryPoint Fragment %main "main"
2753 OpExecutionMode %main OriginUpperLeft
2754 OpSource GLSL 140
2755 %void = OpTypeVoid
2756 %func_type = OpTypeFunction %void
2757 %bool = OpTypeBool
2758 %true = OpConstantTrue %bool
2759 %uint = OpTypeInt 32 0
2760 %undef_bool = OpUndef %bool
2761 )";
2762 
2763   const std::string body =
2764       R"(
2765 ; CHECK: OpLabel
2766 ; CHECK: [[loop_header:%\w+]] = OpLabel
2767 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2768 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2769 ; CHECK: [[bb1]] = OpLabel
2770 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2771 ; CHECK: [[bb2]] = OpLabel
2772 ; CHECK-NEXT: OpSelectionMerge [[loop_cont]]
2773 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]]
2774 ; CHECK: [[bb3]] = OpLabel
2775 ; CHECK-NEXT: OpBranch [[loop_cont]]
2776 ; CHECK: [[loop_cont]] = OpLabel
2777 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[loop_header]] [[loop_merge]]
2778 ; CHECK: [[loop_merge]] = OpLabel
2779 ; CHECK-NEXT: OpReturn
2780 %main = OpFunction %void None %func_type
2781 %entry_bb = OpLabel
2782 OpBranch %loop_header
2783 %loop_header = OpLabel
2784 OpLoopMerge %loop_merge %cont None
2785 OpBranch %bb1
2786 %bb1 = OpLabel
2787 OpSelectionMerge %cont None
2788 OpBranchConditional %true %bb2 %bb4
2789 %bb2 = OpLabel
2790 OpBranchConditional %undef_bool %bb3 %cont
2791 %bb3 = OpLabel
2792 OpBranch %cont
2793 %bb4 = OpLabel
2794 OpBranch %cont
2795 %cont = OpLabel
2796 OpBranchConditional %undef_bool %loop_header %loop_merge
2797 %loop_merge = OpLabel
2798 OpReturn
2799 OpFunctionEnd
2800 )";
2801 
2802   // The selection merge in the loop naming the continue target as merge is
2803   // invalid, but handled by this pass so validation is disabled.
2804   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, false);
2805 }
2806 
TEST_F(DeadBranchElimTest,SelectionMergeWithNestedLoop)2807 TEST_F(DeadBranchElimTest, SelectionMergeWithNestedLoop) {
2808   const std::string body =
2809       R"(
2810 ; CHECK: OpSelectionMerge [[merge1:%\w+]]
2811 ; CHECK: [[merge1]] = OpLabel
2812 ; CHECK-NEXT: OpBranch [[preheader:%\w+]]
2813 ; CHECK: [[preheader]] = OpLabel
2814 ; CHECK-NOT: OpLabel
2815 ; CHECK: OpBranch [[header:%\w+]]
2816 ; CHECK: [[header]] = OpLabel
2817 ; CHECK-NOT: OpLabel
2818 ; CHECK: OpLoopMerge [[merge2:%\w+]]
2819 ; CHECK: [[merge2]] = OpLabel
2820 ; CHECK-NEXT: OpUnreachable
2821                  OpCapability Shader
2822             %1 = OpExtInstImport "GLSL.std.450"
2823                  OpMemoryModel Logical GLSL450
2824                  OpEntryPoint Fragment %main "main"
2825                  OpExecutionMode %main OriginUpperLeft
2826                  OpSource ESSL 310
2827                  OpName %main "main"
2828                  OpName %h "h"
2829                  OpName %i "i"
2830          %void = OpTypeVoid
2831             %3 = OpTypeFunction %void
2832          %bool = OpTypeBool
2833   %_ptr_Function_bool = OpTypePointer Function %bool
2834          %true = OpConstantTrue %bool
2835           %int = OpTypeInt 32 1
2836   %_ptr_Function_int = OpTypePointer Function %int
2837         %int_1 = OpConstant %int 1
2838         %int_0 = OpConstant %int 0
2839            %27 = OpUndef %bool
2840          %main = OpFunction %void None %3
2841             %5 = OpLabel
2842             %h = OpVariable %_ptr_Function_bool Function
2843             %i = OpVariable %_ptr_Function_int Function
2844                  OpSelectionMerge %11 None
2845                  OpBranchConditional %27 %10 %11
2846            %10 = OpLabel
2847                  OpBranch %11
2848            %11 = OpLabel
2849                  OpSelectionMerge %14 None
2850                  OpBranchConditional %true %13 %14
2851            %13 = OpLabel
2852                  OpStore %i %int_1
2853                  OpBranch %19
2854            %19 = OpLabel
2855                  OpLoopMerge %21 %22 None
2856                  OpBranch %23
2857            %23 = OpLabel
2858            %26 = OpSGreaterThan %bool %int_1 %int_0
2859                  OpBranchConditional %true %20 %21
2860            %20 = OpLabel
2861                  OpBranch %22
2862            %22 = OpLabel
2863                  OpBranch %19
2864            %21 = OpLabel
2865                  OpBranch %14
2866            %14 = OpLabel
2867                  OpReturn
2868                  OpFunctionEnd
2869 )";
2870 
2871   SinglePassRunAndMatch<DeadBranchElimPass>(body, true);
2872 }
2873 
TEST_F(DeadBranchElimTest,DontFoldBackedge)2874 TEST_F(DeadBranchElimTest, DontFoldBackedge) {
2875   const std::string body =
2876       R"(OpCapability Shader
2877 %1 = OpExtInstImport "GLSL.std.450"
2878 OpMemoryModel Logical GLSL450
2879 OpEntryPoint Fragment %2 "main"
2880 OpExecutionMode %2 OriginUpperLeft
2881 %void = OpTypeVoid
2882 %4 = OpTypeFunction %void
2883 %bool = OpTypeBool
2884 %false = OpConstantFalse %bool
2885 %2 = OpFunction %void None %4
2886 %7 = OpLabel
2887 OpBranch %8
2888 %8 = OpLabel
2889 OpLoopMerge %9 %10 None
2890 OpBranch %11
2891 %11 = OpLabel
2892 %12 = OpUndef %bool
2893 OpSelectionMerge %10 None
2894 OpBranchConditional %12 %13 %10
2895 %13 = OpLabel
2896 OpBranch %9
2897 %10 = OpLabel
2898 OpBranch %14
2899 %14 = OpLabel
2900 OpBranchConditional %false %8 %9
2901 %9 = OpLabel
2902 OpReturn
2903 OpFunctionEnd
2904 )";
2905 
2906   SinglePassRunAndCheck<DeadBranchElimPass>(body, body, true);
2907 }
2908 
TEST_F(DeadBranchElimTest,FoldBackedgeToHeader)2909 TEST_F(DeadBranchElimTest, FoldBackedgeToHeader) {
2910   const std::string body =
2911       R"(
2912 ; CHECK: OpLabel
2913 ; CHECK: [[header:%\w+]] = OpLabel
2914 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[cont:%\w+]]
2915 ; CHECK: [[cont]] = OpLabel
2916 ; This branch may not be in the continue block, but must come after it.
2917 ; CHECK: OpBranch [[header]]
2918 OpCapability Shader
2919 %1 = OpExtInstImport "GLSL.std.450"
2920 OpMemoryModel Logical GLSL450
2921 OpEntryPoint Fragment %2 "main"
2922 OpExecutionMode %2 OriginUpperLeft
2923 %void = OpTypeVoid
2924 %4 = OpTypeFunction %void
2925 %bool = OpTypeBool
2926 %true = OpConstantTrue %bool
2927 %2 = OpFunction %void None %4
2928 %7 = OpLabel
2929 OpBranch %8
2930 %8 = OpLabel
2931 OpLoopMerge %9 %10 None
2932 OpBranch %11
2933 %11 = OpLabel
2934 %12 = OpUndef %bool
2935 OpSelectionMerge %10 None
2936 OpBranchConditional %12 %13 %10
2937 %13 = OpLabel
2938 OpBranch %9
2939 %10 = OpLabel
2940 OpBranch %14
2941 %14 = OpLabel
2942 OpBranchConditional %true %8 %9
2943 %9 = OpLabel
2944 OpReturn
2945 OpFunctionEnd
2946 )";
2947 
2948   // The selection merge in the loop naming the continue target as merge is
2949   // invalid, but handled by this pass so validation is disabled.
2950   SinglePassRunAndMatch<DeadBranchElimPass>(body, false);
2951 }
2952 
TEST_F(DeadBranchElimTest,UnreachableMergeAndContinueSameBlock)2953 TEST_F(DeadBranchElimTest, UnreachableMergeAndContinueSameBlock) {
2954   const std::string spirv = R"(
2955 ; CHECK: OpLabel
2956 ; CHECK: [[outer:%\w+]] = OpLabel
2957 ; CHECK-NEXT: OpLoopMerge [[outer_merge:%\w+]] [[outer_cont:%\w+]] None
2958 ; CHECK-NEXT: OpBranch [[inner:%\w+]]
2959 ; CHECK: [[inner]] = OpLabel
2960 ; CHECK: OpLoopMerge [[outer_cont]] [[inner_cont:%\w+]] None
2961 ; CHECK: [[inner_cont]] = OpLabel
2962 ; CHECK-NEXT: OpBranch [[inner]]
2963 ; CHECK: [[outer_cont]] = OpLabel
2964 ; CHECK-NEXT: OpBranch [[outer]]
2965 ; CHECK: [[outer_merge]] = OpLabel
2966 ; CHECK-NEXT: OpUnreachable
2967 OpCapability Shader
2968 OpMemoryModel Logical GLSL450
2969 OpEntryPoint GLCompute %main "main"
2970 OpExecutionMode %main LocalSize 1 1 1
2971 %void = OpTypeVoid
2972 %bool = OpTypeBool
2973 %true = OpConstantTrue %bool
2974 %void_fn = OpTypeFunction %void
2975 %main = OpFunction %void None %void_fn
2976 %entry = OpLabel
2977 OpBranch %outer_loop
2978 %outer_loop = OpLabel
2979 OpLoopMerge %outer_merge %outer_continue None
2980 OpBranch %inner_loop
2981 %inner_loop = OpLabel
2982 OpLoopMerge %outer_continue %inner_continue None
2983 OpBranch %inner_body
2984 %inner_body = OpLabel
2985 OpSelectionMerge %inner_continue None
2986 OpBranchConditional %true %ret %inner_continue
2987 %ret = OpLabel
2988 OpReturn
2989 %inner_continue = OpLabel
2990 OpBranchConditional %true %outer_continue %inner_loop
2991 %outer_continue = OpLabel
2992 OpBranchConditional %true %outer_merge %outer_loop
2993 %outer_merge = OpLabel
2994 OpReturn
2995 OpFunctionEnd
2996 )";
2997 
2998   SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
2999 }
3000 
3001 // Fold a switch with a nested break.  The only case should be the default.
TEST_F(DeadBranchElimTest,FoldSwitchWithNestedBreak)3002 TEST_F(DeadBranchElimTest, FoldSwitchWithNestedBreak) {
3003   const std::string spirv = R"(
3004 ; CHECK: OpSwitch %int_3 [[case_bb:%\w+]]{{[[:space:]]}}
3005 ; CHECK: [[case_bb]] = OpLabel
3006 ; CHECK-NEXT: OpUndef
3007 ; CHECK-NEXT: OpSelectionMerge
3008                OpCapability Shader
3009           %1 = OpExtInstImport "GLSL.std.450"
3010                OpMemoryModel Logical GLSL450
3011                OpEntryPoint Vertex %2 "main"
3012                OpSource GLSL 450
3013        %void = OpTypeVoid
3014           %4 = OpTypeFunction %void
3015         %int = OpTypeInt 32 1
3016 %_ptr_Function_int = OpTypePointer Function %int
3017       %int_3 = OpConstant %int 3
3018       %int_1 = OpConstant %int 1
3019        %bool = OpTypeBool
3020           %2 = OpFunction %void None %4
3021          %10 = OpLabel
3022                OpSelectionMerge %11 None
3023                OpSwitch %int_3 %12 3 %13
3024          %12 = OpLabel
3025                OpBranch %11
3026          %13 = OpLabel
3027          %14 = OpUndef %bool
3028                OpSelectionMerge %15 None
3029                OpBranchConditional %14 %16 %15
3030          %16 = OpLabel
3031                OpBranch %11
3032          %15 = OpLabel
3033                OpBranch %11
3034          %11 = OpLabel
3035                OpReturn
3036                OpFunctionEnd
3037 )";
3038 
3039   SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
3040 }
3041 
TEST_F(DeadBranchElimTest,FoldBranchWithBreakToSwitch)3042 TEST_F(DeadBranchElimTest, FoldBranchWithBreakToSwitch) {
3043   const std::string spirv = R"(
3044 ; CHECK: OpSelectionMerge [[sel_merge:%\w+]]
3045 ; CHECK-NEXT: OpSwitch {{%\w+}} {{%\w+}} 3 [[bb:%\w+]]
3046 ; CHECK: [[bb]] = OpLabel
3047 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
3048 ; CHECK: [[bb2]] = OpLabel
3049 ; CHECK-NOT: OpSelectionMerge
3050 ; CHECK: OpFunctionEnd
3051                OpCapability Shader
3052           %1 = OpExtInstImport "GLSL.std.450"
3053                OpMemoryModel Logical GLSL450
3054                OpEntryPoint Vertex %2 "main"
3055                OpSource GLSL 450
3056        %void = OpTypeVoid
3057           %4 = OpTypeFunction %void
3058         %int = OpTypeInt 32 1
3059 %_ptr_Function_int = OpTypePointer Function %int
3060       %int_3 = OpConstant %int 3
3061       %int_1 = OpConstant %int 1
3062        %bool = OpTypeBool
3063        %true = OpConstantTrue %bool
3064           %2 = OpFunction %void None %4
3065          %10 = OpLabel
3066   %undef_int = OpUndef %int
3067                OpSelectionMerge %11 None
3068                OpSwitch %undef_int %12 3 %13
3069          %12 = OpLabel
3070                OpBranch %11
3071          %13 = OpLabel
3072                OpSelectionMerge %15 None
3073                OpBranchConditional %true %16 %15
3074          %16 = OpLabel
3075          %14 = OpUndef %bool
3076                OpBranchConditional %14 %11 %17
3077          %17 = OpLabel
3078                OpBranch %15
3079          %15 = OpLabel
3080                OpBranch %11
3081          %11 = OpLabel
3082                OpReturn
3083                OpFunctionEnd
3084 )";
3085 
3086   SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
3087 }
3088 
TEST_F(DeadBranchElimTest,IfInSwitch)3089 TEST_F(DeadBranchElimTest, IfInSwitch) {
3090   // #version 310 es
3091   //
3092   // void main()
3093   // {
3094   //  switch(0)
3095   //  {
3096   //   case 0:
3097   //   if(false)
3098   //   {
3099   //   }
3100   //   else
3101   //   {
3102   //   }
3103   //  }
3104   // }
3105 
3106   const std::string before =
3107       R"(OpCapability Shader
3108 %1 = OpExtInstImport "GLSL.std.450"
3109 OpMemoryModel Logical GLSL450
3110 OpEntryPoint Fragment %main "main"
3111 OpExecutionMode %main OriginUpperLeft
3112 OpSource ESSL 310
3113 OpName %main "main"
3114 %void = OpTypeVoid
3115 %3 = OpTypeFunction %void
3116 %int = OpTypeInt 32 1
3117 %int_0 = OpConstant %int 0
3118 %bool = OpTypeBool
3119 %false = OpConstantFalse %bool
3120 %main = OpFunction %void None %3
3121 %5 = OpLabel
3122 OpSelectionMerge %9 None
3123 OpSwitch %int_0 %9 0 %8
3124 %8 = OpLabel
3125 OpSelectionMerge %13 None
3126 OpBranchConditional %false %12 %13
3127 %12 = OpLabel
3128 OpBranch %13
3129 %13 = OpLabel
3130 OpBranch %9
3131 %9 = OpLabel
3132 OpReturn
3133 OpFunctionEnd
3134 )";
3135 
3136   const std::string after =
3137       R"(OpCapability Shader
3138 %1 = OpExtInstImport "GLSL.std.450"
3139 OpMemoryModel Logical GLSL450
3140 OpEntryPoint Fragment %main "main"
3141 OpExecutionMode %main OriginUpperLeft
3142 OpSource ESSL 310
3143 OpName %main "main"
3144 %void = OpTypeVoid
3145 %4 = OpTypeFunction %void
3146 %int = OpTypeInt 32 1
3147 %int_0 = OpConstant %int 0
3148 %bool = OpTypeBool
3149 %false = OpConstantFalse %bool
3150 %main = OpFunction %void None %4
3151 %9 = OpLabel
3152 OpBranch %11
3153 %11 = OpLabel
3154 OpBranch %12
3155 %12 = OpLabel
3156 OpBranch %10
3157 %10 = OpLabel
3158 OpReturn
3159 OpFunctionEnd
3160 )";
3161 
3162   SinglePassRunAndCheck<DeadBranchElimPass>(before, after, true, true);
3163 }
3164 
TEST_F(DeadBranchElimTest,BreakInNestedHeaderWithSingleCase)3165 TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithSingleCase) {
3166   const std::string text = R"(OpCapability Shader
3167 %1 = OpExtInstImport "GLSL.std.450"
3168 OpMemoryModel Logical GLSL450
3169 OpEntryPoint Fragment %main "main"
3170 OpExecutionMode %main OriginUpperLeft
3171 OpSource GLSL 450
3172 OpName %main "main"
3173 %void = OpTypeVoid
3174 %4 = OpTypeFunction %void
3175 %bool = OpTypeBool
3176 %uint = OpTypeInt 32 0
3177 %uint_0 = OpConstant %uint 0
3178 %8 = OpUndef %bool
3179 %main = OpFunction %void None %4
3180 %9 = OpLabel
3181 OpSelectionMerge %10 None
3182 OpSwitch %uint_0 %11
3183 %11 = OpLabel
3184 OpSelectionMerge %12 None
3185 OpBranchConditional %8 %10 %12
3186 %12 = OpLabel
3187 OpBranch %10
3188 %10 = OpLabel
3189 OpReturn
3190 OpFunctionEnd
3191 )";
3192 
3193   SinglePassRunAndCheck<DeadBranchElimPass>(text, text, true, true);
3194 }
3195 
TEST_F(DeadBranchElimTest,BreakInNestedHeaderWithTwoCases)3196 TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithTwoCases) {
3197   const std::string text = R"(
3198 ; CHECK: OpSelectionMerge [[merge:%\w+]] None
3199 ; CHECK-NEXT: OpSwitch %uint_0 [[bb:%\w+\n]]
3200 OpCapability Shader
3201 %1 = OpExtInstImport "GLSL.std.450"
3202 OpMemoryModel Logical GLSL450
3203 OpEntryPoint Fragment %main "main"
3204 OpExecutionMode %main OriginUpperLeft
3205 OpSource GLSL 450
3206 OpName %main "main"
3207 %void = OpTypeVoid
3208 %4 = OpTypeFunction %void
3209 %bool = OpTypeBool
3210 %uint = OpTypeInt 32 0
3211 %uint_0 = OpConstant %uint 0
3212 %8 = OpUndef %bool
3213 %main = OpFunction %void None %4
3214 %9 = OpLabel
3215 OpSelectionMerge %10 None
3216 OpSwitch %uint_0 %11 1 %12
3217 %11 = OpLabel
3218 OpSelectionMerge %13 None
3219 OpBranchConditional %8 %10 %13
3220 %13 = OpLabel
3221 OpBranch %10
3222 %12 = OpLabel
3223 OpBranch %10
3224 %10 = OpLabel
3225 OpReturn
3226 OpFunctionEnd
3227 )";
3228 
3229   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
3230 }
3231 
3232 // TODO(greg-lunarg): Add tests to verify handling of these cases:
3233 //
3234 //    More complex control flow
3235 //    Others?
3236 
3237 }  // namespace
3238 }  // namespace opt
3239 }  // namespace spvtools
3240