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