• 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,IfThenElseNull)189 TEST_F(DeadBranchElimTest, IfThenElseNull) {
190   // For booleans OpConstantNull should be treated similar to OpConstantFalse.
191   //
192   // From the SPIR-V spec:
193   // OpConstantNull: Declares a new null constant value.
194   // The null value is type dependent, defined as follows:
195   // - Scalar Boolean: false
196   // ...
197 
198   const std::string predefs =
199       R"(OpCapability Shader
200 %1 = OpExtInstImport "GLSL.std.450"
201 OpMemoryModel Logical GLSL450
202 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
203 OpExecutionMode %main OriginUpperLeft
204 OpSource GLSL 140
205 OpName %main "main"
206 OpName %v "v"
207 OpName %gl_FragColor "gl_FragColor"
208 OpName %BaseColor "BaseColor"
209 %void = OpTypeVoid
210 %7 = OpTypeFunction %void
211 %bool = OpTypeBool
212 %9 = OpConstantNull %bool
213 %float = OpTypeFloat 32
214 %v4float = OpTypeVector %float 4
215 %_ptr_Function_v4float = OpTypePointer Function %v4float
216 %float_0 = OpConstant %float 0
217 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
218 %float_1 = OpConstant %float 1
219 %16 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
220 %_ptr_Output_v4float = OpTypePointer Output %v4float
221 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
222 %_ptr_Input_v4float = OpTypePointer Input %v4float
223 %BaseColor = OpVariable %_ptr_Input_v4float Input
224 )";
225 
226   const std::string before =
227       R"(%main = OpFunction %void None %7
228 %19 = OpLabel
229 %v = OpVariable %_ptr_Function_v4float Function
230 OpSelectionMerge %20 None
231 OpBranchConditional %9 %21 %22
232 %21 = OpLabel
233 OpStore %v %14
234 OpBranch %20
235 %22 = OpLabel
236 OpStore %v %16
237 OpBranch %20
238 %20 = OpLabel
239 %23 = OpLoad %v4float %v
240 OpStore %gl_FragColor %23
241 OpReturn
242 OpFunctionEnd
243 )";
244 
245   const std::string after =
246       R"(%main = OpFunction %void None %7
247 %19 = OpLabel
248 %v = OpVariable %_ptr_Function_v4float Function
249 OpBranch %22
250 %22 = OpLabel
251 OpStore %v %16
252 OpBranch %20
253 %20 = OpLabel
254 %23 = OpLoad %v4float %v
255 OpStore %gl_FragColor %23
256 OpReturn
257 OpFunctionEnd
258 )";
259 
260   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
261                                             true, true);
262 }
263 
TEST_F(DeadBranchElimTest,IfThenTrue)264 TEST_F(DeadBranchElimTest, IfThenTrue) {
265   // #version 140
266   //
267   // in vec4 BaseColor;
268   //
269   // void main()
270   // {
271   //     vec4 v = BaseColor;
272   //     if (true)
273   //       v = v * vec4(0.5,0.5,0.5,0.5);
274   //     gl_FragColor = v;
275   // }
276 
277   const std::string predefs =
278       R"(OpCapability Shader
279 %1 = OpExtInstImport "GLSL.std.450"
280 OpMemoryModel Logical GLSL450
281 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
282 OpExecutionMode %main OriginUpperLeft
283 OpSource GLSL 140
284 OpName %main "main"
285 OpName %v "v"
286 OpName %BaseColor "BaseColor"
287 OpName %gl_FragColor "gl_FragColor"
288 %void = OpTypeVoid
289 %7 = OpTypeFunction %void
290 %float = OpTypeFloat 32
291 %v4float = OpTypeVector %float 4
292 %_ptr_Function_v4float = OpTypePointer Function %v4float
293 %_ptr_Input_v4float = OpTypePointer Input %v4float
294 %BaseColor = OpVariable %_ptr_Input_v4float Input
295 %bool = OpTypeBool
296 %true = OpConstantTrue %bool
297 %float_0_5 = OpConstant %float 0.5
298 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
299 %_ptr_Output_v4float = OpTypePointer Output %v4float
300 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
301 )";
302 
303   const std::string before =
304       R"(%main = OpFunction %void None %7
305 %17 = OpLabel
306 %v = OpVariable %_ptr_Function_v4float Function
307 %18 = OpLoad %v4float %BaseColor
308 OpStore %v %18
309 OpSelectionMerge %19 None
310 OpBranchConditional %true %20 %19
311 %20 = OpLabel
312 %21 = OpLoad %v4float %v
313 %22 = OpFMul %v4float %21 %15
314 OpStore %v %22
315 OpBranch %19
316 %19 = OpLabel
317 %23 = OpLoad %v4float %v
318 OpStore %gl_FragColor %23
319 OpReturn
320 OpFunctionEnd
321 )";
322 
323   const std::string after =
324       R"(%main = OpFunction %void None %7
325 %17 = OpLabel
326 %v = OpVariable %_ptr_Function_v4float Function
327 %18 = OpLoad %v4float %BaseColor
328 OpStore %v %18
329 OpBranch %20
330 %20 = OpLabel
331 %21 = OpLoad %v4float %v
332 %22 = OpFMul %v4float %21 %15
333 OpStore %v %22
334 OpBranch %19
335 %19 = OpLabel
336 %23 = OpLoad %v4float %v
337 OpStore %gl_FragColor %23
338 OpReturn
339 OpFunctionEnd
340 )";
341 
342   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
343                                             true, true);
344 }
345 
TEST_F(DeadBranchElimTest,IfThenFalse)346 TEST_F(DeadBranchElimTest, IfThenFalse) {
347   // #version 140
348   //
349   // in vec4 BaseColor;
350   //
351   // void main()
352   // {
353   //     vec4 v = BaseColor;
354   //     if (false)
355   //       v = v * vec4(0.5,0.5,0.5,0.5);
356   //     gl_FragColor = v;
357   // }
358 
359   const std::string predefs =
360       R"(OpCapability Shader
361 %1 = OpExtInstImport "GLSL.std.450"
362 OpMemoryModel Logical GLSL450
363 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
364 OpExecutionMode %main OriginUpperLeft
365 OpSource GLSL 140
366 OpName %main "main"
367 OpName %v "v"
368 OpName %BaseColor "BaseColor"
369 OpName %gl_FragColor "gl_FragColor"
370 %void = OpTypeVoid
371 %7 = OpTypeFunction %void
372 %float = OpTypeFloat 32
373 %v4float = OpTypeVector %float 4
374 %_ptr_Function_v4float = OpTypePointer Function %v4float
375 %_ptr_Input_v4float = OpTypePointer Input %v4float
376 %BaseColor = OpVariable %_ptr_Input_v4float Input
377 %bool = OpTypeBool
378 %false = OpConstantFalse %bool
379 %float_0_5 = OpConstant %float 0.5
380 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
381 %_ptr_Output_v4float = OpTypePointer Output %v4float
382 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
383 )";
384 
385   const std::string before =
386       R"(%main = OpFunction %void None %7
387 %17 = OpLabel
388 %v = OpVariable %_ptr_Function_v4float Function
389 %18 = OpLoad %v4float %BaseColor
390 OpStore %v %18
391 OpSelectionMerge %19 None
392 OpBranchConditional %false %20 %19
393 %20 = OpLabel
394 %21 = OpLoad %v4float %v
395 %22 = OpFMul %v4float %21 %15
396 OpStore %v %22
397 OpBranch %19
398 %19 = OpLabel
399 %23 = OpLoad %v4float %v
400 OpStore %gl_FragColor %23
401 OpReturn
402 OpFunctionEnd
403 )";
404 
405   const std::string after =
406       R"(%main = OpFunction %void None %7
407 %17 = OpLabel
408 %v = OpVariable %_ptr_Function_v4float Function
409 %18 = OpLoad %v4float %BaseColor
410 OpStore %v %18
411 OpBranch %19
412 %19 = OpLabel
413 %23 = OpLoad %v4float %v
414 OpStore %gl_FragColor %23
415 OpReturn
416 OpFunctionEnd
417 )";
418 
419   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
420                                             true, true);
421 }
422 
TEST_F(DeadBranchElimTest,IfThenElsePhiTrue)423 TEST_F(DeadBranchElimTest, IfThenElsePhiTrue) {
424   // Test handling of phi in merge block after dead branch elimination.
425   // Note: The SPIR-V has had store/load elimination and phi insertion
426   //
427   // #version 140
428   //
429   // void main()
430   // {
431   //     vec4 v;
432   //     if (true)
433   //       v = vec4(0.0,0.0,0.0,0.0);
434   //     else
435   //       v = vec4(1.0,1.0,1.0,1.0);
436   //     gl_FragColor = v;
437   // }
438 
439   const std::string predefs =
440       R"(OpCapability Shader
441 %1 = OpExtInstImport "GLSL.std.450"
442 OpMemoryModel Logical GLSL450
443 OpEntryPoint Fragment %main "main" %gl_FragColor
444 OpExecutionMode %main OriginUpperLeft
445 OpSource GLSL 140
446 OpName %main "main"
447 OpName %gl_FragColor "gl_FragColor"
448 %void = OpTypeVoid
449 %5 = OpTypeFunction %void
450 %bool = OpTypeBool
451 %true = OpConstantTrue %bool
452 %float = OpTypeFloat 32
453 %v4float = OpTypeVector %float 4
454 %_ptr_Function_v4float = OpTypePointer Function %v4float
455 %float_0 = OpConstant %float 0
456 %12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
457 %float_1 = OpConstant %float 1
458 %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
459 %_ptr_Output_v4float = OpTypePointer Output %v4float
460 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
461 %_ptr_Input_v4float = OpTypePointer Input %v4float
462 )";
463 
464   const std::string before =
465       R"(%main = OpFunction %void None %5
466 %17 = OpLabel
467 OpSelectionMerge %18 None
468 OpBranchConditional %true %19 %20
469 %19 = OpLabel
470 OpBranch %18
471 %20 = OpLabel
472 OpBranch %18
473 %18 = OpLabel
474 %21 = OpPhi %v4float %12 %19 %14 %20
475 OpStore %gl_FragColor %21
476 OpReturn
477 OpFunctionEnd
478 )";
479 
480   const std::string after =
481       R"(%main = OpFunction %void None %5
482 %17 = OpLabel
483 OpBranch %19
484 %19 = OpLabel
485 OpBranch %18
486 %18 = OpLabel
487 OpStore %gl_FragColor %12
488 OpReturn
489 OpFunctionEnd
490 )";
491 
492   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
493                                             true, true);
494 }
495 
TEST_F(DeadBranchElimTest,IfThenElsePhiFalse)496 TEST_F(DeadBranchElimTest, IfThenElsePhiFalse) {
497   // Test handling of phi in merge block after dead branch elimination.
498   // Note: The SPIR-V has had store/load elimination and phi insertion
499   //
500   // #version 140
501   //
502   // void main()
503   // {
504   //     vec4 v;
505   //     if (true)
506   //       v = vec4(0.0,0.0,0.0,0.0);
507   //     else
508   //       v = vec4(1.0,1.0,1.0,1.0);
509   //     gl_FragColor = v;
510   // }
511 
512   const std::string predefs =
513       R"(OpCapability Shader
514 %1 = OpExtInstImport "GLSL.std.450"
515 OpMemoryModel Logical GLSL450
516 OpEntryPoint Fragment %main "main" %gl_FragColor
517 OpExecutionMode %main OriginUpperLeft
518 OpSource GLSL 140
519 OpName %main "main"
520 OpName %gl_FragColor "gl_FragColor"
521 %void = OpTypeVoid
522 %5 = OpTypeFunction %void
523 %bool = OpTypeBool
524 %false = OpConstantFalse %bool
525 %float = OpTypeFloat 32
526 %v4float = OpTypeVector %float 4
527 %_ptr_Function_v4float = OpTypePointer Function %v4float
528 %float_0 = OpConstant %float 0
529 %12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
530 %float_1 = OpConstant %float 1
531 %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
532 %_ptr_Output_v4float = OpTypePointer Output %v4float
533 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
534 %_ptr_Input_v4float = OpTypePointer Input %v4float
535 )";
536 
537   const std::string before =
538       R"(%main = OpFunction %void None %5
539 %17 = OpLabel
540 OpSelectionMerge %18 None
541 OpBranchConditional %false %19 %20
542 %19 = OpLabel
543 OpBranch %18
544 %20 = OpLabel
545 OpBranch %18
546 %18 = OpLabel
547 %21 = OpPhi %v4float %12 %19 %14 %20
548 OpStore %gl_FragColor %21
549 OpReturn
550 OpFunctionEnd
551 )";
552 
553   const std::string after =
554       R"(%main = OpFunction %void None %5
555 %17 = OpLabel
556 OpBranch %20
557 %20 = OpLabel
558 OpBranch %18
559 %18 = OpLabel
560 OpStore %gl_FragColor %14
561 OpReturn
562 OpFunctionEnd
563 )";
564 
565   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
566                                             true, true);
567 }
568 
TEST_F(DeadBranchElimTest,CompoundIfThenElseFalse)569 TEST_F(DeadBranchElimTest, CompoundIfThenElseFalse) {
570   // #version 140
571   //
572   // layout(std140) uniform U_t
573   // {
574   //     bool g_B ;
575   // } ;
576   //
577   // void main()
578   // {
579   //     vec4 v;
580   //     if (false) {
581   //       if (g_B)
582   //         v = vec4(0.0,0.0,0.0,0.0);
583   //       else
584   //         v = vec4(1.0,1.0,1.0,1.0);
585   //     } else {
586   //       if (g_B)
587   //         v = vec4(1.0,1.0,1.0,1.0);
588   //       else
589   //         v = vec4(0.0,0.0,0.0,0.0);
590   //     }
591   //     gl_FragColor = v;
592   // }
593 
594   const std::string predefs =
595       R"(OpCapability Shader
596 %1 = OpExtInstImport "GLSL.std.450"
597 OpMemoryModel Logical GLSL450
598 OpEntryPoint Fragment %main "main" %gl_FragColor
599 OpExecutionMode %main OriginUpperLeft
600 OpSource GLSL 140
601 OpName %main "main"
602 OpName %U_t "U_t"
603 OpMemberName %U_t 0 "g_B"
604 OpName %_ ""
605 OpName %v "v"
606 OpName %gl_FragColor "gl_FragColor"
607 OpMemberDecorate %U_t 0 Offset 0
608 OpDecorate %U_t Block
609 OpDecorate %_ DescriptorSet 0
610 %void = OpTypeVoid
611 %8 = OpTypeFunction %void
612 %bool = OpTypeBool
613 %false = OpConstantFalse %bool
614 %uint = OpTypeInt 32 0
615 %U_t = OpTypeStruct %uint
616 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
617 %_ = OpVariable %_ptr_Uniform_U_t Uniform
618 %int = OpTypeInt 32 1
619 %int_0 = OpConstant %int 0
620 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
621 %uint_0 = OpConstant %uint 0
622 %float = OpTypeFloat 32
623 %v4float = OpTypeVector %float 4
624 %_ptr_Function_v4float = OpTypePointer Function %v4float
625 %float_0 = OpConstant %float 0
626 %21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
627 %float_1 = OpConstant %float 1
628 %23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
629 %_ptr_Output_v4float = OpTypePointer Output %v4float
630 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
631 )";
632 
633   const std::string before =
634       R"(%main = OpFunction %void None %8
635 %25 = OpLabel
636 %v = OpVariable %_ptr_Function_v4float Function
637 OpSelectionMerge %26 None
638 OpBranchConditional %false %27 %28
639 %27 = OpLabel
640 %29 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
641 %30 = OpLoad %uint %29
642 %31 = OpINotEqual %bool %30 %uint_0
643 OpSelectionMerge %32 None
644 OpBranchConditional %31 %33 %34
645 %33 = OpLabel
646 OpStore %v %21
647 OpBranch %32
648 %34 = OpLabel
649 OpStore %v %23
650 OpBranch %32
651 %32 = OpLabel
652 OpBranch %26
653 %28 = OpLabel
654 %35 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
655 %36 = OpLoad %uint %35
656 %37 = OpINotEqual %bool %36 %uint_0
657 OpSelectionMerge %38 None
658 OpBranchConditional %37 %39 %40
659 %39 = OpLabel
660 OpStore %v %23
661 OpBranch %38
662 %40 = OpLabel
663 OpStore %v %21
664 OpBranch %38
665 %38 = OpLabel
666 OpBranch %26
667 %26 = OpLabel
668 %41 = OpLoad %v4float %v
669 OpStore %gl_FragColor %41
670 OpReturn
671 OpFunctionEnd
672 )";
673 
674   const std::string after =
675       R"(%main = OpFunction %void None %8
676 %25 = OpLabel
677 %v = OpVariable %_ptr_Function_v4float Function
678 OpBranch %28
679 %28 = OpLabel
680 %35 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
681 %36 = OpLoad %uint %35
682 %37 = OpINotEqual %bool %36 %uint_0
683 OpSelectionMerge %38 None
684 OpBranchConditional %37 %39 %40
685 %40 = OpLabel
686 OpStore %v %21
687 OpBranch %38
688 %39 = OpLabel
689 OpStore %v %23
690 OpBranch %38
691 %38 = OpLabel
692 OpBranch %26
693 %26 = OpLabel
694 %41 = OpLoad %v4float %v
695 OpStore %gl_FragColor %41
696 OpReturn
697 OpFunctionEnd
698 )";
699 
700   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
701                                             true, true);
702 }
703 
TEST_F(DeadBranchElimTest,PreventOrphanMerge)704 TEST_F(DeadBranchElimTest, PreventOrphanMerge) {
705   const std::string predefs =
706       R"(OpCapability Shader
707 %1 = OpExtInstImport "GLSL.std.450"
708 OpMemoryModel Logical GLSL450
709 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
710 OpExecutionMode %main OriginUpperLeft
711 OpSource GLSL 140
712 OpName %main "main"
713 OpName %v "v"
714 OpName %BaseColor "BaseColor"
715 OpName %gl_FragColor "gl_FragColor"
716 %void = OpTypeVoid
717 %7 = OpTypeFunction %void
718 %float = OpTypeFloat 32
719 %v4float = OpTypeVector %float 4
720 %_ptr_Function_v4float = OpTypePointer Function %v4float
721 %_ptr_Input_v4float = OpTypePointer Input %v4float
722 %BaseColor = OpVariable %_ptr_Input_v4float Input
723 %bool = OpTypeBool
724 %true = OpConstantTrue %bool
725 %float_0_5 = OpConstant %float 0.5
726 %_ptr_Output_v4float = OpTypePointer Output %v4float
727 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
728 )";
729 
730   const std::string before =
731       R"(%main = OpFunction %void None %7
732 %16 = OpLabel
733 %v = OpVariable %_ptr_Function_v4float Function
734 %17 = OpLoad %v4float %BaseColor
735 OpStore %v %17
736 OpSelectionMerge %18 None
737 OpBranchConditional %true %19 %20
738 %19 = OpLabel
739 OpKill
740 %20 = OpLabel
741 %21 = OpLoad %v4float %v
742 %22 = OpVectorTimesScalar %v4float %21 %float_0_5
743 OpStore %v %22
744 OpBranch %18
745 %18 = OpLabel
746 %23 = OpLoad %v4float %v
747 OpStore %gl_FragColor %23
748 OpReturn
749 OpFunctionEnd
750 )";
751 
752   const std::string after =
753       R"(%main = OpFunction %void None %7
754 %16 = OpLabel
755 %v = OpVariable %_ptr_Function_v4float Function
756 %17 = OpLoad %v4float %BaseColor
757 OpStore %v %17
758 OpBranch %19
759 %19 = OpLabel
760 OpKill
761 OpFunctionEnd
762 )";
763 
764   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
765                                             true, true);
766 }
767 
TEST_F(DeadBranchElimTest,HandleOrphanMerge)768 TEST_F(DeadBranchElimTest, HandleOrphanMerge) {
769   const std::string predefs =
770       R"(OpCapability Shader
771 %1 = OpExtInstImport "GLSL.std.450"
772 OpMemoryModel Logical GLSL450
773 OpEntryPoint Fragment %main "main" %gl_FragColor
774 OpExecutionMode %main OriginUpperLeft
775 OpSource GLSL 140
776 OpName %main "main"
777 OpName %foo_ "foo("
778 OpName %gl_FragColor "gl_FragColor"
779 OpDecorate %gl_FragColor Location 0
780 %void = OpTypeVoid
781 %6 = OpTypeFunction %void
782 %float = OpTypeFloat 32
783 %v4float = OpTypeVector %float 4
784 %9 = OpTypeFunction %v4float
785 %bool = OpTypeBool
786 %true = OpConstantTrue %bool
787 %float_0 = OpConstant %float 0
788 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
789 %float_1 = OpConstant %float 1
790 %15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
791 %_ptr_Output_v4float = OpTypePointer Output %v4float
792 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
793 %main = OpFunction %void None %6
794 %17 = OpLabel
795 %18 = OpFunctionCall %v4float %foo_
796 OpStore %gl_FragColor %18
797 OpReturn
798 OpFunctionEnd
799 )";
800 
801   const std::string before =
802       R"(%foo_ = OpFunction %v4float None %9
803 %19 = OpLabel
804 OpSelectionMerge %20 None
805 OpBranchConditional %true %21 %22
806 %21 = OpLabel
807 OpReturnValue %13
808 %22 = OpLabel
809 OpReturnValue %15
810 %20 = OpLabel
811 %23 = OpUndef %v4float
812 OpReturnValue %23
813 OpFunctionEnd
814 )";
815 
816   const std::string after =
817       R"(%foo_ = OpFunction %v4float None %9
818 %19 = OpLabel
819 OpBranch %21
820 %21 = OpLabel
821 OpReturnValue %13
822 OpFunctionEnd
823 )";
824 
825   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
826                                             true, true);
827 }
828 
TEST_F(DeadBranchElimTest,KeepContinueTargetWhenKillAfterMerge)829 TEST_F(DeadBranchElimTest, KeepContinueTargetWhenKillAfterMerge) {
830   // #version 450
831   // void main() {
832   //   bool c;
833   //   bool d;
834   //   while(c) {
835   //     if(d) {
836   //      continue;
837   //     }
838   //     if(false) {
839   //      continue;
840   //     }
841   //     discard;
842   //   }
843   // }
844 
845   const std::string predefs =
846       R"(OpCapability Shader
847 %1 = OpExtInstImport "GLSL.std.450"
848 OpMemoryModel Logical GLSL450
849 OpEntryPoint Fragment %main "main"
850 OpExecutionMode %main OriginUpperLeft
851 OpSource GLSL 450
852 OpName %main "main"
853 OpName %c "c"
854 OpName %d "d"
855 %void = OpTypeVoid
856 %6 = OpTypeFunction %void
857 %bool = OpTypeBool
858 %_ptr_Function_bool = OpTypePointer Function %bool
859 %false = OpConstantFalse %bool
860 )";
861 
862   const std::string before =
863       R"(%main = OpFunction %void None %6
864 %10 = OpLabel
865 %c = OpVariable %_ptr_Function_bool Function
866 %d = OpVariable %_ptr_Function_bool Function
867 OpBranch %11
868 %11 = OpLabel
869 OpLoopMerge %12 %13 None
870 OpBranch %14
871 %14 = OpLabel
872 %15 = OpLoad %bool %c
873 OpBranchConditional %15 %16 %12
874 %16 = OpLabel
875 %17 = OpLoad %bool %d
876 OpSelectionMerge %18 None
877 OpBranchConditional %17 %19 %18
878 %19 = OpLabel
879 OpBranch %13
880 %18 = OpLabel
881 OpSelectionMerge %20 None
882 OpBranchConditional %false %21 %20
883 %21 = OpLabel
884 OpBranch %13
885 %20 = OpLabel
886 OpKill
887 %13 = OpLabel
888 OpBranch %11
889 %12 = OpLabel
890 OpReturn
891 OpFunctionEnd
892 )";
893 
894   const std::string after =
895       R"(%main = OpFunction %void None %6
896 %10 = OpLabel
897 %c = OpVariable %_ptr_Function_bool Function
898 %d = OpVariable %_ptr_Function_bool Function
899 OpBranch %11
900 %11 = OpLabel
901 OpLoopMerge %12 %13 None
902 OpBranch %14
903 %14 = OpLabel
904 %15 = OpLoad %bool %c
905 OpBranchConditional %15 %16 %12
906 %16 = OpLabel
907 %17 = OpLoad %bool %d
908 OpSelectionMerge %18 None
909 OpBranchConditional %17 %19 %18
910 %19 = OpLabel
911 OpBranch %13
912 %18 = OpLabel
913 OpBranch %20
914 %20 = OpLabel
915 OpKill
916 %13 = OpLabel
917 OpBranch %11
918 %12 = OpLabel
919 OpReturn
920 OpFunctionEnd
921 )";
922 
923   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
924                                             true, true);
925 }
926 
TEST_F(DeadBranchElimTest,DecorateDeleted)927 TEST_F(DeadBranchElimTest, DecorateDeleted) {
928   // Note: SPIR-V hand-edited to add decoration
929   // #version 140
930   //
931   // in vec4 BaseColor;
932   //
933   // void main()
934   // {
935   //     vec4 v = BaseColor;
936   //     if (false)
937   //       v = v * vec4(0.5,0.5,0.5,0.5);
938   //     gl_FragColor = v;
939   // }
940 
941   const std::string predefs_before =
942       R"(OpCapability Shader
943 %1 = OpExtInstImport "GLSL.std.450"
944 OpMemoryModel Logical GLSL450
945 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
946 OpExecutionMode %main OriginUpperLeft
947 OpSource GLSL 140
948 OpName %main "main"
949 OpName %v "v"
950 OpName %BaseColor "BaseColor"
951 OpName %gl_FragColor "gl_FragColor"
952 OpDecorate %22 RelaxedPrecision
953 %void = OpTypeVoid
954 %7 = OpTypeFunction %void
955 %float = OpTypeFloat 32
956 %v4float = OpTypeVector %float 4
957 %_ptr_Function_v4float = OpTypePointer Function %v4float
958 %_ptr_Input_v4float = OpTypePointer Input %v4float
959 %BaseColor = OpVariable %_ptr_Input_v4float Input
960 %bool = OpTypeBool
961 %false = OpConstantFalse %bool
962 %float_0_5 = OpConstant %float 0.5
963 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
964 %_ptr_Output_v4float = OpTypePointer Output %v4float
965 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
966 )";
967 
968   const std::string predefs_after =
969       R"(OpCapability Shader
970 %1 = OpExtInstImport "GLSL.std.450"
971 OpMemoryModel Logical GLSL450
972 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
973 OpExecutionMode %main OriginUpperLeft
974 OpSource GLSL 140
975 OpName %main "main"
976 OpName %v "v"
977 OpName %BaseColor "BaseColor"
978 OpName %gl_FragColor "gl_FragColor"
979 %void = OpTypeVoid
980 %8 = OpTypeFunction %void
981 %float = OpTypeFloat 32
982 %v4float = OpTypeVector %float 4
983 %_ptr_Function_v4float = OpTypePointer Function %v4float
984 %_ptr_Input_v4float = OpTypePointer Input %v4float
985 %BaseColor = OpVariable %_ptr_Input_v4float Input
986 %bool = OpTypeBool
987 %false = OpConstantFalse %bool
988 %float_0_5 = OpConstant %float 0.5
989 %16 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
990 %_ptr_Output_v4float = OpTypePointer Output %v4float
991 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
992 )";
993 
994   const std::string before =
995       R"(%main = OpFunction %void None %7
996 %17 = OpLabel
997 %v = OpVariable %_ptr_Function_v4float Function
998 %18 = OpLoad %v4float %BaseColor
999 OpStore %v %18
1000 OpSelectionMerge %19 None
1001 OpBranchConditional %false %20 %19
1002 %20 = OpLabel
1003 %21 = OpLoad %v4float %v
1004 %22 = OpFMul %v4float %21 %15
1005 OpStore %v %22
1006 OpBranch %19
1007 %19 = OpLabel
1008 %23 = OpLoad %v4float %v
1009 OpStore %gl_FragColor %23
1010 OpReturn
1011 OpFunctionEnd
1012 )";
1013 
1014   const std::string after =
1015       R"(%main = OpFunction %void None %8
1016 %18 = OpLabel
1017 %v = OpVariable %_ptr_Function_v4float Function
1018 %19 = OpLoad %v4float %BaseColor
1019 OpStore %v %19
1020 OpBranch %20
1021 %20 = OpLabel
1022 %23 = OpLoad %v4float %v
1023 OpStore %gl_FragColor %23
1024 OpReturn
1025 OpFunctionEnd
1026 )";
1027 
1028   SinglePassRunAndCheck<DeadBranchElimPass>(predefs_before + before,
1029                                             predefs_after + after, true, true);
1030 }
1031 
TEST_F(DeadBranchElimTest,LoopInDeadBranch)1032 TEST_F(DeadBranchElimTest, LoopInDeadBranch) {
1033   // #version 450
1034   //
1035   // layout(location = 0) in vec4 BaseColor;
1036   // layout(location = 0) out vec4 OutColor;
1037   //
1038   // void main()
1039   // {
1040   //     vec4 v = BaseColor;
1041   //     if (false)
1042   //       for (int i=0; i<3; i++)
1043   //         v = v * 0.5;
1044   //     OutColor = v;
1045   // }
1046 
1047   const std::string predefs =
1048       R"(OpCapability Shader
1049 %1 = OpExtInstImport "GLSL.std.450"
1050 OpMemoryModel Logical GLSL450
1051 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1052 OpExecutionMode %main OriginUpperLeft
1053 OpSource GLSL 450
1054 OpName %main "main"
1055 OpName %v "v"
1056 OpName %BaseColor "BaseColor"
1057 OpName %i "i"
1058 OpName %OutColor "OutColor"
1059 OpDecorate %BaseColor Location 0
1060 OpDecorate %OutColor Location 0
1061 %void = OpTypeVoid
1062 %8 = OpTypeFunction %void
1063 %float = OpTypeFloat 32
1064 %v4float = OpTypeVector %float 4
1065 %_ptr_Function_v4float = OpTypePointer Function %v4float
1066 %_ptr_Input_v4float = OpTypePointer Input %v4float
1067 %BaseColor = OpVariable %_ptr_Input_v4float Input
1068 %bool = OpTypeBool
1069 %false = OpConstantFalse %bool
1070 %int = OpTypeInt 32 1
1071 %_ptr_Function_int = OpTypePointer Function %int
1072 %int_0 = OpConstant %int 0
1073 %int_3 = OpConstant %int 3
1074 %float_0_5 = OpConstant %float 0.5
1075 %int_1 = OpConstant %int 1
1076 %_ptr_Output_v4float = OpTypePointer Output %v4float
1077 %OutColor = OpVariable %_ptr_Output_v4float Output
1078 )";
1079 
1080   const std::string before =
1081       R"(%main = OpFunction %void None %8
1082 %22 = OpLabel
1083 %v = OpVariable %_ptr_Function_v4float Function
1084 %i = OpVariable %_ptr_Function_int Function
1085 %23 = OpLoad %v4float %BaseColor
1086 OpStore %v %23
1087 OpSelectionMerge %24 None
1088 OpBranchConditional %false %25 %24
1089 %25 = OpLabel
1090 OpStore %i %int_0
1091 OpBranch %26
1092 %26 = OpLabel
1093 OpLoopMerge %27 %28 None
1094 OpBranch %29
1095 %29 = OpLabel
1096 %30 = OpLoad %int %i
1097 %31 = OpSLessThan %bool %30 %int_3
1098 OpBranchConditional %31 %32 %27
1099 %32 = OpLabel
1100 %33 = OpLoad %v4float %v
1101 %34 = OpVectorTimesScalar %v4float %33 %float_0_5
1102 OpStore %v %34
1103 OpBranch %28
1104 %28 = OpLabel
1105 %35 = OpLoad %int %i
1106 %36 = OpIAdd %int %35 %int_1
1107 OpStore %i %36
1108 OpBranch %26
1109 %27 = OpLabel
1110 OpBranch %24
1111 %24 = OpLabel
1112 %37 = OpLoad %v4float %v
1113 OpStore %OutColor %37
1114 OpReturn
1115 OpFunctionEnd
1116 )";
1117 
1118   const std::string after =
1119       R"(%main = OpFunction %void None %8
1120 %22 = OpLabel
1121 %v = OpVariable %_ptr_Function_v4float Function
1122 %i = OpVariable %_ptr_Function_int Function
1123 %23 = OpLoad %v4float %BaseColor
1124 OpStore %v %23
1125 OpBranch %24
1126 %24 = OpLabel
1127 %37 = OpLoad %v4float %v
1128 OpStore %OutColor %37
1129 OpReturn
1130 OpFunctionEnd
1131 )";
1132 
1133   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
1134                                             true, true);
1135 }
1136 
TEST_F(DeadBranchElimTest,SwitchLiveCase)1137 TEST_F(DeadBranchElimTest, SwitchLiveCase) {
1138   // #version 450
1139   //
1140   // layout (location=0) in vec4 BaseColor;
1141   // layout (location=0) out vec4 OutColor;
1142   //
1143   // void main()
1144   // {
1145   //     switch (1) {
1146   //       case 0:
1147   //         OutColor = vec4(0.0,0.0,0.0,0.0);
1148   //         break;
1149   //       case 1:
1150   //         OutColor = vec4(0.125,0.125,0.125,0.125);
1151   //         break;
1152   //       case 2:
1153   //         OutColor = vec4(0.25,0.25,0.25,0.25);
1154   //         break;
1155   //       default:
1156   //         OutColor = vec4(1.0,1.0,1.0,1.0);
1157   //     }
1158   // }
1159 
1160   const std::string predefs =
1161       R"(OpCapability Shader
1162 %1 = OpExtInstImport "GLSL.std.450"
1163 OpMemoryModel Logical GLSL450
1164 OpEntryPoint Fragment %main "main" %OutColor %BaseColor
1165 OpExecutionMode %main OriginUpperLeft
1166 OpSource GLSL 450
1167 OpName %main "main"
1168 OpName %OutColor "OutColor"
1169 OpName %BaseColor "BaseColor"
1170 OpDecorate %OutColor Location 0
1171 OpDecorate %BaseColor Location 0
1172 %void = OpTypeVoid
1173 %6 = OpTypeFunction %void
1174 %int = OpTypeInt 32 1
1175 %int_1 = OpConstant %int 1
1176 %float = OpTypeFloat 32
1177 %v4float = OpTypeVector %float 4
1178 %_ptr_Output_v4float = OpTypePointer Output %v4float
1179 %OutColor = OpVariable %_ptr_Output_v4float Output
1180 %float_0 = OpConstant %float 0
1181 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1182 %float_0_125 = OpConstant %float 0.125
1183 %15 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
1184 %float_0_25 = OpConstant %float 0.25
1185 %17 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
1186 %float_1 = OpConstant %float 1
1187 %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1188 %_ptr_Input_v4float = OpTypePointer Input %v4float
1189 %BaseColor = OpVariable %_ptr_Input_v4float Input
1190 )";
1191 
1192   const std::string before =
1193       R"(%main = OpFunction %void None %6
1194 %21 = OpLabel
1195 OpSelectionMerge %22 None
1196 OpSwitch %int_1 %23 0 %24 1 %25 2 %26
1197 %23 = OpLabel
1198 OpStore %OutColor %19
1199 OpBranch %22
1200 %24 = OpLabel
1201 OpStore %OutColor %13
1202 OpBranch %22
1203 %25 = OpLabel
1204 OpStore %OutColor %15
1205 OpBranch %22
1206 %26 = OpLabel
1207 OpStore %OutColor %17
1208 OpBranch %22
1209 %22 = OpLabel
1210 OpReturn
1211 OpFunctionEnd
1212 )";
1213 
1214   const std::string after =
1215       R"(%main = OpFunction %void None %6
1216 %21 = OpLabel
1217 OpBranch %25
1218 %25 = OpLabel
1219 OpStore %OutColor %15
1220 OpBranch %22
1221 %22 = OpLabel
1222 OpReturn
1223 OpFunctionEnd
1224 )";
1225 
1226   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
1227                                             true, true);
1228 }
1229 
TEST_F(DeadBranchElimTest,SwitchLiveDefault)1230 TEST_F(DeadBranchElimTest, SwitchLiveDefault) {
1231   // #version 450
1232   //
1233   // layout (location=0) in vec4 BaseColor;
1234   // layout (location=0) out vec4 OutColor;
1235   //
1236   // void main()
1237   // {
1238   //     switch (7) {
1239   //       case 0:
1240   //         OutColor = vec4(0.0,0.0,0.0,0.0);
1241   //         break;
1242   //       case 1:
1243   //         OutColor = vec4(0.125,0.125,0.125,0.125);
1244   //         break;
1245   //       case 2:
1246   //         OutColor = vec4(0.25,0.25,0.25,0.25);
1247   //         break;
1248   //       default:
1249   //         OutColor = vec4(1.0,1.0,1.0,1.0);
1250   //     }
1251   // }
1252 
1253   const std::string predefs =
1254       R"(OpCapability Shader
1255 %1 = OpExtInstImport "GLSL.std.450"
1256 OpMemoryModel Logical GLSL450
1257 OpEntryPoint Fragment %main "main" %OutColor %BaseColor
1258 OpExecutionMode %main OriginUpperLeft
1259 OpSource GLSL 450
1260 OpName %main "main"
1261 OpName %OutColor "OutColor"
1262 OpName %BaseColor "BaseColor"
1263 OpDecorate %OutColor Location 0
1264 OpDecorate %BaseColor Location 0
1265 %void = OpTypeVoid
1266 %6 = OpTypeFunction %void
1267 %int = OpTypeInt 32 1
1268 %int_7 = OpConstant %int 7
1269 %float = OpTypeFloat 32
1270 %v4float = OpTypeVector %float 4
1271 %_ptr_Output_v4float = OpTypePointer Output %v4float
1272 %OutColor = OpVariable %_ptr_Output_v4float Output
1273 %float_0 = OpConstant %float 0
1274 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1275 %float_0_125 = OpConstant %float 0.125
1276 %15 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
1277 %float_0_25 = OpConstant %float 0.25
1278 %17 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
1279 %float_1 = OpConstant %float 1
1280 %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1281 %_ptr_Input_v4float = OpTypePointer Input %v4float
1282 %BaseColor = OpVariable %_ptr_Input_v4float Input
1283 )";
1284 
1285   const std::string before =
1286       R"(%main = OpFunction %void None %6
1287 %21 = OpLabel
1288 OpSelectionMerge %22 None
1289 OpSwitch %int_7 %23 0 %24 1 %25 2 %26
1290 %23 = OpLabel
1291 OpStore %OutColor %19
1292 OpBranch %22
1293 %24 = OpLabel
1294 OpStore %OutColor %13
1295 OpBranch %22
1296 %25 = OpLabel
1297 OpStore %OutColor %15
1298 OpBranch %22
1299 %26 = OpLabel
1300 OpStore %OutColor %17
1301 OpBranch %22
1302 %22 = OpLabel
1303 OpReturn
1304 OpFunctionEnd
1305 )";
1306 
1307   const std::string after =
1308       R"(%main = OpFunction %void None %6
1309 %21 = OpLabel
1310 OpBranch %23
1311 %23 = OpLabel
1312 OpStore %OutColor %19
1313 OpBranch %22
1314 %22 = OpLabel
1315 OpReturn
1316 OpFunctionEnd
1317 )";
1318 
1319   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
1320                                             true, true);
1321 }
1322 
TEST_F(DeadBranchElimTest,SwitchLiveCaseBreakFromLoop)1323 TEST_F(DeadBranchElimTest, SwitchLiveCaseBreakFromLoop) {
1324   // This sample does not directly translate to GLSL/HLSL as
1325   // direct breaks from a loop cannot be made from a switch.
1326   // This construct is currently formed by inlining a function
1327   // containing early returns from the cases of a switch. The
1328   // function is wrapped in a one-trip loop and returns are
1329   // translated to branches to the loop's merge block.
1330 
1331   const std::string predefs =
1332       R"(OpCapability Shader
1333 %1 = OpExtInstImport "GLSL.std.450"
1334 OpMemoryModel Logical GLSL450
1335 OpEntryPoint Fragment %main "main" %OutColor %BaseColor
1336 OpExecutionMode %main OriginUpperLeft
1337 OpSource GLSL 450
1338 OpName %main "main"
1339 OpName %oc "oc"
1340 OpName %OutColor "OutColor"
1341 OpName %BaseColor "BaseColor"
1342 OpDecorate %OutColor Location 0
1343 OpDecorate %BaseColor Location 0
1344 %void = OpTypeVoid
1345 %7 = OpTypeFunction %void
1346 %bool = OpTypeBool
1347 %true = OpConstantTrue %bool
1348 %false = OpConstantFalse %bool
1349 %int = OpTypeInt 32 1
1350 %int_1 = OpConstant %int 1
1351 %float = OpTypeFloat 32
1352 %v4float = OpTypeVector %float 4
1353 %_ptr_Function_v4float = OpTypePointer Function %v4float
1354 %float_0 = OpConstant %float 0
1355 %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1356 %float_0_125 = OpConstant %float 0.125
1357 %19 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
1358 %float_0_25 = OpConstant %float 0.25
1359 %21 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
1360 %float_1 = OpConstant %float 1
1361 %23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1362 %_ptr_Output_v4float = OpTypePointer Output %v4float
1363 %OutColor = OpVariable %_ptr_Output_v4float Output
1364 %_ptr_Input_v4float = OpTypePointer Input %v4float
1365 %BaseColor = OpVariable %_ptr_Input_v4float Input
1366 )";
1367 
1368   const std::string before =
1369       R"(%main = OpFunction %void None %7
1370 %26 = OpLabel
1371 %oc = OpVariable %_ptr_Function_v4float Function
1372 OpBranch %27
1373 %27 = OpLabel
1374 OpLoopMerge %28 %29 None
1375 OpBranch %30
1376 %30 = OpLabel
1377 OpSelectionMerge %31 None
1378 OpSwitch %int_1 %31 0 %32 1 %33 2 %34
1379 %32 = OpLabel
1380 OpStore %oc %17
1381 OpBranch %28
1382 %33 = OpLabel
1383 OpStore %oc %19
1384 OpBranch %28
1385 %34 = OpLabel
1386 OpStore %oc %21
1387 OpBranch %28
1388 %31 = OpLabel
1389 OpStore %oc %23
1390 OpBranch %28
1391 %29 = OpLabel
1392 OpBranchConditional %false %27 %28
1393 %28 = OpLabel
1394 %35 = OpLoad %v4float %oc
1395 OpStore %OutColor %35
1396 OpReturn
1397 OpFunctionEnd
1398 )";
1399 
1400   const std::string after =
1401       R"(%main = OpFunction %void None %7
1402 %26 = OpLabel
1403 %oc = OpVariable %_ptr_Function_v4float Function
1404 OpBranch %27
1405 %27 = OpLabel
1406 OpLoopMerge %28 %29 None
1407 OpBranch %30
1408 %30 = OpLabel
1409 OpBranch %33
1410 %33 = OpLabel
1411 OpStore %oc %19
1412 OpBranch %28
1413 %29 = OpLabel
1414 OpBranch %27
1415 %28 = OpLabel
1416 %35 = OpLoad %v4float %oc
1417 OpStore %OutColor %35
1418 OpReturn
1419 OpFunctionEnd
1420 )";
1421 
1422   SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
1423                                             true, true);
1424 }
1425 
TEST_F(DeadBranchElimTest,LeaveContinueBackedge)1426 TEST_F(DeadBranchElimTest, LeaveContinueBackedge) {
1427   const std::string text = R"(
1428 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1429 ; CHECK: [[continue]] = OpLabel
1430 ; CHECK-NEXT: OpBranchConditional {{%\w+}} {{%\w+}} [[merge]]
1431 ; CHECK-NEXT: [[merge]] = OpLabel
1432 ; CHECK-NEXT: OpReturn
1433 OpCapability Kernel
1434 OpCapability Linkage
1435 OpMemoryModel Logical OpenCL
1436 %bool = OpTypeBool
1437 %false = OpConstantFalse %bool
1438 %void = OpTypeVoid
1439 %funcTy = OpTypeFunction %void
1440 %func = OpFunction %void None %funcTy
1441 %1 = OpLabel
1442 OpBranch %2
1443 %2 = OpLabel
1444 OpLoopMerge %3 %4 None
1445 OpBranch %4
1446 %4 = OpLabel
1447 ; Be careful we don't remove the backedge to %2 despite never taking it.
1448 OpBranchConditional %false %2 %3
1449 %3 = OpLabel
1450 OpReturn
1451 OpFunctionEnd
1452 )";
1453 
1454   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1455 }
1456 
TEST_F(DeadBranchElimTest,LeaveContinueBackedgeExtraBlock)1457 TEST_F(DeadBranchElimTest, LeaveContinueBackedgeExtraBlock) {
1458   const std::string text = R"(
1459 ; CHECK: OpBranch [[header:%\w+]]
1460 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1461 ; CHECK-NEXT: OpBranch [[continue]]
1462 ; CHECK-NEXT: [[continue]] = OpLabel
1463 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[extra:%\w+]] [[merge]]
1464 ; CHECK-NEXT: [[extra]] = OpLabel
1465 ; CHECK-NEXT: OpBranch [[header]]
1466 ; CHECK-NEXT: [[merge]] = OpLabel
1467 ; CHECK-NEXT: OpReturn
1468 OpCapability Kernel
1469 OpCapability Linkage
1470 OpMemoryModel Logical OpenCL
1471 %bool = OpTypeBool
1472 %false = OpConstantFalse %bool
1473 %void = OpTypeVoid
1474 %funcTy = OpTypeFunction %void
1475 %func = OpFunction %void None %funcTy
1476 %1 = OpLabel
1477 OpBranch %2
1478 %2 = OpLabel
1479 OpLoopMerge %3 %4 None
1480 OpBranch %4
1481 %4 = OpLabel
1482 ; Be careful we don't remove the backedge to %2 despite never taking it.
1483 OpBranchConditional %false %5 %3
1484 ; This block remains live despite being unreachable.
1485 %5 = OpLabel
1486 OpBranch %2
1487 %3 = OpLabel
1488 OpReturn
1489 OpFunctionEnd
1490 )";
1491 
1492   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1493 }
1494 
TEST_F(DeadBranchElimTest,RemovePhiWithUnreachableContinue)1495 TEST_F(DeadBranchElimTest, RemovePhiWithUnreachableContinue) {
1496   const std::string text = R"(
1497 ; CHECK: [[entry:%\w+]] = OpLabel
1498 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1499 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1500 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
1501 ; CHECK-NEXT: [[ret]] = OpLabel
1502 ; CHECK-NEXT: OpReturn
1503 ; CHECK: [[continue]] = OpLabel
1504 ; CHECK-NEXT: OpBranch [[header]]
1505 ; CHECK: [[merge]] = OpLabel
1506 ; CHECK-NEXT: OpUnreachable
1507 OpCapability Kernel
1508 OpCapability Linkage
1509 OpMemoryModel Logical OpenCL
1510 OpName %func "func"
1511 OpDecorate %func LinkageAttributes "func" Export
1512 %bool = OpTypeBool
1513 %false = OpConstantFalse %bool
1514 %true = OpConstantTrue %bool
1515 %void = OpTypeVoid
1516 %funcTy = OpTypeFunction %void
1517 %func = OpFunction %void None %funcTy
1518 %1 = OpLabel
1519 OpBranch %2
1520 %2 = OpLabel
1521 %phi = OpPhi %bool %false %1 %true %continue
1522 OpLoopMerge %merge %continue None
1523 OpBranch %3
1524 %3 = OpLabel
1525 OpReturn
1526 %continue = OpLabel
1527 OpBranch %2
1528 %merge = OpLabel
1529 OpReturn
1530 OpFunctionEnd
1531 )";
1532 
1533   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1534 }
1535 
TEST_F(DeadBranchElimTest,UnreachableLoopMergeAndContinueTargets)1536 TEST_F(DeadBranchElimTest, UnreachableLoopMergeAndContinueTargets) {
1537   const std::string text = R"(
1538 ; CHECK: [[undef:%\w+]] = OpUndef %bool
1539 ; CHECK: OpSelectionMerge [[header:%\w+]]
1540 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_lab:%\w+]] [[else_lab:%\w+]]
1541 ; CHECK: OpPhi %bool %false [[if_lab]] %false [[else_lab]] [[undef]] [[continue:%\w+]]
1542 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
1543 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
1544 ; CHECK-NEXT: [[ret]] = OpLabel
1545 ; CHECK-NEXT: OpReturn
1546 ; CHECK: [[continue]] = OpLabel
1547 ; CHECK-NEXT: OpBranch [[header]]
1548 ; CHECK: [[merge]] = OpLabel
1549 ; CHECK-NEXT: OpUnreachable
1550 OpCapability Kernel
1551 OpCapability Linkage
1552 OpMemoryModel Logical OpenCL
1553 OpName %func "func"
1554 OpDecorate %func LinkageAttributes "func" Export
1555 %bool = OpTypeBool
1556 %false = OpConstantFalse %bool
1557 %true = OpConstantTrue %bool
1558 %void = OpTypeVoid
1559 %funcTy = OpTypeFunction %void
1560 %func = OpFunction %void None %funcTy
1561 %1 = OpLabel
1562 %c = OpUndef %bool
1563 OpSelectionMerge %2 None
1564 OpBranchConditional %c %if %else
1565 %if = OpLabel
1566 OpBranch %2
1567 %else = OpLabel
1568 OpBranch %2
1569 %2 = OpLabel
1570 %phi = OpPhi %bool %false %if %false %else %true %continue
1571 OpLoopMerge %merge %continue None
1572 OpBranch %3
1573 %3 = OpLabel
1574 OpReturn
1575 %continue = OpLabel
1576 OpBranch %2
1577 %merge = OpLabel
1578 OpReturn
1579 OpFunctionEnd
1580 )";
1581 
1582   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1583 }
TEST_F(DeadBranchElimTest,EarlyReconvergence)1584 TEST_F(DeadBranchElimTest, EarlyReconvergence) {
1585   const std::string text = R"(
1586 ; CHECK-NOT: OpBranchConditional
1587 ; CHECK: [[logical:%\w+]] = OpLogicalOr
1588 ; CHECK-NOT: OpPhi
1589 ; CHECK: OpLogicalAnd {{%\w+}} {{%\w+}} [[logical]]
1590 OpCapability Shader
1591 OpMemoryModel Logical GLSL450
1592 OpEntryPoint Fragment %func "func"
1593 OpExecutionMode %func OriginUpperLeft
1594 %void = OpTypeVoid
1595 %bool = OpTypeBool
1596 %false = OpConstantFalse %bool
1597 %true = OpConstantTrue %bool
1598 %func_ty = OpTypeFunction %void
1599 %func = OpFunction %void None %func_ty
1600 %1 = OpLabel
1601 OpSelectionMerge %2 None
1602 OpBranchConditional %false %3 %4
1603 %3 = OpLabel
1604 %12 = OpLogicalNot %bool %true
1605 OpBranch %2
1606 %4 = OpLabel
1607 OpSelectionMerge %14 None
1608 OpBranchConditional %false %5 %6
1609 %5 = OpLabel
1610 %10 = OpLogicalAnd %bool %true %false
1611 OpBranch %7
1612 %6 = OpLabel
1613 %11 = OpLogicalOr %bool %true %false
1614 OpBranch %7
1615 %7 = OpLabel
1616 ; This phi is in a block preceding the merge %14!
1617 %8 = OpPhi %bool %10 %5 %11 %6
1618 OpBranch %14
1619 %14 = OpLabel
1620 OpBranch %2
1621 %2 = OpLabel
1622 %9 = OpPhi %bool %12 %3 %8 %14
1623 %13 = OpLogicalAnd %bool %true %9
1624 OpReturn
1625 OpFunctionEnd
1626 )";
1627 
1628   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1629 }
1630 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksFloating)1631 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloating) {
1632   const std::string text = R"(
1633 ; CHECK: OpFunction
1634 ; CHECK-NEXT: OpLabel
1635 ; CHECK-NEXT: OpReturn
1636 ; CHECK-NEXT: OpFunctionEnd
1637 OpCapability Kernel
1638 OpCapability Linkage
1639 OpMemoryModel Logical OpenCL
1640 OpName %func "func"
1641 OpDecorate %func LinkageAttributes "func" Export
1642 %void = OpTypeVoid
1643 %1 = OpTypeFunction %void
1644 %func = OpFunction %void None %1
1645 %2 = OpLabel
1646 OpReturn
1647 %3 = OpLabel
1648 OpReturn
1649 OpFunctionEnd
1650 )";
1651 
1652   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1653 }
1654 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksFloatingJoin)1655 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloatingJoin) {
1656   const std::string text = R"(
1657 ; CHECK: OpFunction
1658 ; CHECK-NEXT: OpFunctionParameter
1659 ; CHECK-NEXT: OpLabel
1660 ; CHECK-NEXT: OpReturn
1661 ; CHECK-NEXT: OpFunctionEnd
1662 OpCapability Kernel
1663 OpCapability Linkage
1664 OpMemoryModel Logical OpenCL
1665 OpName %func "func"
1666 OpDecorate %func LinkageAttributes "func" Export
1667 %void = OpTypeVoid
1668 %bool = OpTypeBool
1669 %false = OpConstantFalse %bool
1670 %true = OpConstantTrue %bool
1671 %1 = OpTypeFunction %void %bool
1672 %func = OpFunction %void None %1
1673 %bool_param = OpFunctionParameter %bool
1674 %2 = OpLabel
1675 OpReturn
1676 %3 = OpLabel
1677 OpSelectionMerge %6 None
1678 OpBranchConditional %bool_param %4 %5
1679 %4 = OpLabel
1680 OpBranch %6
1681 %5 = OpLabel
1682 OpBranch %6
1683 %6 = OpLabel
1684 %7 = OpPhi %bool %true %4 %false %6
1685 OpReturn
1686 OpFunctionEnd
1687 )";
1688 
1689   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1690 }
1691 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksDeadPhi)1692 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksDeadPhi) {
1693   const std::string text = R"(
1694 ; CHECK: OpFunction
1695 ; CHECK-NEXT: OpFunctionParameter
1696 ; CHECK-NEXT: OpLabel
1697 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1698 ; CHECK-NEXT: [[label]] = OpLabel
1699 ; CHECK-NEXT: OpLogicalNot %bool %true
1700 ; CHECK-NEXT: OpReturn
1701 ; CHECK-NEXT: OpFunctionEnd
1702 OpCapability Kernel
1703 OpCapability Linkage
1704 OpMemoryModel Logical OpenCL
1705 OpName %func "func"
1706 OpDecorate %func LinkageAttributes "func" Export
1707 %void = OpTypeVoid
1708 %bool = OpTypeBool
1709 %false = OpConstantFalse %bool
1710 %true = OpConstantTrue %bool
1711 %1 = OpTypeFunction %void %bool
1712 %func = OpFunction %void None %1
1713 %bool_param = OpFunctionParameter %bool
1714 %2 = OpLabel
1715 OpBranch %3
1716 %4 = OpLabel
1717 OpBranch %3
1718 %3 = OpLabel
1719 %5 = OpPhi %bool %true %2 %false %4
1720 %6 = OpLogicalNot %bool %5
1721 OpReturn
1722 OpFunctionEnd
1723 )";
1724 
1725   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1726 }
1727 
TEST_F(DeadBranchElimTest,RemoveUnreachableBlocksPartiallyDeadPhi)1728 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksPartiallyDeadPhi) {
1729   const std::string text = R"(
1730 ; CHECK: OpFunction
1731 ; CHECK-NEXT: [[param:%\w+]] = OpFunctionParameter
1732 ; CHECK-NEXT: OpLabel
1733 ; CHECK-NEXT: OpBranchConditional [[param]] [[merge:%\w+]] [[br:%\w+]]
1734 ; CHECK-NEXT: [[merge]] = OpLabel
1735 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %bool %true %2 %false [[br]]
1736 ; CHECK-NEXT: OpLogicalNot %bool [[phi]]
1737 ; CHECK-NEXT: OpReturn
1738 ; CHECK-NEXT: [[br]] = OpLabel
1739 ; CHECK-NEXT: OpBranch [[merge]]
1740 ; CHECK-NEXT: OpFunctionEnd
1741 OpCapability Kernel
1742 OpCapability Linkage
1743 OpMemoryModel Logical OpenCL
1744 OpName %func "func"
1745 OpDecorate %func LinkageAttributes "func" Export
1746 %void = OpTypeVoid
1747 %bool = OpTypeBool
1748 %false = OpConstantFalse %bool
1749 %true = OpConstantTrue %bool
1750 %1 = OpTypeFunction %void %bool
1751 %func = OpFunction %void None %1
1752 %bool_param = OpFunctionParameter %bool
1753 %2 = OpLabel
1754 OpBranchConditional %bool_param %3 %7
1755 %7 = OpLabel
1756 OpBranch %3
1757 %4 = OpLabel
1758 OpBranch %3
1759 %3 = OpLabel
1760 %5 = OpPhi %bool %true %2 %false %7 %false %4
1761 %6 = OpLogicalNot %bool %5
1762 OpReturn
1763 OpFunctionEnd
1764 )";
1765 
1766   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1767   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1768 }
1769 
TEST_F(DeadBranchElimTest,LiveHeaderDeadPhi)1770 TEST_F(DeadBranchElimTest, LiveHeaderDeadPhi) {
1771   const std::string text = R"(
1772 ; CHECK: OpLabel
1773 ; CHECK-NOT: OpBranchConditional
1774 ; CHECK-NOT: OpPhi
1775 ; CHECK: OpLogicalNot %bool %false
1776 OpCapability Kernel
1777 OpCapability Linkage
1778 OpMemoryModel Logical OpenCL
1779 OpName %func "func"
1780 OpDecorate %func LinkageAttributes "func" Export
1781 %void = OpTypeVoid
1782 %bool = OpTypeBool
1783 %true = OpConstantTrue %bool
1784 %false = OpConstantFalse %bool
1785 %func_ty = OpTypeFunction %void
1786 %func = OpFunction %void None %func_ty
1787 %1 = OpLabel
1788 OpSelectionMerge %3 None
1789 OpBranchConditional %true %2 %3
1790 %2 = OpLabel
1791 OpBranch %3
1792 %3 = OpLabel
1793 %5 = OpPhi %bool %true %3 %false %2
1794 %6 = OpLogicalNot %bool %5
1795 OpReturn
1796 OpFunctionEnd
1797 )";
1798 
1799   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1800 }
1801 
TEST_F(DeadBranchElimTest,ExtraBackedgeBlocksLive)1802 TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksLive) {
1803   const std::string text = R"(
1804 ; CHECK: [[entry:%\w+]] = OpLabel
1805 ; CHECK-NOT: OpSelectionMerge
1806 ; CHECK: OpBranch [[header:%\w+]]
1807 ; CHECK-NEXT: [[header]] = OpLabel
1808 ; CHECK-NEXT: OpPhi %bool %true [[entry]] %false [[backedge:%\w+]]
1809 ; CHECK-NEXT: OpLoopMerge
1810 OpCapability Kernel
1811 OpCapability Linkage
1812 OpMemoryModel Logical OpenCL
1813 OpName %func "func"
1814 OpDecorate %func LinkageAttributes "func" Export
1815 %void = OpTypeVoid
1816 %bool = OpTypeBool
1817 %true = OpConstantTrue %bool
1818 %false = OpConstantFalse %bool
1819 %func_ty = OpTypeFunction %void %bool
1820 %func = OpFunction %void None %func_ty
1821 %param = OpFunctionParameter %bool
1822 %entry = OpLabel
1823 OpSelectionMerge %if_merge None
1824 ; This dead branch is included to ensure the pass does work.
1825 OpBranchConditional %false %if_merge %loop_header
1826 %loop_header = OpLabel
1827 ; Both incoming edges are live, so the phi should be untouched.
1828 %phi = OpPhi %bool %true %entry %false %backedge
1829 OpLoopMerge %loop_merge %continue None
1830 OpBranchConditional %param %loop_merge %continue
1831 %continue = OpLabel
1832 OpBranch %backedge
1833 %backedge = OpLabel
1834 OpBranch %loop_header
1835 %loop_merge = OpLabel
1836 OpBranch %if_merge
1837 %if_merge = OpLabel
1838 OpReturn
1839 OpFunctionEnd
1840 )";
1841 
1842   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1843 }
1844 
TEST_F(DeadBranchElimTest,ExtraBackedgeBlocksUnreachable)1845 TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksUnreachable) {
1846   const std::string text = R"(
1847 ; CHECK: [[entry:%\w+]] = OpLabel
1848 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1849 ; CHECK-NEXT: [[header]] = OpLabel
1850 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1851 ; CHECK-NEXT: OpBranch [[merge]]
1852 ; CHECK-NEXT: [[merge]] = OpLabel
1853 ; CHECK-NEXT: OpReturn
1854 ; CHECK-NEXT: [[continue]] = OpLabel
1855 ; CHECK-NEXT: OpBranch [[header]]
1856 OpCapability Kernel
1857 OpCapability Linkage
1858 OpMemoryModel Logical OpenCL
1859 OpName %func "func"
1860 OpDecorate %func LinkageAttributes "func" Export
1861 %void = OpTypeVoid
1862 %bool = OpTypeBool
1863 %true = OpConstantTrue %bool
1864 %false = OpConstantFalse %bool
1865 %func_ty = OpTypeFunction %void %bool
1866 %func = OpFunction %void None %func_ty
1867 %param = OpFunctionParameter %bool
1868 %entry = OpLabel
1869 OpBranch %loop_header
1870 %loop_header = OpLabel
1871 ; Since the continue is unreachable, %backedge will be removed. The phi will
1872 ; instead require an edge from %continue.
1873 %phi = OpPhi %bool %true %entry %false %backedge
1874 OpLoopMerge %merge %continue None
1875 OpBranch %merge
1876 %continue = OpLabel
1877 OpBranch %backedge
1878 %backedge = OpLabel
1879 OpBranch %loop_header
1880 %merge = OpLabel
1881 OpReturn
1882 OpFunctionEnd
1883 )";
1884 
1885   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1886 }
1887 
TEST_F(DeadBranchElimTest,NoUnnecessaryChanges)1888 TEST_F(DeadBranchElimTest, NoUnnecessaryChanges) {
1889   const std::string text = R"(
1890 OpCapability Shader
1891 OpMemoryModel Logical GLSL450
1892 OpEntryPoint Fragment %func "func"
1893 %void = OpTypeVoid
1894 %bool = OpTypeBool
1895 %true = OpConstantTrue %bool
1896 %undef = OpUndef %bool
1897 %functy = OpTypeFunction %void
1898 %func = OpFunction %void None %functy
1899 %1 = OpLabel
1900 OpBranch %2
1901 %2 = OpLabel
1902 OpLoopMerge %4 %5 None
1903 OpBranch %6
1904 %6 = OpLabel
1905 OpReturn
1906 %5 = OpLabel
1907 OpBranch %2
1908 %4 = OpLabel
1909 OpUnreachable
1910 OpFunctionEnd
1911 )";
1912 
1913   auto result = SinglePassRunToBinary<DeadBranchElimPass>(text, true);
1914   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
1915 }
1916 
TEST_F(DeadBranchElimTest,ExtraBackedgePartiallyDead)1917 TEST_F(DeadBranchElimTest, ExtraBackedgePartiallyDead) {
1918   const std::string text = R"(
1919 ; CHECK: OpLabel
1920 ; CHECK: [[header:%\w+]] = OpLabel
1921 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1922 ; CHECK: [[merge]] = OpLabel
1923 ; CHECK: [[continue]] = OpLabel
1924 ; CHECK: OpBranch [[extra:%\w+]]
1925 ; CHECK: [[extra]] = OpLabel
1926 ; CHECK-NOT: OpSelectionMerge
1927 ; CHECK-NEXT: OpBranch [[else:%\w+]]
1928 ; CHECK-NEXT: [[else]] = OpLabel
1929 ; CHECK-NEXT: OpLogicalOr
1930 ; CHECK-NEXT: OpBranch [[backedge:%\w+]]
1931 ; CHECK-NEXT: [[backedge:%\w+]] = OpLabel
1932 ; CHECK-NEXT: OpBranch [[header]]
1933 OpCapability Kernel
1934 OpCapability Linkage
1935 OpMemoryModel Logical OpenCL
1936 OpName %func "func"
1937 OpDecorate %func LinkageAttributes "func" Export
1938 %void = OpTypeVoid
1939 %bool = OpTypeBool
1940 %true = OpConstantTrue %bool
1941 %false = OpConstantFalse %bool
1942 %func_ty = OpTypeFunction %void %bool
1943 %func = OpFunction %void None %func_ty
1944 %param = OpFunctionParameter %bool
1945 %entry = OpLabel
1946 OpBranch %loop_header
1947 %loop_header = OpLabel
1948 OpLoopMerge %loop_merge %continue None
1949 OpBranchConditional %param %loop_merge %continue
1950 %continue = OpLabel
1951 OpBranch %extra
1952 %extra = OpLabel
1953 OpSelectionMerge %backedge None
1954 OpBranchConditional %false %then %else
1955 %then = OpLabel
1956 %and = OpLogicalAnd %bool %true %false
1957 OpBranch %backedge
1958 %else = OpLabel
1959 %or = OpLogicalOr %bool %true %false
1960 OpBranch %backedge
1961 %backedge = OpLabel
1962 OpBranch %loop_header
1963 %loop_merge = OpLabel
1964 OpReturn
1965 OpFunctionEnd
1966 )";
1967 
1968   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
1969 }
1970 
TEST_F(DeadBranchElimTest,UnreachableContinuePhiInMerge)1971 TEST_F(DeadBranchElimTest, UnreachableContinuePhiInMerge) {
1972   const std::string text = R"(
1973 ; CHECK: [[entry:%\w+]] = OpLabel
1974 ; CHECK-NEXT: OpBranch [[header:%\w+]]
1975 ; CHECK-NEXT: [[header]] = OpLabel
1976 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
1977 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1978 ; CHECK-NEXT: [[label]] = OpLabel
1979 ; CHECK-NEXT: [[fadd:%\w+]] = OpFAdd
1980 ; CHECK-NEXT: OpBranch [[label:%\w+]]
1981 ; CHECK-NEXT: [[label]] = OpLabel
1982 ; CHECK-NEXT: OpBranch [[merge]]
1983 ; CHECK-NEXT: [[continue]] = OpLabel
1984 ; CHECK-NEXT: OpBranch [[header]]
1985 ; CHECK-NEXT: [[merge]] = OpLabel
1986 ; CHECK-NEXT: OpStore {{%\w+}} [[fadd]]
1987                OpCapability Shader
1988           %1 = OpExtInstImport "GLSL.std.450"
1989                OpMemoryModel Logical GLSL450
1990                OpEntryPoint Fragment %main "main" %o
1991                OpExecutionMode %main OriginUpperLeft
1992                OpSource GLSL 430
1993                OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
1994                OpSourceExtension "GL_GOOGLE_include_directive"
1995                OpName %main "main"
1996                OpName %o "o"
1997                OpName %S "S"
1998                OpMemberName %S 0 "a"
1999                OpName %U_t "U_t"
2000                OpMemberName %U_t 0 "g_F"
2001                OpMemberName %U_t 1 "g_F2"
2002                OpDecorate %o Location 0
2003                OpMemberDecorate %S 0 Offset 0
2004                OpMemberDecorate %U_t 0 Volatile
2005                OpMemberDecorate %U_t 0 Offset 0
2006                OpMemberDecorate %U_t 1 Offset 4
2007                OpDecorate %U_t BufferBlock
2008        %void = OpTypeVoid
2009           %7 = OpTypeFunction %void
2010       %float = OpTypeFloat 32
2011 %_ptr_Function_float = OpTypePointer Function %float
2012     %float_0 = OpConstant %float 0
2013         %int = OpTypeInt 32 1
2014 %_ptr_Function_int = OpTypePointer Function %int
2015       %int_0 = OpConstant %int 0
2016      %int_10 = OpConstant %int 10
2017        %bool = OpTypeBool
2018        %true = OpConstantTrue %bool
2019     %float_1 = OpConstant %float 1
2020     %float_5 = OpConstant %float 5
2021       %int_1 = OpConstant %int 1
2022 %_ptr_Output_float = OpTypePointer Output %float
2023           %o = OpVariable %_ptr_Output_float Output
2024           %S = OpTypeStruct %float
2025         %U_t = OpTypeStruct %S %S
2026 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
2027        %main = OpFunction %void None %7
2028          %22 = OpLabel
2029                OpBranch %23
2030          %23 = OpLabel
2031          %24 = OpPhi %float %float_0 %22 %25 %26
2032          %27 = OpPhi %int %int_0 %22 %28 %26
2033                OpLoopMerge %29 %26 None
2034                OpBranch %40
2035          %40 = OpLabel
2036          %25 = OpFAdd %float %24 %float_1
2037                OpSelectionMerge %30 None
2038                OpBranchConditional %true %31 %30
2039          %31 = OpLabel
2040                OpBranch %29
2041          %30 = OpLabel
2042                OpBranch %26
2043          %26 = OpLabel
2044          %28 = OpIAdd %int %27 %int_1
2045          %32 = OpSLessThan %bool %27 %int_10
2046 ; continue block branches to the header or another none dead block.
2047                OpBranchConditional %32 %23 %29
2048          %29 = OpLabel
2049          %33 = OpPhi %float %24 %26 %25 %31
2050                OpStore %o %33
2051                OpReturn
2052                OpFunctionEnd
2053 )";
2054 
2055   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2056 }
2057 
TEST_F(DeadBranchElimTest,NonStructuredIf)2058 TEST_F(DeadBranchElimTest, NonStructuredIf) {
2059   const std::string text = R"(
2060 ; CHECK-NOT: OpBranchConditional
2061 OpCapability Kernel
2062 OpCapability Linkage
2063 OpMemoryModel Logical OpenCL
2064 OpDecorate %func LinkageAttributes "func" Export
2065 %void = OpTypeVoid
2066 %bool = OpTypeBool
2067 %true = OpConstantTrue %bool
2068 %functy = OpTypeFunction %void
2069 %func = OpFunction %void None %functy
2070 %entry = OpLabel
2071 OpBranchConditional %true %then %else
2072 %then = OpLabel
2073 OpBranch %final
2074 %else = OpLabel
2075 OpBranch %final
2076 %final = OpLabel
2077 OpReturn
2078 OpFunctionEnd
2079 )";
2080 
2081   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2082 }
2083 
TEST_F(DeadBranchElimTest,ReorderBlocks)2084 TEST_F(DeadBranchElimTest, ReorderBlocks) {
2085   const std::string text = R"(
2086 ; CHECK: OpLabel
2087 ; CHECK: OpBranch [[label:%\w+]]
2088 ; CHECK: [[label:%\w+]] = OpLabel
2089 ; CHECK-NEXT: OpLogicalNot
2090 ; CHECK-NEXT: OpBranch [[label:%\w+]]
2091 ; CHECK: [[label]] = OpLabel
2092 ; CHECK-NEXT: OpReturn
2093 OpCapability Shader
2094 OpMemoryModel Logical GLSL450
2095 OpEntryPoint Fragment %func "func"
2096 OpExecutionMode %func OriginUpperLeft
2097 %void = OpTypeVoid
2098 %bool = OpTypeBool
2099 %true = OpConstantTrue %bool
2100 %func_ty = OpTypeFunction %void
2101 %func = OpFunction %void None %func_ty
2102 %1 = OpLabel
2103 OpSelectionMerge %3 None
2104 OpBranchConditional %true %2 %3
2105 %3 = OpLabel
2106 OpReturn
2107 %2 = OpLabel
2108 %not = OpLogicalNot %bool %true
2109 OpBranch %3
2110 OpFunctionEnd
2111 )";
2112 
2113   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2114 }
2115 
TEST_F(DeadBranchElimTest,ReorderBlocksMultiple)2116 TEST_F(DeadBranchElimTest, ReorderBlocksMultiple) {
2117   // Checks are not important. The validation post optimization is the
2118   // important part.
2119   const std::string text = R"(
2120 ; CHECK: OpLabel
2121 OpCapability Shader
2122 OpMemoryModel Logical GLSL450
2123 OpEntryPoint Fragment %func "func"
2124 OpExecutionMode %func OriginUpperLeft
2125 %void = OpTypeVoid
2126 %bool = OpTypeBool
2127 %true = OpConstantTrue %bool
2128 %func_ty = OpTypeFunction %void
2129 %func = OpFunction %void None %func_ty
2130 %1 = OpLabel
2131 OpSelectionMerge %3 None
2132 OpBranchConditional %true %2 %3
2133 %3 = OpLabel
2134 OpReturn
2135 %2 = OpLabel
2136 OpBranch %4
2137 %4 = OpLabel
2138 OpBranch %3
2139 OpFunctionEnd
2140 )";
2141 
2142   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2143 }
2144 
TEST_F(DeadBranchElimTest,ReorderBlocksMultiple2)2145 TEST_F(DeadBranchElimTest, ReorderBlocksMultiple2) {
2146   // Checks are not important. The validation post optimization is the
2147   // important part.
2148   const std::string text = R"(
2149 ; CHECK: OpLabel
2150 OpCapability Shader
2151 OpMemoryModel Logical GLSL450
2152 OpEntryPoint Fragment %func "func"
2153 OpExecutionMode %func OriginUpperLeft
2154 %void = OpTypeVoid
2155 %bool = OpTypeBool
2156 %true = OpConstantTrue %bool
2157 %func_ty = OpTypeFunction %void
2158 %func = OpFunction %void None %func_ty
2159 %1 = OpLabel
2160 OpSelectionMerge %3 None
2161 OpBranchConditional %true %2 %3
2162 %3 = OpLabel
2163 OpBranch %5
2164 %5 = OpLabel
2165 OpReturn
2166 %2 = OpLabel
2167 OpBranch %4
2168 %4 = OpLabel
2169 OpBranch %3
2170 OpFunctionEnd
2171 )";
2172 
2173   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
2174 }
2175 
TEST_F(DeadBranchElimTest,SelectionMergeWithEarlyExit1)2176 TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit1) {
2177   // Checks  that if a selection merge construct contains a conditional branch
2178   // to the merge node, then the OpSelectionMerge instruction is positioned
2179   // correctly.
2180   const std::string predefs = R"(
2181 OpCapability Shader
2182 %1 = OpExtInstImport "GLSL.std.450"
2183 OpMemoryModel Logical GLSL450
2184 OpEntryPoint Fragment %main "main"
2185 OpExecutionMode %main OriginUpperLeft
2186 OpSource GLSL 140
2187 %void = OpTypeVoid
2188 %func_type = OpTypeFunction %void
2189 %bool = OpTypeBool
2190 %true = OpConstantTrue %bool
2191 %undef_bool = OpUndef %bool
2192 )";
2193 
2194   const std::string body =
2195       R"(
2196 ; CHECK: OpFunction
2197 ; CHECK-NEXT: OpLabel
2198 ; CHECK-NEXT: OpBranch [[taken_branch:%\w+]]
2199 ; CHECK-NEXT: [[taken_branch]] = OpLabel
2200 ; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
2201 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[merge]] {{%\w+}}
2202 %main = OpFunction %void None %func_type
2203 %entry_bb = OpLabel
2204 OpSelectionMerge %outer_merge None
2205 OpBranchConditional %true %bb1 %bb3
2206 %bb1 = OpLabel
2207 OpBranchConditional %undef_bool %outer_merge %bb2
2208 %bb2 = OpLabel
2209 OpBranch %outer_merge
2210 %bb3 = OpLabel
2211 OpBranch %outer_merge
2212 %outer_merge = OpLabel
2213 OpReturn
2214 OpFunctionEnd
2215 )";
2216 
2217   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2218 }
2219 
TEST_F(DeadBranchElimTest,SelectionMergeWithEarlyExit2)2220 TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit2) {
2221   // Checks  that if a selection merge construct contains a conditional branch
2222   // to the merge node, then the OpSelectionMerge instruction is positioned
2223   // correctly.
2224   const std::string predefs = R"(
2225 OpCapability Shader
2226 %1 = OpExtInstImport "GLSL.std.450"
2227 OpMemoryModel Logical GLSL450
2228 OpEntryPoint Fragment %main "main"
2229 OpExecutionMode %main OriginUpperLeft
2230 OpSource GLSL 140
2231 %void = OpTypeVoid
2232 %func_type = OpTypeFunction %void
2233 %bool = OpTypeBool
2234 %true = OpConstantTrue %bool
2235 %undef_bool = OpUndef %bool
2236 )";
2237 
2238   const std::string body =
2239       R"(
2240 ; CHECK: OpFunction
2241 ; CHECK-NEXT: OpLabel
2242 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2243 ; CHECK-NEXT: [[bb1]] = OpLabel
2244 ; CHECK-NEXT: OpSelectionMerge [[inner_merge:%\w+]]
2245 ; CHECK: [[inner_merge]] = OpLabel
2246 ; CHECK-NEXT: OpSelectionMerge [[outer_merge:%\w+]]
2247 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[outer_merge]:%\w+]] {{%\w+}}
2248 ; CHECK: [[outer_merge]] = OpLabel
2249 ; CHECK-NEXT: OpReturn
2250 %main = OpFunction %void None %func_type
2251 %entry_bb = OpLabel
2252 OpSelectionMerge %outer_merge None
2253 OpBranchConditional %true %bb1 %bb5
2254 %bb1 = OpLabel
2255 OpSelectionMerge %inner_merge None
2256 OpBranchConditional %undef_bool %bb2 %bb3
2257 %bb2 = OpLabel
2258 OpBranch %inner_merge
2259 %bb3 = OpLabel
2260 OpBranch %inner_merge
2261 %inner_merge = OpLabel
2262 OpBranchConditional %undef_bool %outer_merge %bb4
2263 %bb4 = OpLabel
2264 OpBranch %outer_merge
2265 %bb5 = OpLabel
2266 OpBranch %outer_merge
2267 %outer_merge = OpLabel
2268 OpReturn
2269 OpFunctionEnd
2270 )";
2271 
2272   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2273 }
2274 
TEST_F(DeadBranchElimTest,SelectionMergeWithConditionalExit)2275 TEST_F(DeadBranchElimTest, SelectionMergeWithConditionalExit) {
2276   // Checks that if a selection merge construct contains a conditional branch
2277   // to the merge node, then we keep the OpSelectionMerge on that branch.
2278   const std::string predefs = R"(
2279 OpCapability Shader
2280 %1 = OpExtInstImport "GLSL.std.450"
2281 OpMemoryModel Logical GLSL450
2282 OpEntryPoint Fragment %main "main"
2283 OpExecutionMode %main OriginUpperLeft
2284 OpSource GLSL 140
2285 %void = OpTypeVoid
2286 %func_type = OpTypeFunction %void
2287 %bool = OpTypeBool
2288 %true = OpConstantTrue %bool
2289 %uint = OpTypeInt 32 0
2290 %undef_int = OpUndef %uint
2291 )";
2292 
2293   const std::string body =
2294       R"(
2295 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2296 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2297 ; CHECK: [[bb1]] = OpLabel
2298 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2299 ; CHECK: [[bb2]] = OpLabel
2300 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2301 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 1 [[bb3:%\w+]]
2302 ; CHECK: [[bb3]] = OpLabel
2303 ; CHECK-NEXT: OpBranch [[sel_merge]]
2304 ; CHECK: [[sel_merge]] = OpLabel
2305 ; CHECK-NEXT: OpBranch [[loop_merge]]
2306 ; CHECK: [[loop_merge]] = OpLabel
2307 ; CHECK-NEXT: OpReturn
2308 %main = OpFunction %void None %func_type
2309 %entry_bb = OpLabel
2310 OpBranch %loop_header
2311 %loop_header = OpLabel
2312 OpLoopMerge %loop_merge %cont None
2313 OpBranch %bb1
2314 %bb1 = OpLabel
2315 OpSelectionMerge %sel_merge None
2316 OpBranchConditional %true %bb2 %bb4
2317 %bb2 = OpLabel
2318 OpSwitch %undef_int %sel_merge 1 %bb3
2319 %bb3 = OpLabel
2320 OpBranch %sel_merge
2321 %bb4 = OpLabel
2322 OpBranch %sel_merge
2323 %sel_merge = OpLabel
2324 OpBranch %loop_merge
2325 %cont = OpLabel
2326 OpBranch %loop_header
2327 %loop_merge = OpLabel
2328 OpReturn
2329 OpFunctionEnd
2330 )";
2331 
2332   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2333 }
2334 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop)2335 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop) {
2336   // Checks  that if a selection merge construct contains a conditional branch
2337   // to a loop surrounding the selection merge, then we do not keep the
2338   // OpSelectionMerge instruction.
2339   const std::string predefs = R"(
2340 OpCapability Shader
2341 %1 = OpExtInstImport "GLSL.std.450"
2342 OpMemoryModel Logical GLSL450
2343 OpEntryPoint Fragment %main "main"
2344 OpExecutionMode %main OriginUpperLeft
2345 OpSource GLSL 140
2346 %void = OpTypeVoid
2347 %func_type = OpTypeFunction %void
2348 %bool = OpTypeBool
2349 %true = OpConstantTrue %bool
2350 %undef_bool = OpUndef %bool
2351 )";
2352 
2353   const std::string body =
2354       R"(
2355 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2356 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2357 ; CHECK: [[bb1]] = OpLabel
2358 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2359 ; CHECK: [[bb2]] = OpLabel
2360 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_merge]]
2361 ; CHECK: [[bb3]] = OpLabel
2362 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2363 ; CHECK: [[sel_merge]] = OpLabel
2364 ; CHECK-NEXT: OpBranch [[loop_merge]]
2365 ; CHECK: [[loop_merge]] = OpLabel
2366 ; CHECK-NEXT: OpReturn
2367 %main = OpFunction %void None %func_type
2368 %entry_bb = OpLabel
2369 OpBranch %loop_header
2370 %loop_header = OpLabel
2371 OpLoopMerge %loop_merge %cont None
2372 OpBranch %bb1
2373 %bb1 = OpLabel
2374 OpSelectionMerge %sel_merge None
2375 OpBranchConditional %true %bb2 %bb4
2376 %bb2 = OpLabel
2377 OpBranchConditional %undef_bool %bb3 %loop_merge
2378 %bb3 = OpLabel
2379 OpBranch %sel_merge
2380 %bb4 = OpLabel
2381 OpBranch %sel_merge
2382 %sel_merge = OpLabel
2383 OpBranch %loop_merge
2384 %cont = OpLabel
2385 OpBranch %loop_header
2386 %loop_merge = OpLabel
2387 OpReturn
2388 OpFunctionEnd
2389 )";
2390 
2391   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2392 }
2393 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue)2394 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue) {
2395   // Checks  that if a selection merge construct contains a conditional branch
2396   // to continue of a loop surrounding the selection merge, then we do not keep
2397   // the OpSelectionMerge instruction.
2398   const std::string predefs = R"(
2399 OpCapability Shader
2400 %1 = OpExtInstImport "GLSL.std.450"
2401 OpMemoryModel Logical GLSL450
2402 OpEntryPoint Fragment %main "main"
2403 OpExecutionMode %main OriginUpperLeft
2404 OpSource GLSL 140
2405 %void = OpTypeVoid
2406 %func_type = OpTypeFunction %void
2407 %bool = OpTypeBool
2408 %true = OpConstantTrue %bool
2409 %undef_bool = OpUndef %bool
2410 )";
2411 
2412   const std::string body =
2413       R"(;
2414 ; CHECK: OpLabel
2415 ; CHECK: [[loop_header:%\w+]] = OpLabel
2416 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2417 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2418 ; CHECK: [[bb1]] = OpLabel
2419 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2420 ; CHECK: [[bb2]] = OpLabel
2421 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]]
2422 ; CHECK: [[bb3]] = OpLabel
2423 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
2424 ; CHECK: [[sel_merge]] = OpLabel
2425 ; CHECK-NEXT: OpBranch [[loop_merge]]
2426 ; CHECK: [[loop_cont]] = OpLabel
2427 ; CHECK-NEXT: OpBranch [[loop_header]]
2428 ; CHECK: [[loop_merge]] = OpLabel
2429 ; CHECK-NEXT: OpReturn
2430 %main = OpFunction %void None %func_type
2431 %entry_bb = OpLabel
2432 OpBranch %loop_header
2433 %loop_header = OpLabel
2434 OpLoopMerge %loop_merge %cont None
2435 OpBranch %bb1
2436 %bb1 = OpLabel
2437 OpSelectionMerge %sel_merge None
2438 OpBranchConditional %true %bb2 %bb4
2439 %bb2 = OpLabel
2440 OpBranchConditional %undef_bool %bb3 %cont
2441 %bb3 = OpLabel
2442 OpBranch %sel_merge
2443 %bb4 = OpLabel
2444 OpBranch %sel_merge
2445 %sel_merge = OpLabel
2446 OpBranch %loop_merge
2447 %cont = OpLabel
2448 OpBranch %loop_header
2449 %loop_merge = OpLabel
2450 OpReturn
2451 OpFunctionEnd
2452 )";
2453 
2454   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2455 }
2456 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop2)2457 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop2) {
2458   // Same as |SelectionMergeWithExitToLoop|, except the switch goes to the loop
2459   // merge or the selection merge.  In this case, we do not need an
2460   // OpSelectionMerge either.
2461   const std::string predefs = R"(
2462 OpCapability Shader
2463 %1 = OpExtInstImport "GLSL.std.450"
2464 OpMemoryModel Logical GLSL450
2465 OpEntryPoint Fragment %main "main"
2466 OpExecutionMode %main OriginUpperLeft
2467 OpSource GLSL 140
2468 %void = OpTypeVoid
2469 %func_type = OpTypeFunction %void
2470 %bool = OpTypeBool
2471 %true = OpConstantTrue %bool
2472 %undef_bool = OpUndef %bool
2473 )";
2474 
2475   const std::string body =
2476       R"(
2477 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2478 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2479 ; CHECK: [[bb1]] = OpLabel
2480 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2481 ; CHECK: [[bb2]] = OpLabel
2482 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_merge]]
2483 ; CHECK: [[sel_merge]] = OpLabel
2484 ; CHECK-NEXT: OpBranch [[loop_merge]]
2485 ; CHECK: [[loop_merge]] = OpLabel
2486 ; CHECK-NEXT: OpReturn
2487 %main = OpFunction %void None %func_type
2488 %entry_bb = OpLabel
2489 OpBranch %loop_header
2490 %loop_header = OpLabel
2491 OpLoopMerge %loop_merge %cont None
2492 OpBranch %bb1
2493 %bb1 = OpLabel
2494 OpSelectionMerge %sel_merge None
2495 OpBranchConditional %true %bb2 %bb4
2496 %bb2 = OpLabel
2497 OpBranchConditional %undef_bool %sel_merge %loop_merge
2498 %bb4 = OpLabel
2499 OpBranch %sel_merge
2500 %sel_merge = OpLabel
2501 OpBranch %loop_merge
2502 %cont = OpLabel
2503 OpBranch %loop_header
2504 %loop_merge = OpLabel
2505 OpReturn
2506 OpFunctionEnd
2507 )";
2508 
2509   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2510 }
2511 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue2)2512 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue2) {
2513   // Same as |SelectionMergeWithExitToLoopContinue|, except the branch goes to
2514   // the loop continue or the selection merge.  In this case, we do not need an
2515   // OpSelectionMerge either.
2516   const std::string predefs = R"(
2517 OpCapability Shader
2518 %1 = OpExtInstImport "GLSL.std.450"
2519 OpMemoryModel Logical GLSL450
2520 OpEntryPoint Fragment %main "main"
2521 OpExecutionMode %main OriginUpperLeft
2522 OpSource GLSL 140
2523 %void = OpTypeVoid
2524 %func_type = OpTypeFunction %void
2525 %bool = OpTypeBool
2526 %true = OpConstantTrue %bool
2527 %undef_bool = OpUndef %bool
2528 )";
2529 
2530   const std::string body =
2531       R"(
2532 ; CHECK: OpLabel
2533 ; CHECK: [[loop_header:%\w+]] = OpLabel
2534 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2535 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2536 ; CHECK: [[bb1]] = OpLabel
2537 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2538 ; CHECK: [[bb2]] = OpLabel
2539 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_cont]]
2540 ; CHECK: [[sel_merge]] = OpLabel
2541 ; CHECK-NEXT: OpBranch [[loop_merge]]
2542 ; CHECK: [[loop_cont]] = OpLabel
2543 ; CHECK: OpBranch [[loop_header]]
2544 ; CHECK: [[loop_merge]] = OpLabel
2545 ; CHECK-NEXT: OpReturn
2546 %main = OpFunction %void None %func_type
2547 %entry_bb = OpLabel
2548 OpBranch %loop_header
2549 %loop_header = OpLabel
2550 OpLoopMerge %loop_merge %cont None
2551 OpBranch %bb1
2552 %bb1 = OpLabel
2553 OpSelectionMerge %sel_merge None
2554 OpBranchConditional %true %bb2 %bb4
2555 %bb2 = OpLabel
2556 OpBranchConditional %undef_bool %sel_merge %cont
2557 %bb4 = OpLabel
2558 OpBranch %sel_merge
2559 %sel_merge = OpLabel
2560 OpBranch %loop_merge
2561 %cont = OpLabel
2562 OpBranch %loop_header
2563 %loop_merge = OpLabel
2564 OpReturn
2565 OpFunctionEnd
2566 )";
2567 
2568   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2569 }
2570 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoop3)2571 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop3) {
2572   // Checks that if a selection merge construct contains a conditional branch
2573   // to the selection merge, and another block inside the selection merge,
2574   // then we must keep the OpSelectionMerge instruction on that branch.
2575   const std::string predefs = R"(
2576 OpCapability Shader
2577 %1 = OpExtInstImport "GLSL.std.450"
2578 OpMemoryModel Logical GLSL450
2579 OpEntryPoint Fragment %main "main"
2580 OpExecutionMode %main OriginUpperLeft
2581 OpSource GLSL 140
2582 %void = OpTypeVoid
2583 %func_type = OpTypeFunction %void
2584 %bool = OpTypeBool
2585 %true = OpConstantTrue %bool
2586 %uint = OpTypeInt 32 0
2587 %undef_int = OpUndef %uint
2588 %undef_bool = OpUndef %bool
2589 )";
2590 
2591   const std::string body =
2592       R"(
2593 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
2594 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2595 ; CHECK: [[bb1]] = OpLabel
2596 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2597 ; CHECK: [[bb2]] = OpLabel
2598 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2599 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge]] [[bb3:%\w+]]
2600 ; CHECK: [[bb3]] = OpLabel
2601 ; CHECK-NEXT: OpBranch [[sel_merge]]
2602 ; CHECK: [[sel_merge]] = OpLabel
2603 ; CHECK-NEXT: OpBranch [[loop_merge]]
2604 ; CHECK: [[loop_merge]] = OpLabel
2605 ; CHECK-NEXT: OpReturn
2606 %main = OpFunction %void None %func_type
2607 %entry_bb = OpLabel
2608 OpBranch %loop_header
2609 %loop_header = OpLabel
2610 OpLoopMerge %loop_merge %cont None
2611 OpBranch %bb1
2612 %bb1 = OpLabel
2613 OpSelectionMerge %sel_merge None
2614 OpBranchConditional %true %bb2 %bb4
2615 %bb2 = OpLabel
2616 ;OpSwitch %undef_int %sel_merge 0 %loop_merge 1 %bb3
2617 OpBranchConditional %undef_bool %sel_merge %bb3
2618 %bb3 = OpLabel
2619 OpBranch %sel_merge
2620 %bb4 = OpLabel
2621 OpBranch %sel_merge
2622 %sel_merge = OpLabel
2623 OpBranch %loop_merge
2624 %cont = OpLabel
2625 OpBranch %loop_header
2626 %loop_merge = OpLabel
2627 OpReturn
2628 OpFunctionEnd
2629 )";
2630 
2631   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2632 }
2633 
TEST_F(DeadBranchElimTest,SelectionMergeWithExitToLoopContinue3)2634 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue3) {
2635   // Checks that if a selection merge construct contains a conditional branch
2636   // the selection merge, and another block inside the selection merge, then we
2637   // must keep the OpSelectionMerge instruction on that branch.
2638   const std::string predefs = R"(
2639 OpCapability Shader
2640 %1 = OpExtInstImport "GLSL.std.450"
2641 OpMemoryModel Logical GLSL450
2642 OpEntryPoint Fragment %main "main"
2643 OpExecutionMode %main OriginUpperLeft
2644 OpSource GLSL 140
2645 %void = OpTypeVoid
2646 %func_type = OpTypeFunction %void
2647 %bool = OpTypeBool
2648 %true = OpConstantTrue %bool
2649 %uint = OpTypeInt 32 0
2650 %undef_int = OpUndef %uint
2651 %undef_bool = OpUndef %bool
2652 )";
2653 
2654   const std::string body =
2655       R"(
2656 ; CHECK: OpLabel
2657 ; CHECK: [[loop_header:%\w+]] = OpLabel
2658 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_continue:%\w+]]
2659 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2660 ; CHECK: [[bb1]] = OpLabel
2661 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2662 ; CHECK: [[bb2]] = OpLabel
2663 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
2664 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge]] [[bb3:%\w+]]
2665 ; CHECK: [[bb3]] = OpLabel
2666 ; CHECK-NEXT: OpBranch [[sel_merge]]
2667 ; CHECK: [[sel_merge]] = OpLabel
2668 ; CHECK-NEXT: OpBranch [[loop_merge]]
2669 ; CHECK: [[loop_continue]] = OpLabel
2670 ; CHECK-NEXT: OpBranch [[loop_header]]
2671 ; CHECK: [[loop_merge]] = OpLabel
2672 ; CHECK-NEXT: OpReturn
2673 %main = OpFunction %void None %func_type
2674 %entry_bb = OpLabel
2675 OpBranch %loop_header
2676 %loop_header = OpLabel
2677 OpLoopMerge %loop_merge %cont None
2678 OpBranch %bb1
2679 %bb1 = OpLabel
2680 OpSelectionMerge %sel_merge None
2681 OpBranchConditional %true %bb2 %bb4
2682 %bb2 = OpLabel
2683 OpBranchConditional %undef_bool %sel_merge %bb3
2684 %bb3 = OpLabel
2685 OpBranch %sel_merge
2686 %bb4 = OpLabel
2687 OpBranch %sel_merge
2688 %sel_merge = OpLabel
2689 OpBranch %loop_merge
2690 %cont = OpLabel
2691 OpBranch %loop_header
2692 %loop_merge = OpLabel
2693 OpReturn
2694 OpFunctionEnd
2695 )";
2696 
2697   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
2698 }
2699 
TEST_F(DeadBranchElimTest,SelectionMergeSameAsLoopContinue)2700 TEST_F(DeadBranchElimTest, SelectionMergeSameAsLoopContinue) {
2701   // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the
2702   // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|.
2703   // The OpSelectionMerge instruction is not needed in this case either.
2704   const std::string predefs = R"(
2705 OpCapability Shader
2706 %1 = OpExtInstImport "GLSL.std.450"
2707 OpMemoryModel Logical GLSL450
2708 OpEntryPoint Fragment %main "main"
2709 OpExecutionMode %main OriginUpperLeft
2710 OpSource GLSL 140
2711 %void = OpTypeVoid
2712 %func_type = OpTypeFunction %void
2713 %bool = OpTypeBool
2714 %true = OpConstantTrue %bool
2715 %uint = OpTypeInt 32 0
2716 %undef_bool = OpUndef %bool
2717 )";
2718 
2719   const std::string body =
2720       R"(
2721 ; CHECK: OpLabel
2722 ; CHECK: [[loop_header:%\w+]] = OpLabel
2723 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
2724 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
2725 ; CHECK: [[bb1]] = OpLabel
2726 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
2727 ; CHECK: [[bb2]] = OpLabel
2728 ; CHECK-NEXT: OpSelectionMerge [[loop_cont]]
2729 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]]
2730 ; CHECK: [[bb3]] = OpLabel
2731 ; CHECK-NEXT: OpBranch [[loop_cont]]
2732 ; CHECK: [[loop_cont]] = OpLabel
2733 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[loop_header]] [[loop_merge]]
2734 ; CHECK: [[loop_merge]] = OpLabel
2735 ; CHECK-NEXT: OpReturn
2736 %main = OpFunction %void None %func_type
2737 %entry_bb = OpLabel
2738 OpBranch %loop_header
2739 %loop_header = OpLabel
2740 OpLoopMerge %loop_merge %cont None
2741 OpBranch %bb1
2742 %bb1 = OpLabel
2743 OpSelectionMerge %cont None
2744 OpBranchConditional %true %bb2 %bb4
2745 %bb2 = OpLabel
2746 OpBranchConditional %undef_bool %bb3 %cont
2747 %bb3 = OpLabel
2748 OpBranch %cont
2749 %bb4 = OpLabel
2750 OpBranch %cont
2751 %cont = OpLabel
2752 OpBranchConditional %undef_bool %loop_header %loop_merge
2753 %loop_merge = OpLabel
2754 OpReturn
2755 OpFunctionEnd
2756 )";
2757 
2758   // The selection merge in the loop naming the continue target as merge is
2759   // invalid, but handled by this pass so validation is disabled.
2760   SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, false);
2761 }
2762 
TEST_F(DeadBranchElimTest,SelectionMergeWithNestedLoop)2763 TEST_F(DeadBranchElimTest, SelectionMergeWithNestedLoop) {
2764   const std::string body =
2765       R"(
2766 ; CHECK: OpSelectionMerge [[merge1:%\w+]]
2767 ; CHECK: [[merge1]] = OpLabel
2768 ; CHECK-NEXT: OpBranch [[preheader:%\w+]]
2769 ; CHECK: [[preheader]] = OpLabel
2770 ; CHECK-NOT: OpLabel
2771 ; CHECK: OpBranch [[header:%\w+]]
2772 ; CHECK: [[header]] = OpLabel
2773 ; CHECK-NOT: OpLabel
2774 ; CHECK: OpLoopMerge [[merge2:%\w+]]
2775 ; CHECK: [[merge2]] = OpLabel
2776 ; CHECK-NEXT: OpUnreachable
2777                  OpCapability Shader
2778             %1 = OpExtInstImport "GLSL.std.450"
2779                  OpMemoryModel Logical GLSL450
2780                  OpEntryPoint Fragment %main "main"
2781                  OpExecutionMode %main OriginUpperLeft
2782                  OpSource ESSL 310
2783                  OpName %main "main"
2784                  OpName %h "h"
2785                  OpName %i "i"
2786          %void = OpTypeVoid
2787             %3 = OpTypeFunction %void
2788          %bool = OpTypeBool
2789   %_ptr_Function_bool = OpTypePointer Function %bool
2790          %true = OpConstantTrue %bool
2791           %int = OpTypeInt 32 1
2792   %_ptr_Function_int = OpTypePointer Function %int
2793         %int_1 = OpConstant %int 1
2794         %int_0 = OpConstant %int 0
2795            %27 = OpUndef %bool
2796          %main = OpFunction %void None %3
2797             %5 = OpLabel
2798             %h = OpVariable %_ptr_Function_bool Function
2799             %i = OpVariable %_ptr_Function_int Function
2800                  OpSelectionMerge %11 None
2801                  OpBranchConditional %27 %10 %11
2802            %10 = OpLabel
2803                  OpBranch %11
2804            %11 = OpLabel
2805                  OpSelectionMerge %14 None
2806                  OpBranchConditional %true %13 %14
2807            %13 = OpLabel
2808                  OpStore %i %int_1
2809                  OpBranch %19
2810            %19 = OpLabel
2811                  OpLoopMerge %21 %22 None
2812                  OpBranch %23
2813            %23 = OpLabel
2814            %26 = OpSGreaterThan %bool %int_1 %int_0
2815                  OpBranchConditional %true %20 %21
2816            %20 = OpLabel
2817                  OpBranch %22
2818            %22 = OpLabel
2819                  OpBranch %19
2820            %21 = OpLabel
2821                  OpBranch %14
2822            %14 = OpLabel
2823                  OpReturn
2824                  OpFunctionEnd
2825 )";
2826 
2827   SinglePassRunAndMatch<DeadBranchElimPass>(body, true);
2828 }
2829 
TEST_F(DeadBranchElimTest,DontFoldBackedge)2830 TEST_F(DeadBranchElimTest, DontFoldBackedge) {
2831   const std::string body =
2832       R"(OpCapability Shader
2833 %1 = OpExtInstImport "GLSL.std.450"
2834 OpMemoryModel Logical GLSL450
2835 OpEntryPoint Fragment %2 "main"
2836 OpExecutionMode %2 OriginUpperLeft
2837 %void = OpTypeVoid
2838 %4 = OpTypeFunction %void
2839 %bool = OpTypeBool
2840 %false = OpConstantFalse %bool
2841 %2 = OpFunction %void None %4
2842 %7 = OpLabel
2843 OpBranch %8
2844 %8 = OpLabel
2845 OpLoopMerge %9 %10 None
2846 OpBranch %11
2847 %11 = OpLabel
2848 %12 = OpUndef %bool
2849 OpSelectionMerge %10 None
2850 OpBranchConditional %12 %13 %10
2851 %13 = OpLabel
2852 OpBranch %9
2853 %10 = OpLabel
2854 OpBranch %14
2855 %14 = OpLabel
2856 OpBranchConditional %false %8 %9
2857 %9 = OpLabel
2858 OpReturn
2859 OpFunctionEnd
2860 )";
2861 
2862   SinglePassRunAndCheck<DeadBranchElimPass>(body, body, true);
2863 }
2864 
TEST_F(DeadBranchElimTest,FoldBackedgeToHeader)2865 TEST_F(DeadBranchElimTest, FoldBackedgeToHeader) {
2866   const std::string body =
2867       R"(
2868 ; CHECK: OpLabel
2869 ; CHECK: [[header:%\w+]] = OpLabel
2870 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[cont:%\w+]]
2871 ; CHECK: [[cont]] = OpLabel
2872 ; This branch may not be in the continue block, but must come after it.
2873 ; CHECK: OpBranch [[header]]
2874 OpCapability Shader
2875 %1 = OpExtInstImport "GLSL.std.450"
2876 OpMemoryModel Logical GLSL450
2877 OpEntryPoint Fragment %2 "main"
2878 OpExecutionMode %2 OriginUpperLeft
2879 %void = OpTypeVoid
2880 %4 = OpTypeFunction %void
2881 %bool = OpTypeBool
2882 %true = OpConstantTrue %bool
2883 %2 = OpFunction %void None %4
2884 %7 = OpLabel
2885 OpBranch %8
2886 %8 = OpLabel
2887 OpLoopMerge %9 %10 None
2888 OpBranch %11
2889 %11 = OpLabel
2890 %12 = OpUndef %bool
2891 OpSelectionMerge %10 None
2892 OpBranchConditional %12 %13 %10
2893 %13 = OpLabel
2894 OpBranch %9
2895 %10 = OpLabel
2896 OpBranch %14
2897 %14 = OpLabel
2898 OpBranchConditional %true %8 %9
2899 %9 = OpLabel
2900 OpReturn
2901 OpFunctionEnd
2902 )";
2903 
2904   // The selection merge in the loop naming the continue target as merge is
2905   // invalid, but handled by this pass so validation is disabled.
2906   SinglePassRunAndMatch<DeadBranchElimPass>(body, false);
2907 }
2908 
TEST_F(DeadBranchElimTest,UnreachableMergeAndContinueSameBlock)2909 TEST_F(DeadBranchElimTest, UnreachableMergeAndContinueSameBlock) {
2910   const std::string spirv = R"(
2911 ; CHECK: OpLabel
2912 ; CHECK: [[outer:%\w+]] = OpLabel
2913 ; CHECK-NEXT: OpLoopMerge [[outer_merge:%\w+]] [[outer_cont:%\w+]] None
2914 ; CHECK-NEXT: OpBranch [[inner:%\w+]]
2915 ; CHECK: [[inner]] = OpLabel
2916 ; CHECK: OpLoopMerge [[inner_merge:%\w+]] [[inner_cont:%\w+]] None
2917 ; CHECK: [[inner_cont]] = OpLabel
2918 ; CHECK-NEXT: OpBranch [[inner]]
2919 ; CHECK: [[inner_merge]] = OpLabel
2920 ; CHECK-NEXT: OpUnreachable
2921 ; CHECK: [[outer_cont]] = OpLabel
2922 ; CHECK-NEXT: OpBranch [[outer]]
2923 ; CHECK: [[outer_merge]] = OpLabel
2924 ; CHECK-NEXT: OpUnreachable
2925 OpCapability Shader
2926 OpMemoryModel Logical GLSL450
2927 OpEntryPoint GLCompute %main "main"
2928 OpExecutionMode %main LocalSize 1 1 1
2929 %void = OpTypeVoid
2930 %bool = OpTypeBool
2931 %true = OpConstantTrue %bool
2932 %void_fn = OpTypeFunction %void
2933 %main = OpFunction %void None %void_fn
2934 %entry = OpLabel
2935 OpBranch %outer_loop
2936 %outer_loop = OpLabel
2937 OpLoopMerge %outer_merge %outer_continue None
2938 OpBranch %inner_loop
2939 %inner_loop = OpLabel
2940 OpLoopMerge %inner_merge %inner_continue None
2941 OpBranch %inner_body
2942 %inner_body = OpLabel
2943 OpSelectionMerge %inner_continue None
2944 OpBranchConditional %true %ret %inner_continue
2945 %ret = OpLabel
2946 OpReturn
2947 %inner_continue = OpLabel
2948 OpBranchConditional %true %inner_merge %inner_loop
2949 %inner_merge = OpLabel
2950 OpBranch %outer_continue
2951 %outer_continue = OpLabel
2952 OpBranchConditional %true %outer_merge %outer_loop
2953 %outer_merge = OpLabel
2954 OpReturn
2955 OpFunctionEnd
2956 )";
2957 
2958   SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
2959 }
2960 
2961 // Fold a switch with a nested break.  The only case should be the default.
TEST_F(DeadBranchElimTest,FoldSwitchWithNestedBreak)2962 TEST_F(DeadBranchElimTest, FoldSwitchWithNestedBreak) {
2963   const std::string spirv = R"(
2964 ; CHECK: OpSwitch %int_3 [[case_bb:%\w+]]{{[[:space:]]}}
2965 ; CHECK: [[case_bb]] = OpLabel
2966 ; CHECK-NEXT: OpUndef
2967 ; CHECK-NEXT: OpSelectionMerge
2968                OpCapability Shader
2969           %1 = OpExtInstImport "GLSL.std.450"
2970                OpMemoryModel Logical GLSL450
2971                OpEntryPoint Vertex %2 "main"
2972                OpSource GLSL 450
2973        %void = OpTypeVoid
2974           %4 = OpTypeFunction %void
2975         %int = OpTypeInt 32 1
2976 %_ptr_Function_int = OpTypePointer Function %int
2977       %int_3 = OpConstant %int 3
2978       %int_1 = OpConstant %int 1
2979        %bool = OpTypeBool
2980           %2 = OpFunction %void None %4
2981          %10 = OpLabel
2982                OpSelectionMerge %11 None
2983                OpSwitch %int_3 %12 3 %13
2984          %12 = OpLabel
2985                OpBranch %11
2986          %13 = OpLabel
2987          %14 = OpUndef %bool
2988                OpSelectionMerge %15 None
2989                OpBranchConditional %14 %16 %15
2990          %16 = OpLabel
2991                OpBranch %11
2992          %15 = OpLabel
2993                OpBranch %11
2994          %11 = OpLabel
2995                OpReturn
2996                OpFunctionEnd
2997 )";
2998 
2999   SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
3000 }
3001 
TEST_F(DeadBranchElimTest,FoldBranchWithBreakToSwitch)3002 TEST_F(DeadBranchElimTest, FoldBranchWithBreakToSwitch) {
3003   const std::string spirv = R"(
3004 ; CHECK: OpSelectionMerge [[sel_merge:%\w+]]
3005 ; CHECK-NEXT: OpSwitch {{%\w+}} {{%\w+}} 3 [[bb:%\w+]]
3006 ; CHECK: [[bb]] = OpLabel
3007 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
3008 ; CHECK: [[bb2]] = OpLabel
3009 ; CHECK-NOT: OpSelectionMerge
3010 ; CHECK: OpFunctionEnd
3011                OpCapability Shader
3012           %1 = OpExtInstImport "GLSL.std.450"
3013                OpMemoryModel Logical GLSL450
3014                OpEntryPoint Vertex %2 "main"
3015                OpSource GLSL 450
3016        %void = OpTypeVoid
3017           %4 = OpTypeFunction %void
3018         %int = OpTypeInt 32 1
3019 %_ptr_Function_int = OpTypePointer Function %int
3020       %int_3 = OpConstant %int 3
3021       %int_1 = OpConstant %int 1
3022        %bool = OpTypeBool
3023        %true = OpConstantTrue %bool
3024           %2 = OpFunction %void None %4
3025          %10 = OpLabel
3026   %undef_int = OpUndef %int
3027                OpSelectionMerge %11 None
3028                OpSwitch %undef_int %12 3 %13
3029          %12 = OpLabel
3030                OpBranch %11
3031          %13 = OpLabel
3032                OpSelectionMerge %15 None
3033                OpBranchConditional %true %16 %15
3034          %16 = OpLabel
3035          %14 = OpUndef %bool
3036                OpBranchConditional %14 %11 %17
3037          %17 = OpLabel
3038                OpBranch %15
3039          %15 = OpLabel
3040                OpBranch %11
3041          %11 = OpLabel
3042                OpReturn
3043                OpFunctionEnd
3044 )";
3045 
3046   SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
3047 }
3048 
TEST_F(DeadBranchElimTest,IfInSwitch)3049 TEST_F(DeadBranchElimTest, IfInSwitch) {
3050   // #version 310 es
3051   //
3052   // void main()
3053   // {
3054   //  switch(0)
3055   //  {
3056   //   case 0:
3057   //   if(false)
3058   //   {
3059   //   }
3060   //   else
3061   //   {
3062   //   }
3063   //  }
3064   // }
3065 
3066   const std::string before =
3067       R"(OpCapability Shader
3068 %1 = OpExtInstImport "GLSL.std.450"
3069 OpMemoryModel Logical GLSL450
3070 OpEntryPoint Fragment %main "main"
3071 OpExecutionMode %main OriginUpperLeft
3072 OpSource ESSL 310
3073 OpName %main "main"
3074 %void = OpTypeVoid
3075 %3 = OpTypeFunction %void
3076 %int = OpTypeInt 32 1
3077 %int_0 = OpConstant %int 0
3078 %bool = OpTypeBool
3079 %false = OpConstantFalse %bool
3080 %main = OpFunction %void None %3
3081 %5 = OpLabel
3082 OpSelectionMerge %9 None
3083 OpSwitch %int_0 %9 0 %8
3084 %8 = OpLabel
3085 OpSelectionMerge %13 None
3086 OpBranchConditional %false %12 %13
3087 %12 = OpLabel
3088 OpBranch %13
3089 %13 = OpLabel
3090 OpBranch %9
3091 %9 = OpLabel
3092 OpReturn
3093 OpFunctionEnd
3094 )";
3095 
3096   const std::string after =
3097       R"(OpCapability Shader
3098 %1 = OpExtInstImport "GLSL.std.450"
3099 OpMemoryModel Logical GLSL450
3100 OpEntryPoint Fragment %main "main"
3101 OpExecutionMode %main OriginUpperLeft
3102 OpSource ESSL 310
3103 OpName %main "main"
3104 %void = OpTypeVoid
3105 %4 = OpTypeFunction %void
3106 %int = OpTypeInt 32 1
3107 %int_0 = OpConstant %int 0
3108 %bool = OpTypeBool
3109 %false = OpConstantFalse %bool
3110 %main = OpFunction %void None %4
3111 %9 = OpLabel
3112 OpBranch %11
3113 %11 = OpLabel
3114 OpBranch %12
3115 %12 = OpLabel
3116 OpBranch %10
3117 %10 = OpLabel
3118 OpReturn
3119 OpFunctionEnd
3120 )";
3121 
3122   SinglePassRunAndCheck<DeadBranchElimPass>(before, after, true, true);
3123 }
3124 
TEST_F(DeadBranchElimTest,BreakInNestedHeaderWithSingleCase)3125 TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithSingleCase) {
3126   const std::string text = R"(OpCapability Shader
3127 %1 = OpExtInstImport "GLSL.std.450"
3128 OpMemoryModel Logical GLSL450
3129 OpEntryPoint Fragment %main "main"
3130 OpExecutionMode %main OriginUpperLeft
3131 OpSource GLSL 450
3132 OpName %main "main"
3133 %void = OpTypeVoid
3134 %4 = OpTypeFunction %void
3135 %bool = OpTypeBool
3136 %uint = OpTypeInt 32 0
3137 %uint_0 = OpConstant %uint 0
3138 %8 = OpUndef %bool
3139 %main = OpFunction %void None %4
3140 %9 = OpLabel
3141 OpSelectionMerge %10 None
3142 OpSwitch %uint_0 %11
3143 %11 = OpLabel
3144 OpSelectionMerge %12 None
3145 OpBranchConditional %8 %10 %12
3146 %12 = OpLabel
3147 OpBranch %10
3148 %10 = OpLabel
3149 OpReturn
3150 OpFunctionEnd
3151 )";
3152 
3153   SinglePassRunAndCheck<DeadBranchElimPass>(text, text, true, true);
3154 }
3155 
TEST_F(DeadBranchElimTest,BreakInNestedHeaderWithTwoCases)3156 TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithTwoCases) {
3157   const std::string text = R"(
3158 ; CHECK: OpSelectionMerge [[merge:%\w+]] None
3159 ; CHECK-NEXT: OpSwitch %uint_0 [[bb:%\w+\n]]
3160 OpCapability Shader
3161 %1 = OpExtInstImport "GLSL.std.450"
3162 OpMemoryModel Logical GLSL450
3163 OpEntryPoint Fragment %main "main"
3164 OpExecutionMode %main OriginUpperLeft
3165 OpSource GLSL 450
3166 OpName %main "main"
3167 %void = OpTypeVoid
3168 %4 = OpTypeFunction %void
3169 %bool = OpTypeBool
3170 %uint = OpTypeInt 32 0
3171 %uint_0 = OpConstant %uint 0
3172 %8 = OpUndef %bool
3173 %main = OpFunction %void None %4
3174 %9 = OpLabel
3175 OpSelectionMerge %10 None
3176 OpSwitch %uint_0 %11 1 %12
3177 %11 = OpLabel
3178 OpSelectionMerge %13 None
3179 OpBranchConditional %8 %10 %13
3180 %13 = OpLabel
3181 OpBranch %10
3182 %12 = OpLabel
3183 OpBranch %10
3184 %10 = OpLabel
3185 OpReturn
3186 OpFunctionEnd
3187 )";
3188 
3189   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
3190 }
3191 
TEST_F(DeadBranchElimTest,DebugInformation)3192 TEST_F(DeadBranchElimTest, DebugInformation) {
3193   const std::string text = R"(
3194 OpCapability Shader
3195 %1 = OpExtInstImport "GLSL.std.450"
3196 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
3197 OpMemoryModel Logical GLSL450
3198 OpEntryPoint Fragment %main "main" %gl_FragColor
3199 OpExecutionMode %main OriginUpperLeft
3200 OpSource GLSL 140
3201 %name = OpString "test"
3202 OpName %main "main"
3203 OpName %gl_FragColor "gl_FragColor"
3204 %void = OpTypeVoid
3205 %5 = OpTypeFunction %void
3206 %bool = OpTypeBool
3207 %true = OpConstantTrue %bool
3208 %float = OpTypeFloat 32
3209 %v4float = OpTypeVector %float 4
3210 %_ptr_Function_v4float = OpTypePointer Function %v4float
3211 %float_0 = OpConstant %float 0
3212 
3213 ; CHECK: [[value:%\w+]] = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
3214 %12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
3215 %float_1 = OpConstant %float 1
3216 %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3217 %_ptr_Output_v4float = OpTypePointer Output %v4float
3218 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
3219 %_ptr_Input_v4float = OpTypePointer Input %v4float
3220 %uint = OpTypeInt 32 0
3221 %uint_32 = OpConstant %uint 32
3222 
3223 %null_expr = OpExtInst %void %ext DebugExpression
3224 %src = OpExtInst %void %ext DebugSource %name
3225 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
3226 %ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %void
3227 %dbg_main = OpExtInst %void %ext DebugFunction %name %ty %src 0 0 %cu %name FlagIsProtected|FlagIsPrivate 0 %main
3228 
3229 ; CHECK: [[bb1:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugLexicalBlock [[src:%\w+]] 1 0 [[dbg_main:%\w+]]
3230 ; CHECK: [[bb2:%\w+]] = OpExtInst %void [[ext]] DebugLexicalBlock [[src]] 2 0 [[dbg_main]]
3231 ; CHECK: [[bb3:%\w+]] = OpExtInst %void [[ext]] DebugLexicalBlock [[src]] 3 0 [[dbg_main]]
3232 %bb1 = OpExtInst %void %ext DebugLexicalBlock %src 1 0 %dbg_main
3233 %bb2 = OpExtInst %void %ext DebugLexicalBlock %src 2 0 %dbg_main
3234 %bb3 = OpExtInst %void %ext DebugLexicalBlock %src 3 0 %dbg_main
3235 
3236 %dbg_f = OpExtInst %void %ext DebugTypeBasic %name %uint_32 Float
3237 ; CHECK: [[dbg_foo:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable {{%\w+}} [[ty:%\w+]] [[src]] 0 0 [[dbg_main]]
3238 %dbg_foo = OpExtInst %void %ext DebugLocalVariable %name %dbg_f %src 0 0 %dbg_main FlagIsLocal
3239 ; CHECK: [[dbg_bar:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable {{%\w+}} [[ty]] [[src]] 1 0 [[bb3]]
3240 %dbg_bar = OpExtInst %void %ext DebugLocalVariable %name %dbg_f %src 1 0 %bb3 FlagIsLocal
3241 
3242 %main = OpFunction %void None %5
3243 %17 = OpLabel
3244 ; CHECK-NOT: DebugScope [[dbg_main]]
3245 ; CHECK-NOT: OpLine {{%\w+}} 0 0
3246 %scope0 = OpExtInst %void %ext DebugScope %dbg_main
3247 OpLine %name 0 0
3248 OpSelectionMerge %18 None
3249 OpBranchConditional %true %19 %20
3250 %19 = OpLabel
3251 ; CHECK: DebugScope [[bb1]]
3252 ; CHECK: OpLine {{%\w+}} 1 0
3253 %scope1 = OpExtInst %void %ext DebugScope %bb1
3254 OpLine %name 1 0
3255 OpBranch %18
3256 %20 = OpLabel
3257 ; CHECK-NOT: DebugScope [[bb2]]
3258 ; CHECK-NOT: OpLine {{%\w+}} 2 0
3259 %scope2 = OpExtInst %void %ext DebugScope %bb2
3260 OpLine %name 2 0
3261 OpBranch %18
3262 %18 = OpLabel
3263 
3264 ; CHECK: DebugScope [[bb3]]
3265 ; CHECK: OpLine {{%\w+}} 3 0
3266 ; CHECK: DebugValue [[dbg_foo]] [[value]]
3267 ; CHECK: OpLine {{%\w+}} 4 0
3268 ; CHECK: OpStore %gl_FragColor [[value]]
3269 ; CHECK: DebugDeclare [[dbg_bar]] %gl_FragColor
3270 ; CHECK: DebugValue [[dbg_bar]] [[value]]
3271 %scope3 = OpExtInst %void %ext DebugScope %bb3
3272 OpLine %name 3 0
3273 %21 = OpPhi %v4float %12 %19 %14 %20
3274 %decl0 = OpExtInst %void %ext DebugValue %dbg_foo %21 %null_expr
3275 OpLine %name 4 0
3276 OpStore %gl_FragColor %21
3277 %decl1 = OpExtInst %void %ext DebugDeclare %dbg_bar %gl_FragColor %null_expr
3278 %decl2 = OpExtInst %void %ext DebugValue %dbg_bar %21 %null_expr
3279 OpLine %name 5 0
3280 OpReturn
3281 OpFunctionEnd
3282 )";
3283 
3284   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
3285 }
3286 
TEST_F(DeadBranchElimTest,DontTransferDecorations)3287 TEST_F(DeadBranchElimTest, DontTransferDecorations) {
3288   // When replacing %4 with %14, we don't want %14 to inherit %4's decorations.
3289   const std::string text = R"(
3290 ; CHECK-NOT: OpDecorate {{%\w+}} RelaxedPrecision
3291 ; CHECK: [[div:%\w+]] = OpFDiv
3292 ; CHECK: {{%\w+}} = OpCopyObject %float [[div]]
3293                OpCapability Shader
3294           %1 = OpExtInstImport "GLSL.std.450"
3295                OpMemoryModel Logical GLSL450
3296                OpEntryPoint Fragment %2 "main"
3297                OpExecutionMode %2 OriginUpperLeft
3298           %3 = OpString "STEVEN"
3299                OpDecorate %4 RelaxedPrecision
3300       %float = OpTypeFloat 32
3301        %uint = OpTypeInt 32 0
3302        %void = OpTypeVoid
3303     %float_1 = OpConstant %float 1
3304      %uint_0 = OpConstant %uint 0
3305          %10 = OpTypeFunction %void
3306           %2 = OpFunction %void None %10
3307          %11 = OpLabel
3308                OpSelectionMerge %12 None
3309                OpSwitch %uint_0 %13
3310          %13 = OpLabel
3311          %14 = OpFDiv %float %float_1 %float_1
3312                OpLine %3 0 0
3313                OpBranch %12
3314          %15 = OpLabel
3315                OpBranch %12
3316          %12 = OpLabel
3317           %4 = OpPhi %float %float_1 %15 %14 %13
3318          %16 = OpCopyObject %float %4
3319                OpReturn
3320                OpFunctionEnd
3321 )";
3322 
3323   SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
3324 }
3325 
TEST_F(DeadBranchElimTest,FunctionDeclaration)3326 TEST_F(DeadBranchElimTest, FunctionDeclaration) {
3327   // Make sure the pass works with a function declaration that is called.
3328   const std::string text = R"(OpCapability Addresses
3329 OpCapability Linkage
3330 OpCapability Kernel
3331 OpCapability Int8
3332 %1 = OpExtInstImport "OpenCL.std"
3333 OpMemoryModel Physical64 OpenCL
3334 OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
3335 OpExecutionMode %2 ContractionOff
3336 OpSource Unknown 0
3337 OpDecorate %3 LinkageAttributes "julia_error_7712" Import
3338 %void = OpTypeVoid
3339 %5 = OpTypeFunction %void
3340 %3 = OpFunction %void None %5
3341 OpFunctionEnd
3342 %2 = OpFunction %void None %5
3343 %6 = OpLabel
3344 %7 = OpFunctionCall %void %3
3345 OpReturn
3346 OpFunctionEnd
3347 )";
3348 
3349   SinglePassRunAndCheck<DeadBranchElimPass>(text, text, false);
3350 }
3351 
3352 // TODO(greg-lunarg): Add tests to verify handling of these cases:
3353 //
3354 //    More complex control flow
3355 //    Others?
3356 
3357 }  // namespace
3358 }  // namespace opt
3359 }  // namespace spvtools
3360