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,MergeContinueWithOpLine)426 TEST_F(BlockMergeTest, MergeContinueWithOpLine) {
427 const std::string text = R"(
428 ; CHECK: OpBranch [[header:%\w+]]
429 ; CHECK: [[header]] = OpLabel
430 ; CHECK-NEXT: OpLogicalAnd
431 ; CHECK-NEXT: OpLine {{%\w+}} 1 1
432 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[header]] None
433 ; CHECK-NEXT: OpBranch [[header]]
434 OpCapability Shader
435 OpMemoryModel Logical GLSL450
436 OpEntryPoint Fragment %func "func"
437 OpExecutionMode %func OriginUpperLeft
438 %src = OpString "test.shader"
439 %void = OpTypeVoid
440 %bool = OpTypeBool
441 %true = OpConstantTrue %bool
442 %false = OpConstantFalse %bool
443 %functy = OpTypeFunction %void
444 %func = OpFunction %void None %functy
445 %entry = OpLabel
446 OpBranch %header
447 %header = OpLabel
448 OpLoopMerge %merge %continue None
449 OpBranch %continue
450 %continue = OpLabel
451 %op = OpLogicalAnd %bool %true %false
452 OpLine %src 1 1
453 OpBranch %header
454 %merge = OpLabel
455 OpUnreachable
456 OpFunctionEnd
457 )";
458
459 SinglePassRunAndMatch<BlockMergePass>(text, true);
460 }
461
TEST_F(BlockMergeTest,TwoHeadersCannotBeMerged)462 TEST_F(BlockMergeTest, TwoHeadersCannotBeMerged) {
463 const std::string text = R"(
464 ; CHECK: OpBranch [[loop_header:%\w+]]
465 ; CHECK: [[loop_header]] = OpLabel
466 ; CHECK-NEXT: OpLoopMerge
467 ; CHECK-NEXT: OpBranch [[if_header:%\w+]]
468 ; CHECK: [[if_header]] = OpLabel
469 ; CHECK-NEXT: OpSelectionMerge
470 OpCapability Shader
471 OpMemoryModel Logical GLSL450
472 OpEntryPoint Fragment %func "func"
473 OpExecutionMode %func OriginUpperLeft
474 %void = OpTypeVoid
475 %bool = OpTypeBool
476 %true = OpConstantTrue %bool
477 %false = OpConstantFalse %bool
478 %functy = OpTypeFunction %void
479 %func = OpFunction %void None %functy
480 %entry = OpLabel
481 OpBranch %header
482 %header = OpLabel
483 OpLoopMerge %merge %continue None
484 OpBranch %inner_header
485 %inner_header = OpLabel
486 OpSelectionMerge %if_merge None
487 OpBranchConditional %true %then %if_merge
488 %then = OpLabel
489 OpBranch %continue
490 %if_merge = OpLabel
491 OpBranch %continue
492 %continue = OpLabel
493 OpBranchConditional %false %merge %header
494 %merge = OpLabel
495 OpReturn
496 OpFunctionEnd
497 )";
498
499 SinglePassRunAndMatch<BlockMergePass>(text, true);
500 }
501
TEST_F(BlockMergeTest,CannotMergeContinue)502 TEST_F(BlockMergeTest, CannotMergeContinue) {
503 const std::string text = R"(
504 ; CHECK: OpBranch [[loop_header:%\w+]]
505 ; CHECK: [[loop_header]] = OpLabel
506 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[continue:%\w+]]
507 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_header:%\w+]]
508 ; CHECK: [[if_header]] = OpLabel
509 ; CHECK-NEXT: OpSelectionMerge
510 ; CHECK: [[continue]] = OpLabel
511 OpCapability Shader
512 OpMemoryModel Logical GLSL450
513 OpEntryPoint Fragment %func "func"
514 OpExecutionMode %func OriginUpperLeft
515 %void = OpTypeVoid
516 %bool = OpTypeBool
517 %true = OpConstantTrue %bool
518 %false = OpConstantFalse %bool
519 %functy = OpTypeFunction %void
520 %func = OpFunction %void None %functy
521 %entry = OpLabel
522 OpBranch %header
523 %header = OpLabel
524 OpLoopMerge %merge %continue None
525 OpBranchConditional %true %inner_header %merge
526 %inner_header = OpLabel
527 OpSelectionMerge %if_merge None
528 OpBranchConditional %true %then %if_merge
529 %then = OpLabel
530 OpBranch %continue
531 %if_merge = OpLabel
532 OpBranch %continue
533 %continue = OpLabel
534 OpBranchConditional %false %merge %header
535 %merge = OpLabel
536 OpReturn
537 OpFunctionEnd
538 )";
539
540 SinglePassRunAndMatch<BlockMergePass>(text, true);
541 }
542
TEST_F(BlockMergeTest,RemoveStructuredDeclaration)543 TEST_F(BlockMergeTest, RemoveStructuredDeclaration) {
544 // Note: SPIR-V hand edited remove dead branch and add block
545 // before continue block
546 //
547 // #version 140
548 // in vec4 BaseColor;
549 //
550 // void main()
551 // {
552 // while (true) {
553 // break;
554 // }
555 // gl_FragColor = BaseColor;
556 // }
557
558 const std::string assembly =
559 R"(
560 ; CHECK: OpLabel
561 ; CHECK: [[header:%\w+]] = OpLabel
562 ; CHECK-NOT: OpLoopMerge
563 ; CHECK: OpReturn
564 ; CHECK: [[continue:%\w+]] = OpLabel
565 ; CHECK-NEXT: OpBranch [[block:%\w+]]
566 ; CHECK: [[block]] = OpLabel
567 ; CHECK-NEXT: OpBranch [[header]]
568 OpCapability Shader
569 %1 = OpExtInstImport "GLSL.std.450"
570 OpMemoryModel Logical GLSL450
571 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
572 OpExecutionMode %main OriginUpperLeft
573 OpSource GLSL 140
574 OpName %main "main"
575 OpName %gl_FragColor "gl_FragColor"
576 OpName %BaseColor "BaseColor"
577 %void = OpTypeVoid
578 %6 = OpTypeFunction %void
579 %bool = OpTypeBool
580 %true = OpConstantTrue %bool
581 %float = OpTypeFloat 32
582 %v4float = OpTypeVector %float 4
583 %_ptr_Output_v4float = OpTypePointer Output %v4float
584 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
585 %_ptr_Input_v4float = OpTypePointer Input %v4float
586 %BaseColor = OpVariable %_ptr_Input_v4float Input
587 %main = OpFunction %void None %6
588 %13 = OpLabel
589 OpBranch %14
590 %14 = OpLabel
591 OpLoopMerge %15 %16 None
592 OpBranch %17
593 %17 = OpLabel
594 OpBranch %15
595 %18 = OpLabel
596 OpBranch %16
597 %16 = OpLabel
598 OpBranch %14
599 %15 = OpLabel
600 %19 = OpLoad %v4float %BaseColor
601 OpStore %gl_FragColor %19
602 OpReturn
603 OpFunctionEnd
604 )";
605
606 SinglePassRunAndMatch<BlockMergePass>(assembly, true);
607 }
608
TEST_F(BlockMergeTest,DontMergeKill)609 TEST_F(BlockMergeTest, DontMergeKill) {
610 const std::string text = R"(
611 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
612 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
613 ; CHECK: [[ret:%\w+]] = OpLabel
614 ; CHECK-NEXT: OpKill
615 ; CHECK-DAG: [[cont]] = OpLabel
616 ; CHECK-DAG: [[merge]] = OpLabel
617 OpCapability Shader
618 OpMemoryModel Logical GLSL450
619 OpEntryPoint Fragment %func "func"
620 OpExecutionMode %func OriginUpperLeft
621 %void = OpTypeVoid
622 %bool = OpTypeBool
623 %functy = OpTypeFunction %void
624 %func = OpFunction %void None %functy
625 %1 = OpLabel
626 OpBranch %2
627 %2 = OpLabel
628 OpLoopMerge %3 %4 None
629 OpBranch %5
630 %5 = OpLabel
631 OpKill
632 %4 = OpLabel
633 OpBranch %2
634 %3 = OpLabel
635 OpUnreachable
636 OpFunctionEnd
637 )";
638
639 SinglePassRunAndMatch<BlockMergePass>(text, true);
640 }
641
TEST_F(BlockMergeTest,DontMergeUnreachable)642 TEST_F(BlockMergeTest, DontMergeUnreachable) {
643 const std::string text = R"(
644 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
645 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
646 ; CHECK: [[ret:%\w+]] = OpLabel
647 ; CHECK-NEXT: OpUnreachable
648 ; CHECK-DAG: [[cont]] = OpLabel
649 ; CHECK-DAG: [[merge]] = OpLabel
650 OpCapability Shader
651 OpMemoryModel Logical GLSL450
652 OpEntryPoint Fragment %func "func"
653 OpExecutionMode %func OriginUpperLeft
654 %void = OpTypeVoid
655 %bool = OpTypeBool
656 %functy = OpTypeFunction %void
657 %func = OpFunction %void None %functy
658 %1 = OpLabel
659 OpBranch %2
660 %2 = OpLabel
661 OpLoopMerge %3 %4 None
662 OpBranch %5
663 %5 = OpLabel
664 OpUnreachable
665 %4 = OpLabel
666 OpBranch %2
667 %3 = OpLabel
668 OpUnreachable
669 OpFunctionEnd
670 )";
671
672 SinglePassRunAndMatch<BlockMergePass>(text, false);
673 }
674
TEST_F(BlockMergeTest,DontMergeReturn)675 TEST_F(BlockMergeTest, DontMergeReturn) {
676 const std::string text = R"(
677 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
678 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
679 ; CHECK: [[ret:%\w+]] = OpLabel
680 ; CHECK-NEXT: OpReturn
681 ; CHECK-DAG: [[cont]] = OpLabel
682 ; CHECK-DAG: [[merge]] = OpLabel
683 OpCapability Shader
684 OpMemoryModel Logical GLSL450
685 OpEntryPoint Fragment %func "func"
686 OpExecutionMode %func OriginUpperLeft
687 %void = OpTypeVoid
688 %bool = OpTypeBool
689 %functy = OpTypeFunction %void
690 %func = OpFunction %void None %functy
691 %1 = OpLabel
692 OpBranch %2
693 %2 = OpLabel
694 OpLoopMerge %3 %4 None
695 OpBranch %5
696 %5 = OpLabel
697 OpReturn
698 %4 = OpLabel
699 OpBranch %2
700 %3 = OpLabel
701 OpUnreachable
702 OpFunctionEnd
703 )";
704
705 SinglePassRunAndMatch<BlockMergePass>(text, true);
706 }
707
TEST_F(BlockMergeTest,DontMergeSwitch)708 TEST_F(BlockMergeTest, DontMergeSwitch) {
709 const std::string text = R"(
710 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
711 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
712 ; CHECK: [[ret:%\w+]] = OpLabel
713 ; CHECK-NEXT: OpSwitch
714 ; CHECK-DAG: [[cont]] = OpLabel
715 ; CHECK-DAG: [[merge]] = OpLabel
716 OpCapability Shader
717 OpMemoryModel Logical GLSL450
718 OpEntryPoint Fragment %func "func"
719 OpExecutionMode %func OriginUpperLeft
720 %void = OpTypeVoid
721 %bool = OpTypeBool
722 %int = OpTypeInt 32 1
723 %int_0 = OpConstant %int 0
724 %functy = OpTypeFunction %void
725 %func = OpFunction %void None %functy
726 %1 = OpLabel
727 OpBranch %2
728 %2 = OpLabel
729 OpLoopMerge %3 %4 None
730 OpBranch %5
731 %5 = OpLabel
732 OpSwitch %int_0 %6
733 %6 = OpLabel
734 OpReturn
735 %4 = OpLabel
736 OpBranch %2
737 %3 = OpLabel
738 OpUnreachable
739 OpFunctionEnd
740 )";
741
742 SinglePassRunAndMatch<BlockMergePass>(text, true);
743 }
744
TEST_F(BlockMergeTest,DontMergeReturnValue)745 TEST_F(BlockMergeTest, DontMergeReturnValue) {
746 const std::string text = R"(
747 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
748 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
749 ; CHECK: [[ret:%\w+]] = OpLabel
750 ; CHECK-NEXT: OpReturn
751 ; CHECK-DAG: [[cont]] = OpLabel
752 ; CHECK-DAG: [[merge]] = OpLabel
753 OpCapability Shader
754 OpMemoryModel Logical GLSL450
755 OpEntryPoint Fragment %func "func"
756 OpExecutionMode %func OriginUpperLeft
757 %void = OpTypeVoid
758 %bool = OpTypeBool
759 %functy = OpTypeFunction %void
760 %otherfuncty = OpTypeFunction %bool
761 %true = OpConstantTrue %bool
762 %func = OpFunction %void None %functy
763 %1 = OpLabel
764 %2 = OpFunctionCall %bool %3
765 OpReturn
766 OpFunctionEnd
767 %3 = OpFunction %bool None %otherfuncty
768 %4 = OpLabel
769 OpBranch %5
770 %5 = OpLabel
771 OpLoopMerge %6 %7 None
772 OpBranch %8
773 %8 = OpLabel
774 OpReturnValue %true
775 %7 = OpLabel
776 OpBranch %5
777 %6 = OpLabel
778 OpUnreachable
779 OpFunctionEnd
780 )";
781
782 SinglePassRunAndMatch<BlockMergePass>(text, true);
783 }
784
TEST_F(BlockMergeTest,MergeHeaders)785 TEST_F(BlockMergeTest, MergeHeaders) {
786 // Merge two headers when the second is the merge block of the first.
787 const std::string text = R"(
788 ; CHECK: OpFunction
789 ; CHECK-NEXT: OpLabel
790 ; CHECK-NEXT: OpBranch [[header:%\w+]]
791 ; CHECK-NEXT: [[header]] = OpLabel
792 ; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
793 ; CHECK: [[merge]] = OpLabel
794 ; CHEKC: OpReturn
795 OpCapability Shader
796 OpMemoryModel Logical GLSL450
797 OpEntryPoint Fragment %func "func"
798 OpExecutionMode %func OriginUpperLeft
799 %void = OpTypeVoid
800 %bool = OpTypeBool
801 %functy = OpTypeFunction %void
802 %otherfuncty = OpTypeFunction %bool
803 %true = OpConstantTrue %bool
804 %func = OpFunction %void None %functy
805 %1 = OpLabel
806 OpBranch %5
807 %5 = OpLabel
808 OpLoopMerge %8 %7 None
809 OpBranch %8
810 %7 = OpLabel
811 OpBranch %5
812 %8 = OpLabel
813 OpSelectionMerge %m None
814 OpBranchConditional %true %a %m
815 %a = OpLabel
816 OpBranch %m
817 %m = OpLabel
818 OpReturn
819 OpFunctionEnd
820 )";
821
822 SinglePassRunAndMatch<BlockMergePass>(text, true);
823 }
824
TEST_F(BlockMergeTest,OpPhiInSuccessor)825 TEST_F(BlockMergeTest, OpPhiInSuccessor) {
826 // Checks that when merging blocks A and B, the OpPhi at the start of B is
827 // removed and uses of its definition are replaced appropriately.
828 const std::string prefix =
829 R"(OpCapability Shader
830 %1 = OpExtInstImport "GLSL.std.450"
831 OpMemoryModel Logical GLSL450
832 OpEntryPoint Fragment %main "main"
833 OpExecutionMode %main OriginUpperLeft
834 OpSource ESSL 310
835 OpName %main "main"
836 OpName %x "x"
837 OpName %y "y"
838 %void = OpTypeVoid
839 %6 = OpTypeFunction %void
840 %int = OpTypeInt 32 1
841 %_ptr_Function_int = OpTypePointer Function %int
842 %int_1 = OpConstant %int 1
843 %main = OpFunction %void None %6
844 %10 = OpLabel
845 %x = OpVariable %_ptr_Function_int Function
846 %y = OpVariable %_ptr_Function_int Function
847 OpStore %x %int_1
848 %11 = OpLoad %int %x
849 )";
850
851 const std::string suffix_before =
852 R"(OpBranch %12
853 %12 = OpLabel
854 %13 = OpPhi %int %11 %10
855 OpStore %y %13
856 OpReturn
857 OpFunctionEnd
858 )";
859
860 const std::string suffix_after =
861 R"(OpStore %y %11
862 OpReturn
863 OpFunctionEnd
864 )";
865 SinglePassRunAndCheck<BlockMergePass>(prefix + suffix_before,
866 prefix + suffix_after, true, true);
867 }
868
TEST_F(BlockMergeTest,MultipleOpPhisInSuccessor)869 TEST_F(BlockMergeTest, MultipleOpPhisInSuccessor) {
870 // Checks that when merging blocks A and B, the OpPhis at the start of B are
871 // removed and uses of their definitions are replaced appropriately.
872 const std::string prefix =
873 R"(OpCapability Shader
874 %1 = OpExtInstImport "GLSL.std.450"
875 OpMemoryModel Logical GLSL450
876 OpEntryPoint Fragment %main "main"
877 OpExecutionMode %main OriginUpperLeft
878 OpSource ESSL 310
879 OpName %main "main"
880 OpName %S "S"
881 OpMemberName %S 0 "x"
882 OpMemberName %S 1 "f"
883 OpName %s "s"
884 OpName %g "g"
885 OpName %y "y"
886 OpName %t "t"
887 OpName %z "z"
888 %void = OpTypeVoid
889 %10 = OpTypeFunction %void
890 %int = OpTypeInt 32 1
891 %float = OpTypeFloat 32
892 %S = OpTypeStruct %int %float
893 %_ptr_Function_S = OpTypePointer Function %S
894 %int_1 = OpConstant %int 1
895 %float_2 = OpConstant %float 2
896 %16 = OpConstantComposite %S %int_1 %float_2
897 %_ptr_Function_float = OpTypePointer Function %float
898 %_ptr_Function_int = OpTypePointer Function %int
899 %int_3 = OpConstant %int 3
900 %int_0 = OpConstant %int 0
901 %main = OpFunction %void None %10
902 %21 = OpLabel
903 %s = OpVariable %_ptr_Function_S Function
904 %g = OpVariable %_ptr_Function_float Function
905 %y = OpVariable %_ptr_Function_int Function
906 %t = OpVariable %_ptr_Function_S Function
907 %z = OpVariable %_ptr_Function_float Function
908 OpStore %s %16
909 OpStore %g %float_2
910 OpStore %y %int_3
911 %22 = OpLoad %S %s
912 OpStore %t %22
913 %23 = OpAccessChain %_ptr_Function_float %s %int_1
914 %24 = OpLoad %float %23
915 %25 = OpLoad %float %g
916 )";
917
918 const std::string suffix_before =
919 R"(OpBranch %26
920 %26 = OpLabel
921 %27 = OpPhi %float %24 %21
922 %28 = OpPhi %float %25 %21
923 %29 = OpFAdd %float %27 %28
924 %30 = OpAccessChain %_ptr_Function_int %s %int_0
925 %31 = OpLoad %int %30
926 OpBranch %32
927 %32 = OpLabel
928 %33 = OpPhi %float %29 %26
929 %34 = OpPhi %int %31 %26
930 %35 = OpConvertSToF %float %34
931 OpBranch %36
932 %36 = OpLabel
933 %37 = OpPhi %float %35 %32
934 %38 = OpFSub %float %33 %37
935 %39 = OpLoad %int %y
936 OpBranch %40
937 %40 = OpLabel
938 %41 = OpPhi %float %38 %36
939 %42 = OpPhi %int %39 %36
940 %43 = OpConvertSToF %float %42
941 %44 = OpFAdd %float %41 %43
942 OpStore %z %44
943 OpReturn
944 OpFunctionEnd
945 )";
946
947 const std::string suffix_after =
948 R"(%29 = OpFAdd %float %24 %25
949 %30 = OpAccessChain %_ptr_Function_int %s %int_0
950 %31 = OpLoad %int %30
951 %35 = OpConvertSToF %float %31
952 %38 = OpFSub %float %29 %35
953 %39 = OpLoad %int %y
954 %43 = OpConvertSToF %float %39
955 %44 = OpFAdd %float %38 %43
956 OpStore %z %44
957 OpReturn
958 OpFunctionEnd
959 )";
960 SinglePassRunAndCheck<BlockMergePass>(prefix + suffix_before,
961 prefix + suffix_after, true, true);
962 }
963
TEST_F(BlockMergeTest,UnreachableLoop)964 TEST_F(BlockMergeTest, UnreachableLoop) {
965 const std::string spirv = R"(OpCapability Shader
966 %1 = OpExtInstImport "GLSL.std.450"
967 OpMemoryModel Logical GLSL450
968 OpEntryPoint Fragment %main "main"
969 OpExecutionMode %main OriginUpperLeft
970 OpSource ESSL 310
971 OpName %main "main"
972 %void = OpTypeVoid
973 %4 = OpTypeFunction %void
974 %int = OpTypeInt 32 1
975 %_ptr_Function_int = OpTypePointer Function %int
976 %bool = OpTypeBool
977 %false = OpConstantFalse %bool
978 %main = OpFunction %void None %4
979 %9 = OpLabel
980 OpBranch %10
981 %11 = OpLabel
982 OpLoopMerge %12 %13 None
983 OpBranchConditional %false %13 %14
984 %13 = OpLabel
985 OpSelectionMerge %15 None
986 OpBranchConditional %false %16 %17
987 %16 = OpLabel
988 OpBranch %15
989 %17 = OpLabel
990 OpBranch %15
991 %15 = OpLabel
992 OpBranch %11
993 %14 = OpLabel
994 OpReturn
995 %12 = OpLabel
996 OpBranch %10
997 %10 = OpLabel
998 OpReturn
999 OpFunctionEnd
1000 )";
1001
1002 SinglePassRunAndCheck<BlockMergePass>(spirv, spirv, true, true);
1003 }
1004
1005 // TODO(greg-lunarg): Add tests to verify handling of these cases:
1006 //
1007 // More complex control flow
1008 // Others?
1009
1010 } // namespace
1011 } // namespace opt
1012 } // namespace spvtools
1013