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