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