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,BlockMergeForLinkage)93 TEST_F(BlockMergeTest, BlockMergeForLinkage) {
94 const std::string before =
95 R"(OpCapability Shader
96 OpCapability Linkage
97 OpMemoryModel Logical GLSL450
98 OpSource HLSL 630
99 OpName %main "main"
100 OpName %BaseColor "BaseColor"
101 OpName %bb_entry "bb.entry"
102 OpName %v "v"
103 OpDecorate %main LinkageAttributes "main" Export
104 %float = OpTypeFloat 32
105 %v4float = OpTypeVector %float 4
106 %_ptr_Function_v4float = OpTypePointer Function %v4float
107 %8 = OpTypeFunction %v4float %_ptr_Function_v4float
108 %main = OpFunction %v4float None %8
109 %BaseColor = OpFunctionParameter %_ptr_Function_v4float
110 %bb_entry = OpLabel
111 %v = OpVariable %_ptr_Function_v4float Function
112 %9 = OpLoad %v4float %BaseColor
113 OpStore %v %9
114 OpBranch %10
115 %10 = OpLabel
116 %11 = OpLoad %v4float %v
117 OpBranch %12
118 %12 = OpLabel
119 OpReturnValue %11
120 OpFunctionEnd
121 )";
122
123 const std::string after =
124 R"(OpCapability Shader
125 OpCapability Linkage
126 OpMemoryModel Logical GLSL450
127 OpSource HLSL 630
128 OpName %main "main"
129 OpName %BaseColor "BaseColor"
130 OpName %bb_entry "bb.entry"
131 OpName %v "v"
132 OpDecorate %main LinkageAttributes "main" Export
133 %float = OpTypeFloat 32
134 %v4float = OpTypeVector %float 4
135 %_ptr_Function_v4float = OpTypePointer Function %v4float
136 %8 = OpTypeFunction %v4float %_ptr_Function_v4float
137 %main = OpFunction %v4float None %8
138 %BaseColor = OpFunctionParameter %_ptr_Function_v4float
139 %bb_entry = OpLabel
140 %v = OpVariable %_ptr_Function_v4float Function
141 %9 = OpLoad %v4float %BaseColor
142 OpStore %v %9
143 %11 = OpLoad %v4float %v
144 OpReturnValue %11
145 OpFunctionEnd
146 )";
147 SinglePassRunAndCheck<BlockMergePass>(before, after, true, true);
148 }
149
TEST_F(BlockMergeTest,EmptyBlock)150 TEST_F(BlockMergeTest, EmptyBlock) {
151 // Note: SPIR-V hand edited to insert empty block
152 // after two statements in main.
153 //
154 // #version 140
155 //
156 // in vec4 BaseColor;
157 //
158 // void main()
159 // {
160 // vec4 v = BaseColor;
161 // gl_FragColor = v;
162 // }
163
164 const std::string predefs =
165 R"(OpCapability Shader
166 %1 = OpExtInstImport "GLSL.std.450"
167 OpMemoryModel Logical GLSL450
168 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
169 OpExecutionMode %main OriginUpperLeft
170 OpSource GLSL 140
171 OpName %main "main"
172 OpName %v "v"
173 OpName %BaseColor "BaseColor"
174 OpName %gl_FragColor "gl_FragColor"
175 %void = OpTypeVoid
176 %7 = OpTypeFunction %void
177 %float = OpTypeFloat 32
178 %v4float = OpTypeVector %float 4
179 %_ptr_Function_v4float = OpTypePointer Function %v4float
180 %_ptr_Input_v4float = OpTypePointer Input %v4float
181 %BaseColor = OpVariable %_ptr_Input_v4float Input
182 %_ptr_Output_v4float = OpTypePointer Output %v4float
183 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
184 )";
185
186 const std::string before =
187 R"(%main = OpFunction %void None %7
188 %13 = OpLabel
189 %v = OpVariable %_ptr_Function_v4float Function
190 %14 = OpLoad %v4float %BaseColor
191 OpStore %v %14
192 OpBranch %15
193 %15 = OpLabel
194 %16 = OpLoad %v4float %v
195 OpStore %gl_FragColor %16
196 OpBranch %17
197 %17 = OpLabel
198 OpBranch %18
199 %18 = OpLabel
200 OpReturn
201 OpFunctionEnd
202 )";
203
204 const std::string after =
205 R"(%main = OpFunction %void None %7
206 %13 = OpLabel
207 %v = OpVariable %_ptr_Function_v4float Function
208 %14 = OpLoad %v4float %BaseColor
209 OpStore %v %14
210 %16 = OpLoad %v4float %v
211 OpStore %gl_FragColor %16
212 OpReturn
213 OpFunctionEnd
214 )";
215
216 SinglePassRunAndCheck<BlockMergePass>(predefs + before, predefs + after, true,
217 true);
218 }
219
TEST_F(BlockMergeTest,NestedInControlFlow)220 TEST_F(BlockMergeTest, NestedInControlFlow) {
221 // Note: SPIR-V hand edited to insert block boundary
222 // between OpFMul and OpStore in then-part.
223 //
224 // #version 140
225 // in vec4 BaseColor;
226 //
227 // layout(std140) uniform U_t
228 // {
229 // bool g_B ;
230 // } ;
231 //
232 // void main()
233 // {
234 // vec4 v = BaseColor;
235 // if (g_B)
236 // vec4 v = v * 0.25;
237 // gl_FragColor = v;
238 // }
239
240 const std::string predefs =
241 R"(OpCapability Shader
242 %1 = OpExtInstImport "GLSL.std.450"
243 OpMemoryModel Logical GLSL450
244 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
245 OpExecutionMode %main OriginUpperLeft
246 OpSource GLSL 140
247 OpName %main "main"
248 OpName %v "v"
249 OpName %BaseColor "BaseColor"
250 OpName %U_t "U_t"
251 OpMemberName %U_t 0 "g_B"
252 OpName %_ ""
253 OpName %v_0 "v"
254 OpName %gl_FragColor "gl_FragColor"
255 OpMemberDecorate %U_t 0 Offset 0
256 OpDecorate %U_t Block
257 OpDecorate %_ DescriptorSet 0
258 %void = OpTypeVoid
259 %10 = OpTypeFunction %void
260 %float = OpTypeFloat 32
261 %v4float = OpTypeVector %float 4
262 %_ptr_Function_v4float = OpTypePointer Function %v4float
263 %_ptr_Input_v4float = OpTypePointer Input %v4float
264 %BaseColor = OpVariable %_ptr_Input_v4float Input
265 %uint = OpTypeInt 32 0
266 %U_t = OpTypeStruct %uint
267 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
268 %_ = OpVariable %_ptr_Uniform_U_t Uniform
269 %int = OpTypeInt 32 1
270 %int_0 = OpConstant %int 0
271 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
272 %bool = OpTypeBool
273 %uint_0 = OpConstant %uint 0
274 %float_0_25 = OpConstant %float 0.25
275 %_ptr_Output_v4float = OpTypePointer Output %v4float
276 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
277 )";
278
279 const std::string before =
280 R"(%main = OpFunction %void None %10
281 %24 = OpLabel
282 %v = OpVariable %_ptr_Function_v4float Function
283 %v_0 = OpVariable %_ptr_Function_v4float Function
284 %25 = OpLoad %v4float %BaseColor
285 OpStore %v %25
286 %26 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
287 %27 = OpLoad %uint %26
288 %28 = OpINotEqual %bool %27 %uint_0
289 OpSelectionMerge %29 None
290 OpBranchConditional %28 %30 %29
291 %30 = OpLabel
292 %31 = OpLoad %v4float %v
293 %32 = OpVectorTimesScalar %v4float %31 %float_0_25
294 OpBranch %33
295 %33 = OpLabel
296 OpStore %v_0 %32
297 OpBranch %29
298 %29 = OpLabel
299 %34 = OpLoad %v4float %v
300 OpStore %gl_FragColor %34
301 OpReturn
302 OpFunctionEnd
303 )";
304
305 const std::string after =
306 R"(%main = OpFunction %void None %10
307 %24 = OpLabel
308 %v = OpVariable %_ptr_Function_v4float Function
309 %v_0 = OpVariable %_ptr_Function_v4float Function
310 %25 = OpLoad %v4float %BaseColor
311 OpStore %v %25
312 %26 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
313 %27 = OpLoad %uint %26
314 %28 = OpINotEqual %bool %27 %uint_0
315 OpSelectionMerge %29 None
316 OpBranchConditional %28 %30 %29
317 %30 = OpLabel
318 %31 = OpLoad %v4float %v
319 %32 = OpVectorTimesScalar %v4float %31 %float_0_25
320 OpStore %v_0 %32
321 OpBranch %29
322 %29 = OpLabel
323 %34 = OpLoad %v4float %v
324 OpStore %gl_FragColor %34
325 OpReturn
326 OpFunctionEnd
327 )";
328
329 SinglePassRunAndCheck<BlockMergePass>(predefs + before, predefs + after, true,
330 true);
331 }
332
TEST_F(BlockMergeTest,PhiInSuccessorOfMergedBlock)333 TEST_F(BlockMergeTest, PhiInSuccessorOfMergedBlock) {
334 const std::string text = R"(
335 ; CHECK: OpSelectionMerge [[merge:%\w+]] None
336 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[then:%\w+]] [[else:%\w+]]
337 ; CHECK: [[then]] = OpLabel
338 ; CHECK-NEXT: OpBranch [[merge]]
339 ; CHECK: [[else]] = OpLabel
340 ; CHECK-NEXT: OpBranch [[merge]]
341 ; CHECK: [[merge]] = OpLabel
342 ; CHECK-NEXT: OpPhi {{%\w+}} %true [[then]] %false [[else]]
343 OpCapability Shader
344 OpMemoryModel Logical GLSL450
345 OpEntryPoint Fragment %func "func"
346 OpExecutionMode %func OriginUpperLeft
347 %void = OpTypeVoid
348 %bool = OpTypeBool
349 %true = OpConstantTrue %bool
350 %false = OpConstantFalse %bool
351 %functy = OpTypeFunction %void
352 %func = OpFunction %void None %functy
353 %entry = OpLabel
354 OpSelectionMerge %merge None
355 OpBranchConditional %true %then %else
356 %then = OpLabel
357 OpBranch %then_next
358 %then_next = OpLabel
359 OpBranch %merge
360 %else = OpLabel
361 OpBranch %merge
362 %merge = OpLabel
363 %phi = OpPhi %bool %true %then_next %false %else
364 OpReturn
365 OpFunctionEnd
366 )";
367
368 SinglePassRunAndMatch<BlockMergePass>(text, true);
369 }
370
TEST_F(BlockMergeTest,UpdateMergeInstruction)371 TEST_F(BlockMergeTest, UpdateMergeInstruction) {
372 const std::string text = R"(
373 ; CHECK: OpSelectionMerge [[merge:%\w+]] None
374 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[then:%\w+]] [[else:%\w+]]
375 ; CHECK: [[then]] = OpLabel
376 ; CHECK-NEXT: OpBranch [[merge]]
377 ; CHECK: [[else]] = OpLabel
378 ; CHECK-NEXT: OpBranch [[merge]]
379 ; CHECK: [[merge]] = OpLabel
380 ; CHECK-NEXT: OpReturn
381 OpCapability Shader
382 OpMemoryModel Logical GLSL450
383 OpEntryPoint Fragment %func "func"
384 OpExecutionMode %func OriginUpperLeft
385 %void = OpTypeVoid
386 %bool = OpTypeBool
387 %true = OpConstantTrue %bool
388 %false = OpConstantFalse %bool
389 %functy = OpTypeFunction %void
390 %func = OpFunction %void None %functy
391 %entry = OpLabel
392 OpSelectionMerge %real_merge None
393 OpBranchConditional %true %then %else
394 %then = OpLabel
395 OpBranch %merge
396 %else = OpLabel
397 OpBranch %merge
398 %merge = OpLabel
399 OpBranch %real_merge
400 %real_merge = OpLabel
401 OpReturn
402 OpFunctionEnd
403 )";
404
405 SinglePassRunAndMatch<BlockMergePass>(text, true);
406 }
407
TEST_F(BlockMergeTest,TwoMergeBlocksCannotBeMerged)408 TEST_F(BlockMergeTest, TwoMergeBlocksCannotBeMerged) {
409 const std::string text = R"(
410 ; CHECK: OpSelectionMerge [[outer_merge:%\w+]] None
411 ; CHECK: OpSelectionMerge [[inner_merge:%\w+]] None
412 ; CHECK: [[inner_merge]] = OpLabel
413 ; CHECK-NEXT: OpBranch [[outer_merge]]
414 ; CHECK: [[outer_merge]] = OpLabel
415 ; CHECK-NEXT: OpReturn
416 OpCapability Shader
417 OpMemoryModel Logical GLSL450
418 OpEntryPoint Fragment %func "func"
419 OpExecutionMode %func OriginUpperLeft
420 %void = OpTypeVoid
421 %bool = OpTypeBool
422 %true = OpConstantTrue %bool
423 %false = OpConstantFalse %bool
424 %functy = OpTypeFunction %void
425 %func = OpFunction %void None %functy
426 %entry = OpLabel
427 OpSelectionMerge %outer_merge None
428 OpBranchConditional %true %then %else
429 %then = OpLabel
430 OpBranch %inner_header
431 %else = OpLabel
432 OpBranch %inner_header
433 %inner_header = OpLabel
434 OpSelectionMerge %inner_merge None
435 OpBranchConditional %true %inner_then %inner_else
436 %inner_then = OpLabel
437 OpBranch %inner_merge
438 %inner_else = OpLabel
439 OpBranch %inner_merge
440 %inner_merge = OpLabel
441 OpBranch %outer_merge
442 %outer_merge = OpLabel
443 OpReturn
444 OpFunctionEnd
445 )";
446
447 SinglePassRunAndMatch<BlockMergePass>(text, true);
448 }
449
TEST_F(BlockMergeTest,MergeContinue)450 TEST_F(BlockMergeTest, MergeContinue) {
451 const std::string text = R"(
452 ; CHECK: OpBranch [[header:%\w+]]
453 ; CHECK: [[header]] = OpLabel
454 ; CHECK-NEXT: OpLogicalAnd
455 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[header]] None
456 ; CHECK-NEXT: OpBranch [[header]]
457 OpCapability Shader
458 OpMemoryModel Logical GLSL450
459 OpEntryPoint Fragment %func "func"
460 OpExecutionMode %func OriginUpperLeft
461 %void = OpTypeVoid
462 %bool = OpTypeBool
463 %true = OpConstantTrue %bool
464 %false = OpConstantFalse %bool
465 %functy = OpTypeFunction %void
466 %func = OpFunction %void None %functy
467 %entry = OpLabel
468 OpBranch %header
469 %header = OpLabel
470 OpLoopMerge %merge %continue None
471 OpBranch %continue
472 %continue = OpLabel
473 %op = OpLogicalAnd %bool %true %false
474 OpBranch %header
475 %merge = OpLabel
476 OpUnreachable
477 OpFunctionEnd
478 )";
479
480 SinglePassRunAndMatch<BlockMergePass>(text, true);
481 }
482
TEST_F(BlockMergeTest,MergeContinueWithOpLine)483 TEST_F(BlockMergeTest, MergeContinueWithOpLine) {
484 const std::string text = R"(
485 ; CHECK: OpBranch [[header:%\w+]]
486 ; CHECK: [[header]] = OpLabel
487 ; CHECK-NEXT: OpLogicalAnd
488 ; CHECK-NEXT: OpLine {{%\w+}} 1 1
489 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[header]] None
490 ; CHECK-NEXT: OpBranch [[header]]
491 OpCapability Shader
492 OpMemoryModel Logical GLSL450
493 OpEntryPoint Fragment %func "func"
494 OpExecutionMode %func OriginUpperLeft
495 %src = OpString "test.shader"
496 %void = OpTypeVoid
497 %bool = OpTypeBool
498 %true = OpConstantTrue %bool
499 %false = OpConstantFalse %bool
500 %functy = OpTypeFunction %void
501 %func = OpFunction %void None %functy
502 %entry = OpLabel
503 OpBranch %header
504 %header = OpLabel
505 OpLoopMerge %merge %continue None
506 OpBranch %continue
507 %continue = OpLabel
508 %op = OpLogicalAnd %bool %true %false
509 OpLine %src 1 1
510 OpBranch %header
511 %merge = OpLabel
512 OpUnreachable
513 OpFunctionEnd
514 )";
515
516 SinglePassRunAndMatch<BlockMergePass>(text, true);
517 }
518
TEST_F(BlockMergeTest,TwoHeadersCannotBeMerged)519 TEST_F(BlockMergeTest, TwoHeadersCannotBeMerged) {
520 const std::string text = R"(
521 ; CHECK: OpBranch [[loop_header:%\w+]]
522 ; CHECK: [[loop_header]] = OpLabel
523 ; CHECK-NEXT: OpLoopMerge
524 ; CHECK-NEXT: OpBranch [[if_header:%\w+]]
525 ; CHECK: [[if_header]] = OpLabel
526 ; CHECK-NEXT: OpSelectionMerge
527 OpCapability Shader
528 OpMemoryModel Logical GLSL450
529 OpEntryPoint Fragment %func "func"
530 OpExecutionMode %func OriginUpperLeft
531 %void = OpTypeVoid
532 %bool = OpTypeBool
533 %true = OpConstantTrue %bool
534 %false = OpConstantFalse %bool
535 %functy = OpTypeFunction %void
536 %func = OpFunction %void None %functy
537 %entry = OpLabel
538 OpBranch %header
539 %header = OpLabel
540 OpLoopMerge %merge %continue None
541 OpBranch %inner_header
542 %inner_header = OpLabel
543 OpSelectionMerge %if_merge None
544 OpBranchConditional %true %then %if_merge
545 %then = OpLabel
546 OpBranch %continue
547 %if_merge = OpLabel
548 OpBranch %continue
549 %continue = OpLabel
550 OpBranchConditional %false %merge %header
551 %merge = OpLabel
552 OpReturn
553 OpFunctionEnd
554 )";
555
556 SinglePassRunAndMatch<BlockMergePass>(text, true);
557 }
558
TEST_F(BlockMergeTest,CannotMergeContinue)559 TEST_F(BlockMergeTest, CannotMergeContinue) {
560 const std::string text = R"(
561 ; CHECK: OpBranch [[loop_header:%\w+]]
562 ; CHECK: [[loop_header]] = OpLabel
563 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[continue:%\w+]]
564 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_header:%\w+]]
565 ; CHECK: [[if_header]] = OpLabel
566 ; CHECK-NEXT: OpSelectionMerge
567 ; CHECK: [[continue]] = OpLabel
568 OpCapability Shader
569 OpMemoryModel Logical GLSL450
570 OpEntryPoint Fragment %func "func"
571 OpExecutionMode %func OriginUpperLeft
572 %void = OpTypeVoid
573 %bool = OpTypeBool
574 %true = OpConstantTrue %bool
575 %false = OpConstantFalse %bool
576 %functy = OpTypeFunction %void
577 %func = OpFunction %void None %functy
578 %entry = OpLabel
579 OpBranch %header
580 %header = OpLabel
581 OpLoopMerge %merge %continue None
582 OpBranchConditional %true %inner_header %merge
583 %inner_header = OpLabel
584 OpSelectionMerge %if_merge None
585 OpBranchConditional %true %then %if_merge
586 %then = OpLabel
587 OpBranch %continue
588 %if_merge = OpLabel
589 OpBranch %continue
590 %continue = OpLabel
591 OpBranchConditional %false %merge %header
592 %merge = OpLabel
593 OpReturn
594 OpFunctionEnd
595 )";
596
597 SinglePassRunAndMatch<BlockMergePass>(text, true);
598 }
599
TEST_F(BlockMergeTest,RemoveStructuredDeclaration)600 TEST_F(BlockMergeTest, RemoveStructuredDeclaration) {
601 // Note: SPIR-V hand edited remove dead branch and add block
602 // before continue block
603 //
604 // #version 140
605 // in vec4 BaseColor;
606 //
607 // void main()
608 // {
609 // while (true) {
610 // break;
611 // }
612 // gl_FragColor = BaseColor;
613 // }
614
615 const std::string assembly =
616 R"(
617 ; CHECK: OpLabel
618 ; CHECK: [[header:%\w+]] = OpLabel
619 ; CHECK-NOT: OpLoopMerge
620 ; CHECK: OpReturn
621 ; CHECK: [[continue:%\w+]] = OpLabel
622 ; CHECK-NEXT: OpBranch [[block:%\w+]]
623 ; CHECK: [[block]] = OpLabel
624 ; CHECK-NEXT: OpBranch [[header]]
625 OpCapability Shader
626 %1 = OpExtInstImport "GLSL.std.450"
627 OpMemoryModel Logical GLSL450
628 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
629 OpExecutionMode %main OriginUpperLeft
630 OpSource GLSL 140
631 OpName %main "main"
632 OpName %gl_FragColor "gl_FragColor"
633 OpName %BaseColor "BaseColor"
634 %void = OpTypeVoid
635 %6 = OpTypeFunction %void
636 %bool = OpTypeBool
637 %true = OpConstantTrue %bool
638 %float = OpTypeFloat 32
639 %v4float = OpTypeVector %float 4
640 %_ptr_Output_v4float = OpTypePointer Output %v4float
641 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
642 %_ptr_Input_v4float = OpTypePointer Input %v4float
643 %BaseColor = OpVariable %_ptr_Input_v4float Input
644 %main = OpFunction %void None %6
645 %13 = OpLabel
646 OpBranch %14
647 %14 = OpLabel
648 OpLoopMerge %15 %16 None
649 OpBranch %17
650 %17 = OpLabel
651 OpBranch %15
652 %18 = OpLabel
653 OpBranch %16
654 %16 = OpLabel
655 OpBranch %14
656 %15 = OpLabel
657 %19 = OpLoad %v4float %BaseColor
658 OpStore %gl_FragColor %19
659 OpReturn
660 OpFunctionEnd
661 )";
662
663 SinglePassRunAndMatch<BlockMergePass>(assembly, true);
664 }
665
TEST_F(BlockMergeTest,DontMergeKill)666 TEST_F(BlockMergeTest, DontMergeKill) {
667 const std::string text = R"(
668 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
669 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
670 ; CHECK: [[ret:%\w+]] = OpLabel
671 ; CHECK-NEXT: OpKill
672 ; CHECK-DAG: [[cont]] = OpLabel
673 ; CHECK-DAG: [[merge]] = OpLabel
674 OpCapability Shader
675 OpMemoryModel Logical GLSL450
676 OpEntryPoint Fragment %func "func"
677 OpExecutionMode %func OriginUpperLeft
678 %void = OpTypeVoid
679 %bool = OpTypeBool
680 %functy = OpTypeFunction %void
681 %func = OpFunction %void None %functy
682 %1 = OpLabel
683 OpBranch %2
684 %2 = OpLabel
685 OpLoopMerge %3 %4 None
686 OpBranch %5
687 %5 = OpLabel
688 OpKill
689 %4 = OpLabel
690 OpBranch %2
691 %3 = OpLabel
692 OpUnreachable
693 OpFunctionEnd
694 )";
695
696 SinglePassRunAndMatch<BlockMergePass>(text, true);
697 }
698
TEST_F(BlockMergeTest,DontMergeTerminateInvocation)699 TEST_F(BlockMergeTest, DontMergeTerminateInvocation) {
700 const std::string text = R"(
701 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
702 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
703 ; CHECK: [[ret:%\w+]] = OpLabel
704 ; CHECK-NEXT: OpTerminateInvocation
705 ; CHECK-DAG: [[cont]] = OpLabel
706 ; CHECK-DAG: [[merge]] = OpLabel
707 OpCapability Shader
708 OpExtension "SPV_KHR_terminate_invocation"
709 OpMemoryModel Logical GLSL450
710 OpEntryPoint Fragment %func "func"
711 OpExecutionMode %func OriginUpperLeft
712 %void = OpTypeVoid
713 %bool = OpTypeBool
714 %functy = OpTypeFunction %void
715 %func = OpFunction %void None %functy
716 %1 = OpLabel
717 OpBranch %2
718 %2 = OpLabel
719 OpLoopMerge %3 %4 None
720 OpBranch %5
721 %5 = OpLabel
722 OpTerminateInvocation
723 %4 = OpLabel
724 OpBranch %2
725 %3 = OpLabel
726 OpUnreachable
727 OpFunctionEnd
728 )";
729
730 SinglePassRunAndMatch<BlockMergePass>(text, true);
731 }
732
TEST_F(BlockMergeTest,DontMergeUnreachable)733 TEST_F(BlockMergeTest, DontMergeUnreachable) {
734 const std::string text = R"(
735 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
736 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
737 ; CHECK: [[ret:%\w+]] = OpLabel
738 ; CHECK-NEXT: OpUnreachable
739 ; CHECK-DAG: [[cont]] = OpLabel
740 ; CHECK-DAG: [[merge]] = OpLabel
741 OpCapability Shader
742 OpMemoryModel Logical GLSL450
743 OpEntryPoint Fragment %func "func"
744 OpExecutionMode %func OriginUpperLeft
745 %void = OpTypeVoid
746 %bool = OpTypeBool
747 %functy = OpTypeFunction %void
748 %func = OpFunction %void None %functy
749 %1 = OpLabel
750 OpBranch %2
751 %2 = OpLabel
752 OpLoopMerge %3 %4 None
753 OpBranch %5
754 %5 = OpLabel
755 OpUnreachable
756 %4 = OpLabel
757 OpBranch %2
758 %3 = OpLabel
759 OpUnreachable
760 OpFunctionEnd
761 )";
762
763 SinglePassRunAndMatch<BlockMergePass>(text, false);
764 }
765
TEST_F(BlockMergeTest,DontMergeReturn)766 TEST_F(BlockMergeTest, DontMergeReturn) {
767 const std::string text = R"(
768 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
769 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
770 ; CHECK: [[ret:%\w+]] = OpLabel
771 ; CHECK-NEXT: OpReturn
772 ; CHECK-DAG: [[cont]] = OpLabel
773 ; CHECK-DAG: [[merge]] = OpLabel
774 OpCapability Shader
775 OpMemoryModel Logical GLSL450
776 OpEntryPoint Fragment %func "func"
777 OpExecutionMode %func OriginUpperLeft
778 %void = OpTypeVoid
779 %bool = OpTypeBool
780 %functy = OpTypeFunction %void
781 %func = OpFunction %void None %functy
782 %1 = OpLabel
783 OpBranch %2
784 %2 = OpLabel
785 OpLoopMerge %3 %4 None
786 OpBranch %5
787 %5 = OpLabel
788 OpReturn
789 %4 = OpLabel
790 OpBranch %2
791 %3 = OpLabel
792 OpUnreachable
793 OpFunctionEnd
794 )";
795
796 SinglePassRunAndMatch<BlockMergePass>(text, true);
797 }
798
TEST_F(BlockMergeTest,DontMergeSwitch)799 TEST_F(BlockMergeTest, DontMergeSwitch) {
800 const std::string text = R"(
801 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
802 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
803 ; CHECK: [[ret:%\w+]] = OpLabel
804 ; CHECK-NEXT: OpSelectionMerge
805 ; CHECK-NEXT: OpSwitch
806 ; CHECK-DAG: [[cont]] = OpLabel
807 ; CHECK-DAG: [[merge]] = OpLabel
808 OpCapability Shader
809 OpMemoryModel Logical GLSL450
810 OpEntryPoint Fragment %func "func"
811 OpExecutionMode %func OriginUpperLeft
812 %void = OpTypeVoid
813 %bool = OpTypeBool
814 %int = OpTypeInt 32 1
815 %int_0 = OpConstant %int 0
816 %functy = OpTypeFunction %void
817 %func = OpFunction %void None %functy
818 %1 = OpLabel
819 OpBranch %2
820 %2 = OpLabel
821 OpLoopMerge %3 %4 None
822 OpBranch %5
823 %5 = OpLabel
824 OpSelectionMerge %6 None
825 OpSwitch %int_0 %6
826 %6 = OpLabel
827 OpReturn
828 %4 = OpLabel
829 OpBranch %2
830 %3 = OpLabel
831 OpUnreachable
832 OpFunctionEnd
833 )";
834
835 SinglePassRunAndMatch<BlockMergePass>(text, true);
836 }
837
TEST_F(BlockMergeTest,DontMergeReturnValue)838 TEST_F(BlockMergeTest, DontMergeReturnValue) {
839 const std::string text = R"(
840 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
841 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
842 ; CHECK: [[ret:%\w+]] = OpLabel
843 ; CHECK-NEXT: OpReturn
844 ; CHECK-DAG: [[cont]] = OpLabel
845 ; CHECK-DAG: [[merge]] = OpLabel
846 OpCapability Shader
847 OpMemoryModel Logical GLSL450
848 OpEntryPoint Fragment %func "func"
849 OpExecutionMode %func OriginUpperLeft
850 %void = OpTypeVoid
851 %bool = OpTypeBool
852 %functy = OpTypeFunction %void
853 %otherfuncty = OpTypeFunction %bool
854 %true = OpConstantTrue %bool
855 %func = OpFunction %void None %functy
856 %1 = OpLabel
857 %2 = OpFunctionCall %bool %3
858 OpReturn
859 OpFunctionEnd
860 %3 = OpFunction %bool None %otherfuncty
861 %4 = OpLabel
862 OpBranch %5
863 %5 = OpLabel
864 OpLoopMerge %6 %7 None
865 OpBranch %8
866 %8 = OpLabel
867 OpReturnValue %true
868 %7 = OpLabel
869 OpBranch %5
870 %6 = OpLabel
871 OpUnreachable
872 OpFunctionEnd
873 )";
874
875 SinglePassRunAndMatch<BlockMergePass>(text, true);
876 }
877
TEST_F(BlockMergeTest,MergeHeaders)878 TEST_F(BlockMergeTest, MergeHeaders) {
879 // Merge two headers when the second is the merge block of the first.
880 const std::string text = R"(
881 ; CHECK: OpFunction
882 ; CHECK-NEXT: OpLabel
883 ; CHECK-NEXT: OpBranch [[header:%\w+]]
884 ; CHECK-NEXT: [[header]] = OpLabel
885 ; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
886 ; CHECK: [[merge]] = OpLabel
887 ; CHECK: OpReturn
888 OpCapability Shader
889 OpMemoryModel Logical GLSL450
890 OpEntryPoint Fragment %func "func"
891 OpExecutionMode %func OriginUpperLeft
892 %void = OpTypeVoid
893 %bool = OpTypeBool
894 %functy = OpTypeFunction %void
895 %otherfuncty = OpTypeFunction %bool
896 %true = OpConstantTrue %bool
897 %func = OpFunction %void None %functy
898 %1 = OpLabel
899 OpBranch %5
900 %5 = OpLabel
901 OpLoopMerge %8 %7 None
902 OpBranch %8
903 %7 = OpLabel
904 OpBranch %5
905 %8 = OpLabel
906 OpSelectionMerge %m None
907 OpBranchConditional %true %a %m
908 %a = OpLabel
909 OpBranch %m
910 %m = OpLabel
911 OpReturn
912 OpFunctionEnd
913 )";
914
915 SinglePassRunAndMatch<BlockMergePass>(text, true);
916 }
917
TEST_F(BlockMergeTest,OpPhiInSuccessor)918 TEST_F(BlockMergeTest, OpPhiInSuccessor) {
919 // Checks that when merging blocks A and B, the OpPhi at the start of B is
920 // removed and uses of its definition are replaced appropriately.
921 const std::string prefix =
922 R"(OpCapability Shader
923 %1 = OpExtInstImport "GLSL.std.450"
924 OpMemoryModel Logical GLSL450
925 OpEntryPoint Fragment %main "main"
926 OpExecutionMode %main OriginUpperLeft
927 OpSource ESSL 310
928 OpName %main "main"
929 OpName %x "x"
930 OpName %y "y"
931 %void = OpTypeVoid
932 %6 = OpTypeFunction %void
933 %int = OpTypeInt 32 1
934 %_ptr_Function_int = OpTypePointer Function %int
935 %int_1 = OpConstant %int 1
936 %main = OpFunction %void None %6
937 %10 = OpLabel
938 %x = OpVariable %_ptr_Function_int Function
939 %y = OpVariable %_ptr_Function_int Function
940 OpStore %x %int_1
941 %11 = OpLoad %int %x
942 )";
943
944 const std::string suffix_before =
945 R"(OpBranch %12
946 %12 = OpLabel
947 %13 = OpPhi %int %11 %10
948 OpStore %y %13
949 OpReturn
950 OpFunctionEnd
951 )";
952
953 const std::string suffix_after =
954 R"(OpStore %y %11
955 OpReturn
956 OpFunctionEnd
957 )";
958 SinglePassRunAndCheck<BlockMergePass>(prefix + suffix_before,
959 prefix + suffix_after, true, true);
960 }
961
TEST_F(BlockMergeTest,MultipleOpPhisInSuccessor)962 TEST_F(BlockMergeTest, MultipleOpPhisInSuccessor) {
963 // Checks that when merging blocks A and B, the OpPhis at the start of B are
964 // removed and uses of their definitions are replaced appropriately.
965 const std::string prefix =
966 R"(OpCapability Shader
967 %1 = OpExtInstImport "GLSL.std.450"
968 OpMemoryModel Logical GLSL450
969 OpEntryPoint Fragment %main "main"
970 OpExecutionMode %main OriginUpperLeft
971 OpSource ESSL 310
972 OpName %main "main"
973 OpName %S "S"
974 OpMemberName %S 0 "x"
975 OpMemberName %S 1 "f"
976 OpName %s "s"
977 OpName %g "g"
978 OpName %y "y"
979 OpName %t "t"
980 OpName %z "z"
981 %void = OpTypeVoid
982 %10 = OpTypeFunction %void
983 %int = OpTypeInt 32 1
984 %float = OpTypeFloat 32
985 %S = OpTypeStruct %int %float
986 %_ptr_Function_S = OpTypePointer Function %S
987 %int_1 = OpConstant %int 1
988 %float_2 = OpConstant %float 2
989 %16 = OpConstantComposite %S %int_1 %float_2
990 %_ptr_Function_float = OpTypePointer Function %float
991 %_ptr_Function_int = OpTypePointer Function %int
992 %int_3 = OpConstant %int 3
993 %int_0 = OpConstant %int 0
994 %main = OpFunction %void None %10
995 %21 = OpLabel
996 %s = OpVariable %_ptr_Function_S Function
997 %g = OpVariable %_ptr_Function_float Function
998 %y = OpVariable %_ptr_Function_int Function
999 %t = OpVariable %_ptr_Function_S Function
1000 %z = OpVariable %_ptr_Function_float Function
1001 OpStore %s %16
1002 OpStore %g %float_2
1003 OpStore %y %int_3
1004 %22 = OpLoad %S %s
1005 OpStore %t %22
1006 %23 = OpAccessChain %_ptr_Function_float %s %int_1
1007 %24 = OpLoad %float %23
1008 %25 = OpLoad %float %g
1009 )";
1010
1011 const std::string suffix_before =
1012 R"(OpBranch %26
1013 %26 = OpLabel
1014 %27 = OpPhi %float %24 %21
1015 %28 = OpPhi %float %25 %21
1016 %29 = OpFAdd %float %27 %28
1017 %30 = OpAccessChain %_ptr_Function_int %s %int_0
1018 %31 = OpLoad %int %30
1019 OpBranch %32
1020 %32 = OpLabel
1021 %33 = OpPhi %float %29 %26
1022 %34 = OpPhi %int %31 %26
1023 %35 = OpConvertSToF %float %34
1024 OpBranch %36
1025 %36 = OpLabel
1026 %37 = OpPhi %float %35 %32
1027 %38 = OpFSub %float %33 %37
1028 %39 = OpLoad %int %y
1029 OpBranch %40
1030 %40 = OpLabel
1031 %41 = OpPhi %float %38 %36
1032 %42 = OpPhi %int %39 %36
1033 %43 = OpConvertSToF %float %42
1034 %44 = OpFAdd %float %41 %43
1035 OpStore %z %44
1036 OpReturn
1037 OpFunctionEnd
1038 )";
1039
1040 const std::string suffix_after =
1041 R"(%29 = OpFAdd %float %24 %25
1042 %30 = OpAccessChain %_ptr_Function_int %s %int_0
1043 %31 = OpLoad %int %30
1044 %35 = OpConvertSToF %float %31
1045 %38 = OpFSub %float %29 %35
1046 %39 = OpLoad %int %y
1047 %43 = OpConvertSToF %float %39
1048 %44 = OpFAdd %float %38 %43
1049 OpStore %z %44
1050 OpReturn
1051 OpFunctionEnd
1052 )";
1053 SinglePassRunAndCheck<BlockMergePass>(prefix + suffix_before,
1054 prefix + suffix_after, true, true);
1055 }
1056
TEST_F(BlockMergeTest,UnreachableLoop)1057 TEST_F(BlockMergeTest, UnreachableLoop) {
1058 const std::string spirv = R"(OpCapability Shader
1059 %1 = OpExtInstImport "GLSL.std.450"
1060 OpMemoryModel Logical GLSL450
1061 OpEntryPoint Fragment %main "main"
1062 OpExecutionMode %main OriginUpperLeft
1063 OpSource ESSL 310
1064 OpName %main "main"
1065 %void = OpTypeVoid
1066 %4 = OpTypeFunction %void
1067 %int = OpTypeInt 32 1
1068 %_ptr_Function_int = OpTypePointer Function %int
1069 %bool = OpTypeBool
1070 %false = OpConstantFalse %bool
1071 %main = OpFunction %void None %4
1072 %9 = OpLabel
1073 OpBranch %10
1074 %11 = OpLabel
1075 OpLoopMerge %12 %13 None
1076 OpBranchConditional %false %13 %14
1077 %13 = OpLabel
1078 OpSelectionMerge %15 None
1079 OpBranchConditional %false %16 %17
1080 %16 = OpLabel
1081 OpBranch %15
1082 %17 = OpLabel
1083 OpBranch %15
1084 %15 = OpLabel
1085 OpBranch %11
1086 %14 = OpLabel
1087 OpReturn
1088 %12 = OpLabel
1089 OpBranch %10
1090 %10 = OpLabel
1091 OpReturn
1092 OpFunctionEnd
1093 )";
1094
1095 SinglePassRunAndCheck<BlockMergePass>(spirv, spirv, true, true);
1096 }
1097
TEST_F(BlockMergeTest,DebugMerge)1098 TEST_F(BlockMergeTest, DebugMerge) {
1099 // Verify merge can be done completely, cleanly and validly in presence of
1100 // NonSemantic.Shader.DebugInfo.100 instructions
1101 const std::string text = R"(
1102 ; CHECK: OpLoopMerge
1103 ; CHECK-NEXT: OpBranch
1104 ; CHECK-NOT: OpBranch
1105 OpCapability Shader
1106 OpExtension "SPV_KHR_non_semantic_info"
1107 %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
1108 OpMemoryModel Logical GLSL450
1109 OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
1110 OpExecutionMode %main OriginUpperLeft
1111 %5 = OpString "lexblock.hlsl"
1112 %20 = OpString "float"
1113 %32 = OpString "main"
1114 %33 = OpString ""
1115 %46 = OpString "b"
1116 %49 = OpString "a"
1117 %58 = OpString "c"
1118 %63 = OpString "color"
1119 OpName %in_var_COLOR "in.var.COLOR"
1120 OpName %out_var_SV_TARGET "out.var.SV_TARGET"
1121 OpName %main "main"
1122 OpDecorate %in_var_COLOR Location 0
1123 OpDecorate %out_var_SV_TARGET Location 0
1124 %float = OpTypeFloat 32
1125 %float_0 = OpConstant %float 0
1126 %v4float = OpTypeVector %float 4
1127 %9 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1128 %float_1 = OpConstant %float 1
1129 %13 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1130 %uint = OpTypeInt 32 0
1131 %uint_32 = OpConstant %uint 32
1132 %_ptr_Input_v4float = OpTypePointer Input %v4float
1133 %_ptr_Output_v4float = OpTypePointer Output %v4float
1134 %void = OpTypeVoid
1135 %uint_3 = OpConstant %uint 3
1136 %uint_0 = OpConstant %uint 0
1137 %uint_4 = OpConstant %uint 4
1138 %uint_1 = OpConstant %uint 1
1139 %uint_5 = OpConstant %uint 5
1140 %uint_12 = OpConstant %uint 12
1141 %uint_13 = OpConstant %uint 13
1142 %uint_20 = OpConstant %uint 20
1143 %uint_15 = OpConstant %uint 15
1144 %uint_17 = OpConstant %uint 17
1145 %uint_16 = OpConstant %uint 16
1146 %uint_14 = OpConstant %uint 14
1147 %uint_10 = OpConstant %uint 10
1148 %65 = OpTypeFunction %void
1149 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
1150 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
1151 %62 = OpExtInst %void %1 DebugExpression
1152 %22 = OpExtInst %void %1 DebugTypeBasic %20 %uint_32 %uint_3 %uint_0
1153 %25 = OpExtInst %void %1 DebugTypeVector %22 %uint_4
1154 %27 = OpExtInst %void %1 DebugTypeFunction %uint_3 %25 %25
1155 %28 = OpExtInst %void %1 DebugSource %5
1156 %29 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %28 %uint_5
1157 %34 = OpExtInst %void %1 DebugFunction %32 %27 %28 %uint_12 %uint_1 %29 %33 %uint_3 %uint_13
1158 %37 = OpExtInst %void %1 DebugLexicalBlock %28 %uint_13 %uint_1 %34
1159 %52 = OpExtInst %void %1 DebugLexicalBlock %28 %uint_15 %uint_12 %37
1160 %54 = OpExtInst %void %1 DebugLocalVariable %46 %25 %28 %uint_17 %uint_12 %52 %uint_4
1161 %56 = OpExtInst %void %1 DebugLocalVariable %49 %25 %28 %uint_16 %uint_12 %52 %uint_4
1162 %59 = OpExtInst %void %1 DebugLocalVariable %58 %25 %28 %uint_14 %uint_10 %37 %uint_4
1163 %64 = OpExtInst %void %1 DebugLocalVariable %63 %25 %28 %uint_12 %uint_20 %34 %uint_4 %uint_1
1164 %main = OpFunction %void None %65
1165 %66 = OpLabel
1166 %69 = OpLoad %v4float %in_var_COLOR
1167 %168 = OpExtInst %void %1 DebugValue %64 %69 %62
1168 %169 = OpExtInst %void %1 DebugScope %37
1169 OpLine %5 14 10
1170 %164 = OpExtInst %void %1 DebugValue %59 %9 %62
1171 OpLine %5 15 3
1172 OpBranch %150
1173 %150 = OpLabel
1174 %165 = OpPhi %v4float %9 %66 %158 %159
1175 %167 = OpExtInst %void %1 DebugValue %59 %165 %62
1176 %170 = OpExtInst %void %1 DebugScope %37
1177 OpLine %5 15 12
1178 %171 = OpExtInst %void %1 DebugNoScope
1179 OpLoopMerge %160 %159 None
1180 OpBranch %151
1181 %151 = OpLabel
1182 OpLine %5 16 12
1183 %162 = OpExtInst %void %1 DebugValue %56 %9 %62
1184 OpLine %5 17 12
1185 %163 = OpExtInst %void %1 DebugValue %54 %13 %62
1186 OpLine %5 18 15
1187 %158 = OpFAdd %v4float %165 %13
1188 OpLine %5 18 5
1189 %166 = OpExtInst %void %1 DebugValue %59 %158 %62
1190 %172 = OpExtInst %void %1 DebugScope %37
1191 OpLine %5 19 3
1192 OpBranch %159
1193 %159 = OpLabel
1194 OpLine %5 19 3
1195 OpBranch %150
1196 %160 = OpLabel
1197 OpUnreachable
1198 OpFunctionEnd
1199 )";
1200
1201 SinglePassRunAndMatch<BlockMergePass>(text, true);
1202 }
1203
1204 // TODO(greg-lunarg): Add tests to verify handling of these cases:
1205 //
1206 // More complex control flow
1207 // Others?
1208
1209 } // namespace
1210 } // namespace opt
1211 } // namespace spvtools
1212