• 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,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,DontMergeTerminateInvocation)642 TEST_F(BlockMergeTest, DontMergeTerminateInvocation) {
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: OpTerminateInvocation
648 ; CHECK-DAG: [[cont]] = OpLabel
649 ; CHECK-DAG: [[merge]] = OpLabel
650 OpCapability Shader
651 OpExtension "SPV_KHR_terminate_invocation"
652 OpMemoryModel Logical GLSL450
653 OpEntryPoint Fragment %func "func"
654 OpExecutionMode %func OriginUpperLeft
655 %void = OpTypeVoid
656 %bool = OpTypeBool
657 %functy = OpTypeFunction %void
658 %func = OpFunction %void None %functy
659 %1 = OpLabel
660 OpBranch %2
661 %2 = OpLabel
662 OpLoopMerge %3 %4 None
663 OpBranch %5
664 %5 = OpLabel
665 OpTerminateInvocation
666 %4 = OpLabel
667 OpBranch %2
668 %3 = OpLabel
669 OpUnreachable
670 OpFunctionEnd
671 )";
672 
673   SinglePassRunAndMatch<BlockMergePass>(text, true);
674 }
675 
TEST_F(BlockMergeTest,DontMergeUnreachable)676 TEST_F(BlockMergeTest, DontMergeUnreachable) {
677   const std::string text = R"(
678 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
679 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
680 ; CHECK: [[ret:%\w+]] = OpLabel
681 ; CHECK-NEXT: OpUnreachable
682 ; CHECK-DAG: [[cont]] = OpLabel
683 ; CHECK-DAG: [[merge]] = OpLabel
684 OpCapability Shader
685 OpMemoryModel Logical GLSL450
686 OpEntryPoint Fragment %func "func"
687 OpExecutionMode %func OriginUpperLeft
688 %void = OpTypeVoid
689 %bool = OpTypeBool
690 %functy = OpTypeFunction %void
691 %func = OpFunction %void None %functy
692 %1 = OpLabel
693 OpBranch %2
694 %2 = OpLabel
695 OpLoopMerge %3 %4 None
696 OpBranch %5
697 %5 = OpLabel
698 OpUnreachable
699 %4 = OpLabel
700 OpBranch %2
701 %3 = OpLabel
702 OpUnreachable
703 OpFunctionEnd
704 )";
705 
706   SinglePassRunAndMatch<BlockMergePass>(text, false);
707 }
708 
TEST_F(BlockMergeTest,DontMergeReturn)709 TEST_F(BlockMergeTest, DontMergeReturn) {
710   const std::string text = R"(
711 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
712 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
713 ; CHECK: [[ret:%\w+]] = OpLabel
714 ; CHECK-NEXT: OpReturn
715 ; CHECK-DAG: [[cont]] = OpLabel
716 ; CHECK-DAG: [[merge]] = OpLabel
717 OpCapability Shader
718 OpMemoryModel Logical GLSL450
719 OpEntryPoint Fragment %func "func"
720 OpExecutionMode %func OriginUpperLeft
721 %void = OpTypeVoid
722 %bool = OpTypeBool
723 %functy = OpTypeFunction %void
724 %func = OpFunction %void None %functy
725 %1 = OpLabel
726 OpBranch %2
727 %2 = OpLabel
728 OpLoopMerge %3 %4 None
729 OpBranch %5
730 %5 = OpLabel
731 OpReturn
732 %4 = OpLabel
733 OpBranch %2
734 %3 = OpLabel
735 OpUnreachable
736 OpFunctionEnd
737 )";
738 
739   SinglePassRunAndMatch<BlockMergePass>(text, true);
740 }
741 
TEST_F(BlockMergeTest,DontMergeSwitch)742 TEST_F(BlockMergeTest, DontMergeSwitch) {
743   const std::string text = R"(
744 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
745 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
746 ; CHECK: [[ret:%\w+]] = OpLabel
747 ; CHECK-NEXT: OpSelectionMerge
748 ; CHECK-NEXT: OpSwitch
749 ; CHECK-DAG: [[cont]] = OpLabel
750 ; CHECK-DAG: [[merge]] = OpLabel
751 OpCapability Shader
752 OpMemoryModel Logical GLSL450
753 OpEntryPoint Fragment %func "func"
754 OpExecutionMode %func OriginUpperLeft
755 %void = OpTypeVoid
756 %bool = OpTypeBool
757 %int = OpTypeInt 32 1
758 %int_0 = OpConstant %int 0
759 %functy = OpTypeFunction %void
760 %func = OpFunction %void None %functy
761 %1 = OpLabel
762 OpBranch %2
763 %2 = OpLabel
764 OpLoopMerge %3 %4 None
765 OpBranch %5
766 %5 = OpLabel
767 OpSelectionMerge %6 None
768 OpSwitch %int_0 %6
769 %6 = OpLabel
770 OpReturn
771 %4 = OpLabel
772 OpBranch %2
773 %3 = OpLabel
774 OpUnreachable
775 OpFunctionEnd
776 )";
777 
778   SinglePassRunAndMatch<BlockMergePass>(text, true);
779 }
780 
TEST_F(BlockMergeTest,DontMergeReturnValue)781 TEST_F(BlockMergeTest, DontMergeReturnValue) {
782   const std::string text = R"(
783 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
784 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
785 ; CHECK: [[ret:%\w+]] = OpLabel
786 ; CHECK-NEXT: OpReturn
787 ; CHECK-DAG: [[cont]] = OpLabel
788 ; CHECK-DAG: [[merge]] = OpLabel
789 OpCapability Shader
790 OpMemoryModel Logical GLSL450
791 OpEntryPoint Fragment %func "func"
792 OpExecutionMode %func OriginUpperLeft
793 %void = OpTypeVoid
794 %bool = OpTypeBool
795 %functy = OpTypeFunction %void
796 %otherfuncty = OpTypeFunction %bool
797 %true = OpConstantTrue %bool
798 %func = OpFunction %void None %functy
799 %1 = OpLabel
800 %2 = OpFunctionCall %bool %3
801 OpReturn
802 OpFunctionEnd
803 %3 = OpFunction %bool None %otherfuncty
804 %4 = OpLabel
805 OpBranch %5
806 %5 = OpLabel
807 OpLoopMerge %6 %7 None
808 OpBranch %8
809 %8 = OpLabel
810 OpReturnValue %true
811 %7 = OpLabel
812 OpBranch %5
813 %6 = OpLabel
814 OpUnreachable
815 OpFunctionEnd
816 )";
817 
818   SinglePassRunAndMatch<BlockMergePass>(text, true);
819 }
820 
TEST_F(BlockMergeTest,MergeHeaders)821 TEST_F(BlockMergeTest, MergeHeaders) {
822   // Merge two headers when the second is the merge block of the first.
823   const std::string text = R"(
824 ; CHECK: OpFunction
825 ; CHECK-NEXT: OpLabel
826 ; CHECK-NEXT: OpBranch [[header:%\w+]]
827 ; CHECK-NEXT: [[header]] = OpLabel
828 ; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
829 ; CHECK: [[merge]] = OpLabel
830 ; CHEKC: OpReturn
831 OpCapability Shader
832 OpMemoryModel Logical GLSL450
833 OpEntryPoint Fragment %func "func"
834 OpExecutionMode %func OriginUpperLeft
835 %void = OpTypeVoid
836 %bool = OpTypeBool
837 %functy = OpTypeFunction %void
838 %otherfuncty = OpTypeFunction %bool
839 %true = OpConstantTrue %bool
840 %func = OpFunction %void None %functy
841 %1 = OpLabel
842 OpBranch %5
843 %5 = OpLabel
844 OpLoopMerge %8 %7 None
845 OpBranch %8
846 %7 = OpLabel
847 OpBranch %5
848 %8 = OpLabel
849 OpSelectionMerge %m None
850 OpBranchConditional %true %a %m
851 %a = OpLabel
852 OpBranch %m
853 %m = OpLabel
854 OpReturn
855 OpFunctionEnd
856 )";
857 
858   SinglePassRunAndMatch<BlockMergePass>(text, true);
859 }
860 
TEST_F(BlockMergeTest,OpPhiInSuccessor)861 TEST_F(BlockMergeTest, OpPhiInSuccessor) {
862   // Checks that when merging blocks A and B, the OpPhi at the start of B is
863   // removed and uses of its definition are replaced appropriately.
864   const std::string prefix =
865       R"(OpCapability Shader
866 %1 = OpExtInstImport "GLSL.std.450"
867 OpMemoryModel Logical GLSL450
868 OpEntryPoint Fragment %main "main"
869 OpExecutionMode %main OriginUpperLeft
870 OpSource ESSL 310
871 OpName %main "main"
872 OpName %x "x"
873 OpName %y "y"
874 %void = OpTypeVoid
875 %6 = OpTypeFunction %void
876 %int = OpTypeInt 32 1
877 %_ptr_Function_int = OpTypePointer Function %int
878 %int_1 = OpConstant %int 1
879 %main = OpFunction %void None %6
880 %10 = OpLabel
881 %x = OpVariable %_ptr_Function_int Function
882 %y = OpVariable %_ptr_Function_int Function
883 OpStore %x %int_1
884 %11 = OpLoad %int %x
885 )";
886 
887   const std::string suffix_before =
888       R"(OpBranch %12
889 %12 = OpLabel
890 %13 = OpPhi %int %11 %10
891 OpStore %y %13
892 OpReturn
893 OpFunctionEnd
894 )";
895 
896   const std::string suffix_after =
897       R"(OpStore %y %11
898 OpReturn
899 OpFunctionEnd
900 )";
901   SinglePassRunAndCheck<BlockMergePass>(prefix + suffix_before,
902                                         prefix + suffix_after, true, true);
903 }
904 
TEST_F(BlockMergeTest,MultipleOpPhisInSuccessor)905 TEST_F(BlockMergeTest, MultipleOpPhisInSuccessor) {
906   // Checks that when merging blocks A and B, the OpPhis at the start of B are
907   // removed and uses of their definitions are replaced appropriately.
908   const std::string prefix =
909       R"(OpCapability Shader
910 %1 = OpExtInstImport "GLSL.std.450"
911 OpMemoryModel Logical GLSL450
912 OpEntryPoint Fragment %main "main"
913 OpExecutionMode %main OriginUpperLeft
914 OpSource ESSL 310
915 OpName %main "main"
916 OpName %S "S"
917 OpMemberName %S 0 "x"
918 OpMemberName %S 1 "f"
919 OpName %s "s"
920 OpName %g "g"
921 OpName %y "y"
922 OpName %t "t"
923 OpName %z "z"
924 %void = OpTypeVoid
925 %10 = OpTypeFunction %void
926 %int = OpTypeInt 32 1
927 %float = OpTypeFloat 32
928 %S = OpTypeStruct %int %float
929 %_ptr_Function_S = OpTypePointer Function %S
930 %int_1 = OpConstant %int 1
931 %float_2 = OpConstant %float 2
932 %16 = OpConstantComposite %S %int_1 %float_2
933 %_ptr_Function_float = OpTypePointer Function %float
934 %_ptr_Function_int = OpTypePointer Function %int
935 %int_3 = OpConstant %int 3
936 %int_0 = OpConstant %int 0
937 %main = OpFunction %void None %10
938 %21 = OpLabel
939 %s = OpVariable %_ptr_Function_S Function
940 %g = OpVariable %_ptr_Function_float Function
941 %y = OpVariable %_ptr_Function_int Function
942 %t = OpVariable %_ptr_Function_S Function
943 %z = OpVariable %_ptr_Function_float Function
944 OpStore %s %16
945 OpStore %g %float_2
946 OpStore %y %int_3
947 %22 = OpLoad %S %s
948 OpStore %t %22
949 %23 = OpAccessChain %_ptr_Function_float %s %int_1
950 %24 = OpLoad %float %23
951 %25 = OpLoad %float %g
952 )";
953 
954   const std::string suffix_before =
955       R"(OpBranch %26
956 %26 = OpLabel
957 %27 = OpPhi %float %24 %21
958 %28 = OpPhi %float %25 %21
959 %29 = OpFAdd %float %27 %28
960 %30 = OpAccessChain %_ptr_Function_int %s %int_0
961 %31 = OpLoad %int %30
962 OpBranch %32
963 %32 = OpLabel
964 %33 = OpPhi %float %29 %26
965 %34 = OpPhi %int %31 %26
966 %35 = OpConvertSToF %float %34
967 OpBranch %36
968 %36 = OpLabel
969 %37 = OpPhi %float %35 %32
970 %38 = OpFSub %float %33 %37
971 %39 = OpLoad %int %y
972 OpBranch %40
973 %40 = OpLabel
974 %41 = OpPhi %float %38 %36
975 %42 = OpPhi %int %39 %36
976 %43 = OpConvertSToF %float %42
977 %44 = OpFAdd %float %41 %43
978 OpStore %z %44
979 OpReturn
980 OpFunctionEnd
981 )";
982 
983   const std::string suffix_after =
984       R"(%29 = OpFAdd %float %24 %25
985 %30 = OpAccessChain %_ptr_Function_int %s %int_0
986 %31 = OpLoad %int %30
987 %35 = OpConvertSToF %float %31
988 %38 = OpFSub %float %29 %35
989 %39 = OpLoad %int %y
990 %43 = OpConvertSToF %float %39
991 %44 = OpFAdd %float %38 %43
992 OpStore %z %44
993 OpReturn
994 OpFunctionEnd
995 )";
996   SinglePassRunAndCheck<BlockMergePass>(prefix + suffix_before,
997                                         prefix + suffix_after, true, true);
998 }
999 
TEST_F(BlockMergeTest,UnreachableLoop)1000 TEST_F(BlockMergeTest, UnreachableLoop) {
1001   const std::string spirv = R"(OpCapability Shader
1002 %1 = OpExtInstImport "GLSL.std.450"
1003 OpMemoryModel Logical GLSL450
1004 OpEntryPoint Fragment %main "main"
1005 OpExecutionMode %main OriginUpperLeft
1006 OpSource ESSL 310
1007 OpName %main "main"
1008 %void = OpTypeVoid
1009 %4 = OpTypeFunction %void
1010 %int = OpTypeInt 32 1
1011 %_ptr_Function_int = OpTypePointer Function %int
1012 %bool = OpTypeBool
1013 %false = OpConstantFalse %bool
1014 %main = OpFunction %void None %4
1015 %9 = OpLabel
1016 OpBranch %10
1017 %11 = OpLabel
1018 OpLoopMerge %12 %13 None
1019 OpBranchConditional %false %13 %14
1020 %13 = OpLabel
1021 OpSelectionMerge %15 None
1022 OpBranchConditional %false %16 %17
1023 %16 = OpLabel
1024 OpBranch %15
1025 %17 = OpLabel
1026 OpBranch %15
1027 %15 = OpLabel
1028 OpBranch %11
1029 %14 = OpLabel
1030 OpReturn
1031 %12 = OpLabel
1032 OpBranch %10
1033 %10 = OpLabel
1034 OpReturn
1035 OpFunctionEnd
1036 )";
1037 
1038   SinglePassRunAndCheck<BlockMergePass>(spirv, spirv, true, true);
1039 }
1040 
1041 // TODO(greg-lunarg): Add tests to verify handling of these cases:
1042 //
1043 //    More complex control flow
1044 //    Others?
1045 
1046 }  // namespace
1047 }  // namespace opt
1048 }  // namespace spvtools
1049