• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 Valve Corporation
2 // Copyright (c) 2017 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <string>
17 
18 #include "test/opt/pass_fixture.h"
19 #include "test/opt/pass_utils.h"
20 
21 namespace spvtools {
22 namespace opt {
23 namespace {
24 
25 using BlockMergeTest = PassTest<::testing::Test>;
26 
TEST_F(BlockMergeTest,Simple)27 TEST_F(BlockMergeTest, Simple) {
28   // Note: SPIR-V hand edited to insert block boundary
29   // between two statements in main.
30   //
31   //  #version 140
32   //
33   //  in vec4 BaseColor;
34   //
35   //  void main()
36   //  {
37   //      vec4 v = BaseColor;
38   //      gl_FragColor = v;
39   //  }
40 
41   const std::string predefs =
42       R"(OpCapability Shader
43 %1 = OpExtInstImport "GLSL.std.450"
44 OpMemoryModel Logical GLSL450
45 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
46 OpExecutionMode %main OriginUpperLeft
47 OpSource GLSL 140
48 OpName %main "main"
49 OpName %v "v"
50 OpName %BaseColor "BaseColor"
51 OpName %gl_FragColor "gl_FragColor"
52 %void = OpTypeVoid
53 %7 = OpTypeFunction %void
54 %float = OpTypeFloat 32
55 %v4float = OpTypeVector %float 4
56 %_ptr_Function_v4float = OpTypePointer Function %v4float
57 %_ptr_Input_v4float = OpTypePointer Input %v4float
58 %BaseColor = OpVariable %_ptr_Input_v4float Input
59 %_ptr_Output_v4float = OpTypePointer Output %v4float
60 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
61 )";
62 
63   const std::string before =
64       R"(%main = OpFunction %void None %7
65 %13 = OpLabel
66 %v = OpVariable %_ptr_Function_v4float Function
67 %14 = OpLoad %v4float %BaseColor
68 OpStore %v %14
69 OpBranch %15
70 %15 = OpLabel
71 %16 = OpLoad %v4float %v
72 OpStore %gl_FragColor %16
73 OpReturn
74 OpFunctionEnd
75 )";
76 
77   const std::string after =
78       R"(%main = OpFunction %void None %7
79 %13 = OpLabel
80 %v = OpVariable %_ptr_Function_v4float Function
81 %14 = OpLoad %v4float %BaseColor
82 OpStore %v %14
83 %16 = OpLoad %v4float %v
84 OpStore %gl_FragColor %16
85 OpReturn
86 OpFunctionEnd
87 )";
88 
89   SinglePassRunAndCheck<BlockMergePass>(predefs + before, predefs + after, true,
90                                         true);
91 }
92 
TEST_F(BlockMergeTest,EmptyBlock)93 TEST_F(BlockMergeTest, EmptyBlock) {
94   // Note: SPIR-V hand edited to insert empty block
95   // after two statements in main.
96   //
97   //  #version 140
98   //
99   //  in vec4 BaseColor;
100   //
101   //  void main()
102   //  {
103   //      vec4 v = BaseColor;
104   //      gl_FragColor = v;
105   //  }
106 
107   const std::string predefs =
108       R"(OpCapability Shader
109 %1 = OpExtInstImport "GLSL.std.450"
110 OpMemoryModel Logical GLSL450
111 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
112 OpExecutionMode %main OriginUpperLeft
113 OpSource GLSL 140
114 OpName %main "main"
115 OpName %v "v"
116 OpName %BaseColor "BaseColor"
117 OpName %gl_FragColor "gl_FragColor"
118 %void = OpTypeVoid
119 %7 = OpTypeFunction %void
120 %float = OpTypeFloat 32
121 %v4float = OpTypeVector %float 4
122 %_ptr_Function_v4float = OpTypePointer Function %v4float
123 %_ptr_Input_v4float = OpTypePointer Input %v4float
124 %BaseColor = OpVariable %_ptr_Input_v4float Input
125 %_ptr_Output_v4float = OpTypePointer Output %v4float
126 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
127 )";
128 
129   const std::string before =
130       R"(%main = OpFunction %void None %7
131 %13 = OpLabel
132 %v = OpVariable %_ptr_Function_v4float Function
133 %14 = OpLoad %v4float %BaseColor
134 OpStore %v %14
135 OpBranch %15
136 %15 = OpLabel
137 %16 = OpLoad %v4float %v
138 OpStore %gl_FragColor %16
139 OpBranch %17
140 %17 = OpLabel
141 OpBranch %18
142 %18 = OpLabel
143 OpReturn
144 OpFunctionEnd
145 )";
146 
147   const std::string after =
148       R"(%main = OpFunction %void None %7
149 %13 = OpLabel
150 %v = OpVariable %_ptr_Function_v4float Function
151 %14 = OpLoad %v4float %BaseColor
152 OpStore %v %14
153 %16 = OpLoad %v4float %v
154 OpStore %gl_FragColor %16
155 OpReturn
156 OpFunctionEnd
157 )";
158 
159   SinglePassRunAndCheck<BlockMergePass>(predefs + before, predefs + after, true,
160                                         true);
161 }
162 
TEST_F(BlockMergeTest,NestedInControlFlow)163 TEST_F(BlockMergeTest, NestedInControlFlow) {
164   // Note: SPIR-V hand edited to insert block boundary
165   // between OpFMul and OpStore in then-part.
166   //
167   // #version 140
168   // in vec4 BaseColor;
169   //
170   // layout(std140) uniform U_t
171   // {
172   //     bool g_B ;
173   // } ;
174   //
175   // void main()
176   // {
177   //     vec4 v = BaseColor;
178   //     if (g_B)
179   //       vec4 v = v * 0.25;
180   //     gl_FragColor = v;
181   // }
182 
183   const std::string predefs =
184       R"(OpCapability Shader
185 %1 = OpExtInstImport "GLSL.std.450"
186 OpMemoryModel Logical GLSL450
187 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
188 OpExecutionMode %main OriginUpperLeft
189 OpSource GLSL 140
190 OpName %main "main"
191 OpName %v "v"
192 OpName %BaseColor "BaseColor"
193 OpName %U_t "U_t"
194 OpMemberName %U_t 0 "g_B"
195 OpName %_ ""
196 OpName %v_0 "v"
197 OpName %gl_FragColor "gl_FragColor"
198 OpMemberDecorate %U_t 0 Offset 0
199 OpDecorate %U_t Block
200 OpDecorate %_ DescriptorSet 0
201 %void = OpTypeVoid
202 %10 = OpTypeFunction %void
203 %float = OpTypeFloat 32
204 %v4float = OpTypeVector %float 4
205 %_ptr_Function_v4float = OpTypePointer Function %v4float
206 %_ptr_Input_v4float = OpTypePointer Input %v4float
207 %BaseColor = OpVariable %_ptr_Input_v4float Input
208 %uint = OpTypeInt 32 0
209 %U_t = OpTypeStruct %uint
210 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
211 %_ = OpVariable %_ptr_Uniform_U_t Uniform
212 %int = OpTypeInt 32 1
213 %int_0 = OpConstant %int 0
214 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
215 %bool = OpTypeBool
216 %uint_0 = OpConstant %uint 0
217 %float_0_25 = OpConstant %float 0.25
218 %_ptr_Output_v4float = OpTypePointer Output %v4float
219 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
220 )";
221 
222   const std::string before =
223       R"(%main = OpFunction %void None %10
224 %24 = OpLabel
225 %v = OpVariable %_ptr_Function_v4float Function
226 %v_0 = OpVariable %_ptr_Function_v4float Function
227 %25 = OpLoad %v4float %BaseColor
228 OpStore %v %25
229 %26 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
230 %27 = OpLoad %uint %26
231 %28 = OpINotEqual %bool %27 %uint_0
232 OpSelectionMerge %29 None
233 OpBranchConditional %28 %30 %29
234 %30 = OpLabel
235 %31 = OpLoad %v4float %v
236 %32 = OpVectorTimesScalar %v4float %31 %float_0_25
237 OpBranch %33
238 %33 = OpLabel
239 OpStore %v_0 %32
240 OpBranch %29
241 %29 = OpLabel
242 %34 = OpLoad %v4float %v
243 OpStore %gl_FragColor %34
244 OpReturn
245 OpFunctionEnd
246 )";
247 
248   const std::string after =
249       R"(%main = OpFunction %void None %10
250 %24 = OpLabel
251 %v = OpVariable %_ptr_Function_v4float Function
252 %v_0 = OpVariable %_ptr_Function_v4float Function
253 %25 = OpLoad %v4float %BaseColor
254 OpStore %v %25
255 %26 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
256 %27 = OpLoad %uint %26
257 %28 = OpINotEqual %bool %27 %uint_0
258 OpSelectionMerge %29 None
259 OpBranchConditional %28 %30 %29
260 %30 = OpLabel
261 %31 = OpLoad %v4float %v
262 %32 = OpVectorTimesScalar %v4float %31 %float_0_25
263 OpStore %v_0 %32
264 OpBranch %29
265 %29 = OpLabel
266 %34 = OpLoad %v4float %v
267 OpStore %gl_FragColor %34
268 OpReturn
269 OpFunctionEnd
270 )";
271 
272   SinglePassRunAndCheck<BlockMergePass>(predefs + before, predefs + after, true,
273                                         true);
274 }
275 
TEST_F(BlockMergeTest,PhiInSuccessorOfMergedBlock)276 TEST_F(BlockMergeTest, PhiInSuccessorOfMergedBlock) {
277   const std::string text = R"(
278 ; CHECK: OpSelectionMerge [[merge:%\w+]] None
279 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[then:%\w+]] [[else:%\w+]]
280 ; CHECK: [[then]] = OpLabel
281 ; CHECK-NEXT: OpBranch [[merge]]
282 ; CHECK: [[else]] = OpLabel
283 ; CHECK-NEXT: OpBranch [[merge]]
284 ; CHECK: [[merge]] = OpLabel
285 ; CHECK-NEXT: OpPhi {{%\w+}} %true [[then]] %false [[else]]
286 OpCapability Shader
287 OpMemoryModel Logical GLSL450
288 OpEntryPoint Fragment %func "func"
289 OpExecutionMode %func OriginUpperLeft
290 %void = OpTypeVoid
291 %bool = OpTypeBool
292 %true = OpConstantTrue %bool
293 %false = OpConstantFalse  %bool
294 %functy = OpTypeFunction %void
295 %func = OpFunction %void None %functy
296 %entry = OpLabel
297 OpSelectionMerge %merge None
298 OpBranchConditional %true %then %else
299 %then = OpLabel
300 OpBranch %then_next
301 %then_next = OpLabel
302 OpBranch %merge
303 %else = OpLabel
304 OpBranch %merge
305 %merge = OpLabel
306 %phi = OpPhi %bool %true %then_next %false %else
307 OpReturn
308 OpFunctionEnd
309 )";
310 
311   SinglePassRunAndMatch<BlockMergePass>(text, true);
312 }
313 
TEST_F(BlockMergeTest,UpdateMergeInstruction)314 TEST_F(BlockMergeTest, UpdateMergeInstruction) {
315   const std::string text = R"(
316 ; CHECK: OpSelectionMerge [[merge:%\w+]] None
317 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[then:%\w+]] [[else:%\w+]]
318 ; CHECK: [[then]] = OpLabel
319 ; CHECK-NEXT: OpBranch [[merge]]
320 ; CHECK: [[else]] = OpLabel
321 ; CHECK-NEXT: OpBranch [[merge]]
322 ; CHECK: [[merge]] = OpLabel
323 ; CHECK-NEXT: OpReturn
324 OpCapability Shader
325 OpMemoryModel Logical GLSL450
326 OpEntryPoint Fragment %func "func"
327 OpExecutionMode %func OriginUpperLeft
328 %void = OpTypeVoid
329 %bool = OpTypeBool
330 %true = OpConstantTrue %bool
331 %false = OpConstantFalse  %bool
332 %functy = OpTypeFunction %void
333 %func = OpFunction %void None %functy
334 %entry = OpLabel
335 OpSelectionMerge %real_merge None
336 OpBranchConditional %true %then %else
337 %then = OpLabel
338 OpBranch %merge
339 %else = OpLabel
340 OpBranch %merge
341 %merge = OpLabel
342 OpBranch %real_merge
343 %real_merge = OpLabel
344 OpReturn
345 OpFunctionEnd
346 )";
347 
348   SinglePassRunAndMatch<BlockMergePass>(text, true);
349 }
350 
TEST_F(BlockMergeTest,TwoMergeBlocksCannotBeMerged)351 TEST_F(BlockMergeTest, TwoMergeBlocksCannotBeMerged) {
352   const std::string text = R"(
353 ; CHECK: OpSelectionMerge [[outer_merge:%\w+]] None
354 ; CHECK: OpSelectionMerge [[inner_merge:%\w+]] None
355 ; CHECK: [[inner_merge]] = OpLabel
356 ; CHECK-NEXT: OpBranch [[outer_merge]]
357 ; CHECK: [[outer_merge]] = OpLabel
358 ; CHECK-NEXT: OpReturn
359 OpCapability Shader
360 OpMemoryModel Logical GLSL450
361 OpEntryPoint Fragment %func "func"
362 OpExecutionMode %func OriginUpperLeft
363 %void = OpTypeVoid
364 %bool = OpTypeBool
365 %true = OpConstantTrue %bool
366 %false = OpConstantFalse  %bool
367 %functy = OpTypeFunction %void
368 %func = OpFunction %void None %functy
369 %entry = OpLabel
370 OpSelectionMerge %outer_merge None
371 OpBranchConditional %true %then %else
372 %then = OpLabel
373 OpBranch %inner_header
374 %else = OpLabel
375 OpBranch %inner_header
376 %inner_header = OpLabel
377 OpSelectionMerge %inner_merge None
378 OpBranchConditional %true %inner_then %inner_else
379 %inner_then = OpLabel
380 OpBranch %inner_merge
381 %inner_else = OpLabel
382 OpBranch %inner_merge
383 %inner_merge = OpLabel
384 OpBranch %outer_merge
385 %outer_merge = OpLabel
386 OpReturn
387 OpFunctionEnd
388 )";
389 
390   SinglePassRunAndMatch<BlockMergePass>(text, true);
391 }
392 
TEST_F(BlockMergeTest,MergeContinue)393 TEST_F(BlockMergeTest, MergeContinue) {
394   const std::string text = R"(
395 ; CHECK: OpBranch [[header:%\w+]]
396 ; CHECK: [[header]] = OpLabel
397 ; CHECK-NEXT: OpLogicalAnd
398 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[header]] None
399 ; CHECK-NEXT: OpBranch [[header]]
400 OpCapability Shader
401 OpMemoryModel Logical GLSL450
402 OpEntryPoint Fragment %func "func"
403 OpExecutionMode %func OriginUpperLeft
404 %void = OpTypeVoid
405 %bool = OpTypeBool
406 %true = OpConstantTrue %bool
407 %false = OpConstantFalse  %bool
408 %functy = OpTypeFunction %void
409 %func = OpFunction %void None %functy
410 %entry = OpLabel
411 OpBranch %header
412 %header = OpLabel
413 OpLoopMerge %merge %continue None
414 OpBranch %continue
415 %continue = OpLabel
416 %op = OpLogicalAnd %bool %true %false
417 OpBranch %header
418 %merge = OpLabel
419 OpUnreachable
420 OpFunctionEnd
421 )";
422 
423   SinglePassRunAndMatch<BlockMergePass>(text, true);
424 }
425 
TEST_F(BlockMergeTest,TwoHeadersCannotBeMerged)426 TEST_F(BlockMergeTest, TwoHeadersCannotBeMerged) {
427   const std::string text = R"(
428 ; CHECK: OpBranch [[loop_header:%\w+]]
429 ; CHECK: [[loop_header]] = OpLabel
430 ; CHECK-NEXT: OpLoopMerge
431 ; CHECK-NEXT: OpBranch [[if_header:%\w+]]
432 ; CHECK: [[if_header]] = OpLabel
433 ; CHECK-NEXT: OpSelectionMerge
434 OpCapability Shader
435 OpMemoryModel Logical GLSL450
436 OpEntryPoint Fragment %func "func"
437 OpExecutionMode %func OriginUpperLeft
438 %void = OpTypeVoid
439 %bool = OpTypeBool
440 %true = OpConstantTrue %bool
441 %false = OpConstantFalse  %bool
442 %functy = OpTypeFunction %void
443 %func = OpFunction %void None %functy
444 %entry = OpLabel
445 OpBranch %header
446 %header = OpLabel
447 OpLoopMerge %merge %continue None
448 OpBranch %inner_header
449 %inner_header = OpLabel
450 OpSelectionMerge %continue None
451 OpBranchConditional %true %then %continue
452 %then = OpLabel
453 OpBranch %continue
454 %continue = OpLabel
455 OpBranchConditional %false %merge %header
456 %merge = OpLabel
457 OpReturn
458 OpFunctionEnd
459 )";
460 
461   SinglePassRunAndMatch<BlockMergePass>(text, true);
462 }
463 
TEST_F(BlockMergeTest,RemoveStructuredDeclaration)464 TEST_F(BlockMergeTest, RemoveStructuredDeclaration) {
465   // Note: SPIR-V hand edited remove dead branch and add block
466   // before continue block
467   //
468   // #version 140
469   // in vec4 BaseColor;
470   //
471   // void main()
472   // {
473   //     while (true) {
474   //         break;
475   //     }
476   //     gl_FragColor = BaseColor;
477   // }
478 
479   const std::string assembly =
480       R"(
481 ; CHECK: OpLabel
482 ; CHECK: [[header:%\w+]] = OpLabel
483 ; CHECK-NOT: OpLoopMerge
484 ; CHECK: OpReturn
485 ; CHECK: [[continue:%\w+]] = OpLabel
486 ; CHECK-NEXT: OpBranch [[header]]
487 OpCapability Shader
488 %1 = OpExtInstImport "GLSL.std.450"
489 OpMemoryModel Logical GLSL450
490 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
491 OpExecutionMode %main OriginUpperLeft
492 OpSource GLSL 140
493 OpName %main "main"
494 OpName %gl_FragColor "gl_FragColor"
495 OpName %BaseColor "BaseColor"
496 %void = OpTypeVoid
497 %6 = OpTypeFunction %void
498 %bool = OpTypeBool
499 %true = OpConstantTrue %bool
500 %float = OpTypeFloat 32
501 %v4float = OpTypeVector %float 4
502 %_ptr_Output_v4float = OpTypePointer Output %v4float
503 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
504 %_ptr_Input_v4float = OpTypePointer Input %v4float
505 %BaseColor = OpVariable %_ptr_Input_v4float Input
506 %main = OpFunction %void None %6
507 %13 = OpLabel
508 OpBranch %14
509 %14 = OpLabel
510 OpLoopMerge %15 %16 None
511 OpBranch %17
512 %17 = OpLabel
513 OpBranch %15
514 %18 = OpLabel
515 OpBranch %16
516 %16 = OpLabel
517 OpBranch %14
518 %15 = OpLabel
519 %19 = OpLoad %v4float %BaseColor
520 OpStore %gl_FragColor %19
521 OpReturn
522 OpFunctionEnd
523 )";
524 
525   SinglePassRunAndMatch<BlockMergePass>(assembly, true);
526 }
527 
TEST_F(BlockMergeTest,DontMergeKill)528 TEST_F(BlockMergeTest, DontMergeKill) {
529   const std::string text = R"(
530 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
531 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
532 ; CHECK: [[ret:%\w+]] = OpLabel
533 ; CHECK-NEXT: OpKill
534 ; CHECK-DAG: [[cont]] = OpLabel
535 ; CHECK-DAG: [[merge]] = OpLabel
536 OpCapability Shader
537 OpMemoryModel Logical GLSL450
538 OpEntryPoint Fragment %func "func"
539 OpExecutionMode %func OriginUpperLeft
540 %void = OpTypeVoid
541 %bool = OpTypeBool
542 %functy = OpTypeFunction %void
543 %func = OpFunction %void None %functy
544 %1 = OpLabel
545 OpBranch %2
546 %2 = OpLabel
547 OpLoopMerge %3 %4 None
548 OpBranch %5
549 %5 = OpLabel
550 OpKill
551 %4 = OpLabel
552 OpBranch %2
553 %3 = OpLabel
554 OpUnreachable
555 OpFunctionEnd
556 )";
557 
558   SinglePassRunAndMatch<BlockMergePass>(text, true);
559 }
560 
TEST_F(BlockMergeTest,DontMergeUnreachable)561 TEST_F(BlockMergeTest, DontMergeUnreachable) {
562   const std::string text = R"(
563 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
564 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
565 ; CHECK: [[ret:%\w+]] = OpLabel
566 ; CHECK-NEXT: OpUnreachable
567 ; CHECK-DAG: [[cont]] = OpLabel
568 ; CHECK-DAG: [[merge]] = OpLabel
569 OpCapability Shader
570 OpMemoryModel Logical GLSL450
571 OpEntryPoint Fragment %func "func"
572 OpExecutionMode %func OriginUpperLeft
573 %void = OpTypeVoid
574 %bool = OpTypeBool
575 %functy = OpTypeFunction %void
576 %func = OpFunction %void None %functy
577 %1 = OpLabel
578 OpBranch %2
579 %2 = OpLabel
580 OpLoopMerge %3 %4 None
581 OpBranch %5
582 %5 = OpLabel
583 OpUnreachable
584 %4 = OpLabel
585 OpBranch %2
586 %3 = OpLabel
587 OpUnreachable
588 OpFunctionEnd
589 )";
590 
591   SinglePassRunAndMatch<BlockMergePass>(text, true);
592 }
593 
TEST_F(BlockMergeTest,DontMergeReturn)594 TEST_F(BlockMergeTest, DontMergeReturn) {
595   const std::string text = R"(
596 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
597 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
598 ; CHECK: [[ret:%\w+]] = OpLabel
599 ; CHECK-NEXT: OpReturn
600 ; CHECK-DAG: [[cont]] = OpLabel
601 ; CHECK-DAG: [[merge]] = OpLabel
602 OpCapability Shader
603 OpMemoryModel Logical GLSL450
604 OpEntryPoint Fragment %func "func"
605 OpExecutionMode %func OriginUpperLeft
606 %void = OpTypeVoid
607 %bool = OpTypeBool
608 %functy = OpTypeFunction %void
609 %func = OpFunction %void None %functy
610 %1 = OpLabel
611 OpBranch %2
612 %2 = OpLabel
613 OpLoopMerge %3 %4 None
614 OpBranch %5
615 %5 = OpLabel
616 OpReturn
617 %4 = OpLabel
618 OpBranch %2
619 %3 = OpLabel
620 OpUnreachable
621 OpFunctionEnd
622 )";
623 
624   SinglePassRunAndMatch<BlockMergePass>(text, true);
625 }
626 
TEST_F(BlockMergeTest,DontMergeSwitch)627 TEST_F(BlockMergeTest, DontMergeSwitch) {
628   const std::string text = R"(
629 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
630 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
631 ; CHECK: [[ret:%\w+]] = OpLabel
632 ; CHECK-NEXT: OpSwitch
633 ; CHECK-DAG: [[cont]] = OpLabel
634 ; CHECK-DAG: [[merge]] = OpLabel
635 OpCapability Shader
636 OpMemoryModel Logical GLSL450
637 OpEntryPoint Fragment %func "func"
638 OpExecutionMode %func OriginUpperLeft
639 %void = OpTypeVoid
640 %bool = OpTypeBool
641 %int = OpTypeInt 32 1
642 %int_0 = OpConstant %int 0
643 %functy = OpTypeFunction %void
644 %func = OpFunction %void None %functy
645 %1 = OpLabel
646 OpBranch %2
647 %2 = OpLabel
648 OpLoopMerge %3 %4 None
649 OpBranch %5
650 %5 = OpLabel
651 OpSwitch %int_0 %6
652 %6 = OpLabel
653 OpReturn
654 %4 = OpLabel
655 OpBranch %2
656 %3 = OpLabel
657 OpUnreachable
658 OpFunctionEnd
659 )";
660 
661   SinglePassRunAndMatch<BlockMergePass>(text, true);
662 }
663 
TEST_F(BlockMergeTest,DontMergeReturnValue)664 TEST_F(BlockMergeTest, DontMergeReturnValue) {
665   const std::string text = R"(
666 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
667 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
668 ; CHECK: [[ret:%\w+]] = OpLabel
669 ; CHECK-NEXT: OpReturn
670 ; CHECK-DAG: [[cont]] = OpLabel
671 ; CHECK-DAG: [[merge]] = OpLabel
672 OpCapability Shader
673 OpMemoryModel Logical GLSL450
674 OpEntryPoint Fragment %func "func"
675 OpExecutionMode %func OriginUpperLeft
676 %void = OpTypeVoid
677 %bool = OpTypeBool
678 %functy = OpTypeFunction %void
679 %otherfuncty = OpTypeFunction %bool
680 %true = OpConstantTrue %bool
681 %func = OpFunction %void None %functy
682 %1 = OpLabel
683 %2 = OpFunctionCall %bool %3
684 OpReturn
685 OpFunctionEnd
686 %3 = OpFunction %bool None %otherfuncty
687 %4 = OpLabel
688 OpBranch %5
689 %5 = OpLabel
690 OpLoopMerge %6 %7 None
691 OpBranch %8
692 %8 = OpLabel
693 OpReturnValue %true
694 %7 = OpLabel
695 OpBranch %5
696 %6 = OpLabel
697 OpUnreachable
698 OpFunctionEnd
699 )";
700 
701   SinglePassRunAndMatch<BlockMergePass>(text, true);
702 }
703 
TEST_F(BlockMergeTest,MergeHeaders)704 TEST_F(BlockMergeTest, MergeHeaders) {
705   // Merge two headers when the second is the merge block of the first.
706   const std::string text = R"(
707 ; CHECK: OpFunction
708 ; CHECK-NEXT: OpLabel
709 ; CHECK-NEXT: OpBranch [[header:%\w+]]
710 ; CHECK-NEXT: [[header]] = OpLabel
711 ; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
712 ; CHECK: [[merge]] = OpLabel
713 ; CHEKC: OpReturn
714 OpCapability Shader
715 OpMemoryModel Logical GLSL450
716 OpEntryPoint Fragment %func "func"
717 OpExecutionMode %func OriginUpperLeft
718 %void = OpTypeVoid
719 %bool = OpTypeBool
720 %functy = OpTypeFunction %void
721 %otherfuncty = OpTypeFunction %bool
722 %true = OpConstantTrue %bool
723 %func = OpFunction %void None %functy
724 %1 = OpLabel
725 OpBranch %5
726 %5 = OpLabel
727 OpLoopMerge %8 %7 None
728 OpBranch %8
729 %7 = OpLabel
730 OpBranch %5
731 %8 = OpLabel
732 OpSelectionMerge %m None
733 OpBranchConditional %true %a %m
734 %a = OpLabel
735 OpBranch %m
736 %m = OpLabel
737 OpReturn
738 OpFunctionEnd
739 )";
740 
741   SinglePassRunAndMatch<BlockMergePass>(text, true);
742 }
743 
744 // TODO(greg-lunarg): Add tests to verify handling of these cases:
745 //
746 //    More complex control flow
747 //    Others?
748 
749 }  // namespace
750 }  // namespace opt
751 }  // namespace spvtools
752