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