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