1 // Copyright (c) 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <string>
16 
17 #include "gmock/gmock.h"
18 #include "spirv-tools/libspirv.hpp"
19 #include "spirv-tools/optimizer.hpp"
20 #include "test/opt/pass_fixture.h"
21 #include "test/opt/pass_utils.h"
22 
23 namespace spvtools {
24 namespace opt {
25 namespace {
26 
27 using MergeReturnPassTest = PassTest<::testing::Test>;
28 
TEST_F(MergeReturnPassTest,OneReturn)29 TEST_F(MergeReturnPassTest, OneReturn) {
30   const std::string before =
31       R"(OpCapability Addresses
32 OpCapability Kernel
33 OpCapability GenericPointer
34 OpCapability Linkage
35 OpMemoryModel Physical32 OpenCL
36 OpEntryPoint Kernel %1 "simple_kernel"
37 %2 = OpTypeVoid
38 %3 = OpTypeFunction %2
39 %1 = OpFunction %2 None %3
40 %4 = OpLabel
41 OpReturn
42 OpFunctionEnd
43 )";
44 
45   const std::string after = before;
46 
47   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
48   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
49   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
50 }
51 
TEST_F(MergeReturnPassTest,TwoReturnsNoValue)52 TEST_F(MergeReturnPassTest, TwoReturnsNoValue) {
53   const std::string before =
54       R"(OpCapability Addresses
55 OpCapability Kernel
56 OpCapability GenericPointer
57 OpCapability Linkage
58 OpMemoryModel Physical32 OpenCL
59 OpEntryPoint Kernel %6 "simple_kernel"
60 %2 = OpTypeVoid
61 %3 = OpTypeBool
62 %4 = OpConstantFalse %3
63 %1 = OpTypeFunction %2
64 %6 = OpFunction %2 None %1
65 %7 = OpLabel
66 OpBranchConditional %4 %8 %9
67 %8 = OpLabel
68 OpReturn
69 %9 = OpLabel
70 OpReturn
71 OpFunctionEnd
72 )";
73 
74   const std::string after =
75       R"(OpCapability Addresses
76 OpCapability Kernel
77 OpCapability GenericPointer
78 OpCapability Linkage
79 OpMemoryModel Physical32 OpenCL
80 OpEntryPoint Kernel %6 "simple_kernel"
81 %2 = OpTypeVoid
82 %3 = OpTypeBool
83 %4 = OpConstantFalse %3
84 %1 = OpTypeFunction %2
85 %6 = OpFunction %2 None %1
86 %7 = OpLabel
87 OpBranchConditional %4 %8 %9
88 %8 = OpLabel
89 OpBranch %10
90 %9 = OpLabel
91 OpBranch %10
92 %10 = OpLabel
93 OpReturn
94 OpFunctionEnd
95 )";
96 
97   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
98   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
99   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
100 }
101 
TEST_F(MergeReturnPassTest,DebugTwoReturnsNoValue)102 TEST_F(MergeReturnPassTest, DebugTwoReturnsNoValue) {
103   const std::string before =
104       R"(OpCapability Addresses
105 OpCapability Kernel
106 OpCapability GenericPointer
107 OpCapability Linkage
108 %10 = OpExtInstImport "OpenCL.DebugInfo.100"
109 OpMemoryModel Physical32 OpenCL
110 OpEntryPoint Kernel %6 "simple_kernel"
111 %11 = OpString "test"
112 %2 = OpTypeVoid
113 %3 = OpTypeBool
114 %4 = OpConstantFalse %3
115 %1 = OpTypeFunction %2
116 %12 = OpExtInst %2 %10 DebugSource %11
117 %13 = OpExtInst %2 %10 DebugCompilationUnit 1 4 %12 HLSL
118 %14 = OpExtInst %2 %10 DebugTypeFunction FlagIsProtected|FlagIsPrivate %2
119 %15 = OpExtInst %2 %10 DebugFunction %11 %14 %12 0 0 %13 %11 FlagIsProtected|FlagIsPrivate 0 %6
120 %6 = OpFunction %2 None %1
121 %7 = OpLabel
122 OpBranchConditional %4 %8 %9
123 %8 = OpLabel
124 %16 = OpExtInst %2 %10 DebugScope %15
125 OpLine %11 100 0
126 OpReturn
127 %9 = OpLabel
128 %17 = OpExtInst %2 %10 DebugScope %13
129 OpLine %11 200 0
130 OpReturn
131 OpFunctionEnd
132 )";
133 
134   const std::string after =
135       R"(OpCapability Addresses
136 OpCapability Kernel
137 OpCapability GenericPointer
138 OpCapability Linkage
139 %10 = OpExtInstImport "OpenCL.DebugInfo.100"
140 OpMemoryModel Physical32 OpenCL
141 OpEntryPoint Kernel %6 "simple_kernel"
142 %11 = OpString "test"
143 %2 = OpTypeVoid
144 %3 = OpTypeBool
145 %4 = OpConstantFalse %3
146 %1 = OpTypeFunction %2
147 %12 = OpExtInst %2 %10 DebugSource %11
148 %13 = OpExtInst %2 %10 DebugCompilationUnit 1 4 %12 HLSL
149 %14 = OpExtInst %2 %10 DebugTypeFunction FlagIsProtected|FlagIsPrivate %2
150 %15 = OpExtInst %2 %10 DebugFunction %11 %14 %12 0 0 %13 %11 FlagIsProtected|FlagIsPrivate 0 %6
151 %6 = OpFunction %2 None %1
152 %7 = OpLabel
153 OpBranchConditional %4 %8 %9
154 %8 = OpLabel
155 %19 = OpExtInst %2 %10 DebugScope %15
156 OpLine %11 100 0
157 OpBranch %18
158 %20 = OpExtInst %2 %10 DebugNoScope
159 %9 = OpLabel
160 %21 = OpExtInst %2 %10 DebugScope %13
161 OpLine %11 200 0
162 OpBranch %18
163 %22 = OpExtInst %2 %10 DebugNoScope
164 %18 = OpLabel
165 OpReturn
166 OpFunctionEnd
167 )";
168 
169   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
170   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
171   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
172 }
173 
TEST_F(MergeReturnPassTest,TwoReturnsWithValues)174 TEST_F(MergeReturnPassTest, TwoReturnsWithValues) {
175   const std::string before =
176       R"(OpCapability Linkage
177 OpCapability Kernel
178 OpMemoryModel Logical OpenCL
179 OpDecorate %7 LinkageAttributes "simple_kernel" Export
180 %1 = OpTypeInt 32 0
181 %2 = OpTypeBool
182 %3 = OpConstantFalse %2
183 %4 = OpConstant %1 0
184 %5 = OpConstant %1 1
185 %6 = OpTypeFunction %1
186 %7 = OpFunction %1 None %6
187 %8 = OpLabel
188 OpBranchConditional %3 %9 %10
189 %9 = OpLabel
190 OpReturnValue %4
191 %10 = OpLabel
192 OpReturnValue %5
193 OpFunctionEnd
194 )";
195 
196   const std::string after =
197       R"(OpCapability Linkage
198 OpCapability Kernel
199 OpMemoryModel Logical OpenCL
200 OpDecorate %7 LinkageAttributes "simple_kernel" Export
201 %1 = OpTypeInt 32 0
202 %2 = OpTypeBool
203 %3 = OpConstantFalse %2
204 %4 = OpConstant %1 0
205 %5 = OpConstant %1 1
206 %6 = OpTypeFunction %1
207 %7 = OpFunction %1 None %6
208 %8 = OpLabel
209 OpBranchConditional %3 %9 %10
210 %9 = OpLabel
211 OpBranch %11
212 %10 = OpLabel
213 OpBranch %11
214 %11 = OpLabel
215 %12 = OpPhi %1 %4 %9 %5 %10
216 OpReturnValue %12
217 OpFunctionEnd
218 )";
219 
220   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
221   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
222   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
223 }
224 
TEST_F(MergeReturnPassTest,UnreachableReturnsNoValue)225 TEST_F(MergeReturnPassTest, UnreachableReturnsNoValue) {
226   const std::string before =
227       R"(OpCapability Addresses
228 OpCapability Kernel
229 OpCapability GenericPointer
230 OpCapability Linkage
231 OpMemoryModel Physical32 OpenCL
232 OpEntryPoint Kernel %6 "simple_kernel"
233 %2 = OpTypeVoid
234 %3 = OpTypeBool
235 %4 = OpConstantFalse %3
236 %1 = OpTypeFunction %2
237 %6 = OpFunction %2 None %1
238 %7 = OpLabel
239 OpReturn
240 %8 = OpLabel
241 OpBranchConditional %4 %9 %10
242 %9 = OpLabel
243 OpReturn
244 %10 = OpLabel
245 OpReturn
246 OpFunctionEnd
247 )";
248 
249   const std::string after =
250       R"(OpCapability Addresses
251 OpCapability Kernel
252 OpCapability GenericPointer
253 OpCapability Linkage
254 OpMemoryModel Physical32 OpenCL
255 OpEntryPoint Kernel %6 "simple_kernel"
256 %2 = OpTypeVoid
257 %3 = OpTypeBool
258 %4 = OpConstantFalse %3
259 %1 = OpTypeFunction %2
260 %6 = OpFunction %2 None %1
261 %7 = OpLabel
262 OpBranch %11
263 %8 = OpLabel
264 OpBranchConditional %4 %9 %10
265 %9 = OpLabel
266 OpBranch %11
267 %10 = OpLabel
268 OpBranch %11
269 %11 = OpLabel
270 OpReturn
271 OpFunctionEnd
272 )";
273 
274   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
275   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
276   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
277 }
278 
TEST_F(MergeReturnPassTest,UnreachableReturnsWithValues)279 TEST_F(MergeReturnPassTest, UnreachableReturnsWithValues) {
280   const std::string before =
281       R"(OpCapability Linkage
282 OpCapability Kernel
283 OpMemoryModel Logical OpenCL
284 OpDecorate %7 LinkageAttributes "simple_kernel" Export
285 %1 = OpTypeInt 32 0
286 %2 = OpTypeBool
287 %3 = OpConstantFalse %2
288 %4 = OpConstant %1 0
289 %5 = OpConstant %1 1
290 %6 = OpTypeFunction %1
291 %7 = OpFunction %1 None %6
292 %8 = OpLabel
293 %9 = OpIAdd %1 %4 %5
294 OpReturnValue %9
295 %10 = OpLabel
296 OpBranchConditional %3 %11 %12
297 %11 = OpLabel
298 OpReturnValue %4
299 %12 = OpLabel
300 OpReturnValue %5
301 OpFunctionEnd
302 )";
303 
304   const std::string after =
305       R"(OpCapability Linkage
306 OpCapability Kernel
307 OpMemoryModel Logical OpenCL
308 OpDecorate %7 LinkageAttributes "simple_kernel" Export
309 %1 = OpTypeInt 32 0
310 %2 = OpTypeBool
311 %3 = OpConstantFalse %2
312 %4 = OpConstant %1 0
313 %5 = OpConstant %1 1
314 %6 = OpTypeFunction %1
315 %7 = OpFunction %1 None %6
316 %8 = OpLabel
317 %9 = OpIAdd %1 %4 %5
318 OpBranch %13
319 %10 = OpLabel
320 OpBranchConditional %3 %11 %12
321 %11 = OpLabel
322 OpBranch %13
323 %12 = OpLabel
324 OpBranch %13
325 %13 = OpLabel
326 %14 = OpPhi %1 %9 %8 %4 %11 %5 %12
327 OpReturnValue %14
328 OpFunctionEnd
329 )";
330 
331   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
332   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
333   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
334 }
335 
TEST_F(MergeReturnPassTest,DebugUnreachableReturnsWithValues)336 TEST_F(MergeReturnPassTest, DebugUnreachableReturnsWithValues) {
337   const std::string before =
338       R"(OpCapability Linkage
339 OpCapability Kernel
340 %13 = OpExtInstImport "OpenCL.DebugInfo.100"
341 OpMemoryModel Logical OpenCL
342 %14 = OpString "test"
343 OpDecorate %7 LinkageAttributes "simple_kernel" Export
344 %1 = OpTypeInt 32 0
345 %20 = OpTypeVoid
346 %2 = OpTypeBool
347 %3 = OpConstantFalse %2
348 %4 = OpConstant %1 0
349 %5 = OpConstant %1 1
350 %6 = OpTypeFunction %1
351 %15 = OpExtInst %20 %13 DebugSource %14
352 %16 = OpExtInst %20 %13 DebugCompilationUnit 1 4 %15 HLSL
353 %17 = OpExtInst %20 %13 DebugTypeFunction FlagIsProtected|FlagIsPrivate %20
354 %18 = OpExtInst %20 %13 DebugFunction %14 %17 %15 0 0 %16 %14 FlagIsProtected|FlagIsPrivate 0 %7
355 %7 = OpFunction %1 None %6
356 %8 = OpLabel
357 %9 = OpIAdd %1 %4 %5
358 %19 = OpExtInst %20 %13 DebugScope %18
359 OpLine %14 100 0
360 OpReturnValue %9
361 %10 = OpLabel
362 OpBranchConditional %3 %11 %12
363 %11 = OpLabel
364 %21 = OpExtInst %20 %13 DebugScope %16
365 OpLine %14 200 0
366 OpReturnValue %4
367 %12 = OpLabel
368 %22 = OpExtInst %20 %13 DebugScope %18
369 OpLine %14 300 0
370 OpReturnValue %5
371 OpFunctionEnd
372 )";
373 
374   const std::string after =
375       R"(OpCapability Linkage
376 OpCapability Kernel
377 %13 = OpExtInstImport "OpenCL.DebugInfo.100"
378 OpMemoryModel Logical OpenCL
379 %14 = OpString "test"
380 OpDecorate %7 LinkageAttributes "simple_kernel" Export
381 %1 = OpTypeInt 32 0
382 %20 = OpTypeVoid
383 %2 = OpTypeBool
384 %3 = OpConstantFalse %2
385 %4 = OpConstant %1 0
386 %5 = OpConstant %1 1
387 %6 = OpTypeFunction %1
388 %15 = OpExtInst %20 %13 DebugSource %14
389 %16 = OpExtInst %20 %13 DebugCompilationUnit 1 4 %15 HLSL
390 %17 = OpExtInst %20 %13 DebugTypeFunction FlagIsProtected|FlagIsPrivate %20
391 %18 = OpExtInst %20 %13 DebugFunction %14 %17 %15 0 0 %16 %14 FlagIsProtected|FlagIsPrivate 0 %7
392 %7 = OpFunction %1 None %6
393 %8 = OpLabel
394 %9 = OpIAdd %1 %4 %5
395 %25 = OpExtInst %20 %13 DebugScope %18
396 OpLine %14 100 0
397 OpBranch %23
398 %26 = OpExtInst %20 %13 DebugNoScope
399 %10 = OpLabel
400 OpBranchConditional %3 %11 %12
401 %11 = OpLabel
402 %27 = OpExtInst %20 %13 DebugScope %16
403 OpLine %14 200 0
404 OpBranch %23
405 %28 = OpExtInst %20 %13 DebugNoScope
406 %12 = OpLabel
407 %29 = OpExtInst %20 %13 DebugScope %18
408 OpLine %14 300 0
409 OpBranch %23
410 %30 = OpExtInst %20 %13 DebugNoScope
411 %23 = OpLabel
412 %24 = OpPhi %1 %9 %8 %4 %11 %5 %12
413 OpReturnValue %24
414 OpFunctionEnd
415 )";
416 
417   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
418   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
419   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
420 }
421 
TEST_F(MergeReturnPassTest,StructuredControlFlowWithUnreachableMerge)422 TEST_F(MergeReturnPassTest, StructuredControlFlowWithUnreachableMerge) {
423   const std::string before =
424       R"(
425 ; CHECK: [[false:%\w+]] = OpConstantFalse
426 ; CHECK: [[true:%\w+]] = OpConstantTrue
427 ; CHECK: OpFunction
428 ; CHECK: [[var:%\w+]] = OpVariable [[:%\w+]] Function [[false]]
429 ; CHECK: OpSelectionMerge [[return_block:%\w+]]
430 ; CHECK: OpSelectionMerge [[merge_lab:%\w+]]
431 ; CHECK: OpBranchConditional [[cond:%\w+]] [[if_lab:%\w+]] [[then_lab:%\w+]]
432 ; CHECK: [[if_lab]] = OpLabel
433 ; CHECK-NEXT: OpStore [[var]] [[true]]
434 ; CHECK-NEXT: OpBranch [[return_block]]
435 ; CHECK: [[then_lab]] = OpLabel
436 ; CHECK-NEXT: OpStore [[var]] [[true]]
437 ; CHECK-NEXT: OpBranch [[return_block]]
438 ; CHECK: [[merge_lab]] = OpLabel
439 ; CHECK-NEXT: OpBranch [[return_block]]
440 ; CHECK: [[return_block]] = OpLabel
441 ; CHECK-NEXT: OpReturn
442 OpCapability Addresses
443 OpCapability Shader
444 OpCapability Linkage
445 OpMemoryModel Logical GLSL450
446 OpEntryPoint GLCompute %6 "simple_shader"
447 %2 = OpTypeVoid
448 %3 = OpTypeBool
449 %4 = OpConstantFalse %3
450 %1 = OpTypeFunction %2
451 %6 = OpFunction %2 None %1
452 %7 = OpLabel
453 OpSelectionMerge %10 None
454 OpBranchConditional %4 %8 %9
455 %8 = OpLabel
456 OpReturn
457 %9 = OpLabel
458 OpReturn
459 %10 = OpLabel
460 OpUnreachable
461 OpFunctionEnd
462 )";
463 
464   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
465   SinglePassRunAndMatch<MergeReturnPass>(before, false);
466 }
467 
TEST_F(MergeReturnPassTest,DebugStructuredControlFlowWithUnreachableMerge)468 TEST_F(MergeReturnPassTest, DebugStructuredControlFlowWithUnreachableMerge) {
469   const std::string before =
470       R"(
471 ; CHECK: [[false:%\w+]] = OpConstantFalse
472 ; CHECK: [[true:%\w+]] = OpConstantTrue
473 ; CHECK: OpFunction
474 ; CHECK: [[var:%\w+]] = OpVariable [[:%\w+]] Function [[false]]
475 ; CHECK: OpSelectionMerge [[return_block:%\w+]]
476 ; CHECK: OpSelectionMerge [[merge_lab:%\w+]]
477 ; CHECK: OpBranchConditional [[cond:%\w+]] [[if_lab:%\w+]] [[then_lab:%\w+]]
478 ; CHECK: [[if_lab]] = OpLabel
479 ; CHECK-NEXT: OpStore [[var]] [[true]]
480 ; CHECK-NEXT: DebugScope
481 ; CHECK-NEXT: OpLine {{%\d+}} 100 0
482 ; CHECK-NEXT: OpBranch [[return_block]]
483 ; CHECK: [[then_lab]] = OpLabel
484 ; CHECK-NEXT: OpStore [[var]] [[true]]
485 ; CHECK-NEXT: DebugScope
486 ; CHECK-NEXT: OpLine {{%\d+}} 200 0
487 ; CHECK-NEXT: OpBranch [[return_block]]
488 ; CHECK: [[merge_lab]] = OpLabel
489 ; CHECK-NEXT: DebugScope
490 ; CHECK-NEXT: OpLine {{%\d+}} 300 0
491 ; CHECK-NEXT: OpBranch [[return_block]]
492 ; CHECK: [[return_block]] = OpLabel
493 ; CHECK-NEXT: OpReturn
494 OpCapability Addresses
495 OpCapability Shader
496 OpCapability Linkage
497 %12 = OpExtInstImport "OpenCL.DebugInfo.100"
498 OpMemoryModel Logical GLSL450
499 OpEntryPoint GLCompute %6 "simple_shader"
500 %11 = OpString "test"
501 %2 = OpTypeVoid
502 %3 = OpTypeBool
503 %4 = OpConstantFalse %3
504 %1 = OpTypeFunction %2
505 %13 = OpExtInst %2 %12 DebugSource %11
506 %14 = OpExtInst %2 %12 DebugCompilationUnit 1 4 %13 HLSL
507 %6 = OpFunction %2 None %1
508 %7 = OpLabel
509 OpSelectionMerge %10 None
510 OpBranchConditional %4 %8 %9
511 %8 = OpLabel
512 %15 = OpExtInst %2 %12 DebugScope %14
513 OpLine %11 100 0
514 OpReturn
515 %9 = OpLabel
516 %16 = OpExtInst %2 %12 DebugScope %14
517 OpLine %11 200 0
518 OpReturn
519 %10 = OpLabel
520 %17 = OpExtInst %2 %12 DebugScope %14
521 OpLine %11 300 0
522 OpUnreachable
523 OpFunctionEnd
524 )";
525 
526   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
527   SinglePassRunAndMatch<MergeReturnPass>(before, false);
528 }
529 
TEST_F(MergeReturnPassTest,StructuredControlFlowAddPhi)530 TEST_F(MergeReturnPassTest, StructuredControlFlowAddPhi) {
531   const std::string before =
532       R"(
533 ; CHECK: [[false:%\w+]] = OpConstantFalse
534 ; CHECK: [[true:%\w+]] = OpConstantTrue
535 ; CHECK: OpFunction
536 ; CHECK: [[var:%\w+]] = OpVariable [[:%\w+]] Function [[false]]
537 ; CHECK: OpSelectionMerge [[single_case_switch_merge:%\w+]]
538 ; CHECK: OpSelectionMerge [[merge_lab:%\w+]]
539 ; CHECK: OpBranchConditional [[cond:%\w+]] [[if_lab:%\w+]] [[then_lab:%\w+]]
540 ; CHECK: [[if_lab]] = OpLabel
541 ; CHECK-NEXT: [[add:%\w+]] = OpIAdd [[type:%\w+]]
542 ; CHECK-NEXT: OpBranch
543 ; CHECK: [[then_lab]] = OpLabel
544 ; CHECK-NEXT: OpStore [[var]] [[true]]
545 ; CHECK-NEXT: OpBranch [[single_case_switch_merge]]
546 ; CHECK: [[merge_lab]] = OpLabel
547 ; CHECK: [[single_case_switch_merge]] = OpLabel
548 ; CHECK-NEXT: OpReturn
549 OpCapability Addresses
550 OpCapability Shader
551 OpCapability Linkage
552 OpMemoryModel Logical GLSL450
553 OpEntryPoint GLCompute %6 "simple_shader"
554 %2 = OpTypeVoid
555 %3 = OpTypeBool
556 %int = OpTypeInt 32 0
557 %int_0 = OpConstant %int 0
558 %4 = OpConstantFalse %3
559 %1 = OpTypeFunction %2
560 %6 = OpFunction %2 None %1
561 %7 = OpLabel
562 OpSelectionMerge %10 None
563 OpBranchConditional %4 %8 %9
564 %8 = OpLabel
565 %11 = OpIAdd %int %int_0 %int_0
566 OpBranch %10
567 %9 = OpLabel
568 OpReturn
569 %10 = OpLabel
570 %12 = OpIAdd %int %11 %11
571 OpReturn
572 OpFunctionEnd
573 )";
574 
575   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
576   SinglePassRunAndMatch<MergeReturnPass>(before, false);
577 }
578 
TEST_F(MergeReturnPassTest,StructuredControlDecoration)579 TEST_F(MergeReturnPassTest, StructuredControlDecoration) {
580   const std::string before =
581       R"(
582 ; CHECK: OpDecorate [[dec_id:%\w+]] RelaxedPrecision
583 ; CHECK: [[false:%\w+]] = OpConstantFalse
584 ; CHECK: [[true:%\w+]] = OpConstantTrue
585 ; CHECK: OpFunction
586 ; CHECK: [[var:%\w+]] = OpVariable [[:%\w+]] Function [[false]]
587 ; CHECK: OpSelectionMerge [[return_block:%\w+]]
588 ; CHECK: OpSelectionMerge [[merge_lab:%\w+]]
589 ; CHECK: OpBranchConditional [[cond:%\w+]] [[if_lab:%\w+]] [[then_lab:%\w+]]
590 ; CHECK: [[if_lab]] = OpLabel
591 ; CHECK-NEXT: [[dec_id]] = OpIAdd [[type:%\w+]]
592 ; CHECK-NEXT: OpBranch
593 ; CHECK: [[then_lab]] = OpLabel
594 ; CHECK-NEXT: OpStore [[var]] [[true]]
595 ; CHECK-NEXT: OpBranch [[return_block]]
596 ; CHECK: [[merge_lab]] = OpLabel
597 ; CHECK-NEXT: OpStore [[var]] [[true]]
598 ; CHECK-NEXT: OpBranch [[return_block]]
599 ; CHECK: [[return_block]] = OpLabel
600 ; CHECK-NEXT: OpReturn
601 OpCapability Addresses
602 OpCapability Shader
603 OpCapability Linkage
604 OpMemoryModel Logical GLSL450
605 OpEntryPoint GLCompute %6 "simple_shader"
606 OpDecorate %11 RelaxedPrecision
607 %2 = OpTypeVoid
608 %3 = OpTypeBool
609 %int = OpTypeInt 32 0
610 %int_0 = OpConstant %int 0
611 %4 = OpConstantFalse %3
612 %1 = OpTypeFunction %2
613 %6 = OpFunction %2 None %1
614 %7 = OpLabel
615 OpSelectionMerge %10 None
616 OpBranchConditional %4 %8 %9
617 %8 = OpLabel
618 %11 = OpIAdd %int %int_0 %int_0
619 OpBranch %10
620 %9 = OpLabel
621 OpReturn
622 %10 = OpLabel
623 OpReturn
624 OpFunctionEnd
625 )";
626 
627   SinglePassRunAndMatch<MergeReturnPass>(before, false);
628 }
629 
TEST_F(MergeReturnPassTest,SplitBlockUsedInPhi)630 TEST_F(MergeReturnPassTest, SplitBlockUsedInPhi) {
631   const std::string before =
632       R"(
633 ; CHECK: OpFunction
634 ; CHECK: OpSelectionMerge [[single_case_switch_merge:%\w+]]
635 ; CHECK: OpLoopMerge [[loop_merge:%\w+]]
636 ; CHECK: [[loop_merge]] = OpLabel
637 ; CHECK: OpBranchConditional {{%\w+}} [[single_case_switch_merge]] [[old_code_path:%\w+]]
638 ; CHECK: [[old_code_path:%\w+]] = OpLabel
639 ; CHECK: OpBranchConditional {{%\w+}} [[side_node:%\w+]] [[phi_block:%\w+]]
640 ; CHECK: [[phi_block]] = OpLabel
641 ; CHECK-NEXT: OpPhi %bool %false [[side_node]] %true [[old_code_path]]
642                OpCapability Addresses
643                OpCapability Shader
644                OpCapability Linkage
645                OpMemoryModel Logical GLSL450
646                OpEntryPoint GLCompute %1 "simple_shader"
647        %void = OpTypeVoid
648        %bool = OpTypeBool
649       %false = OpConstantFalse %bool
650        %true = OpConstantTrue %bool
651           %6 = OpTypeFunction %void
652           %1 = OpFunction %void None %6
653           %7 = OpLabel
654                OpLoopMerge %merge %cont None
655                OpBranchConditional %false %9 %merge
656           %9 = OpLabel
657                OpReturn
658        %cont = OpLabel
659                OpBranch %7
660       %merge = OpLabel
661                OpSelectionMerge %merge2 None
662                OpBranchConditional %false %if %merge2
663          %if = OpLabel
664                OpBranch %merge2
665      %merge2 = OpLabel
666          %12 = OpPhi %bool %false %if %true %merge
667                OpReturn
668                OpFunctionEnd
669 )";
670 
671   SinglePassRunAndMatch<MergeReturnPass>(before, false);
672 }
673 
TEST_F(MergeReturnPassTest,DebugSplitBlockUsedInPhi)674 TEST_F(MergeReturnPassTest, DebugSplitBlockUsedInPhi) {
675   const std::string before =
676       R"(
677 ; CHECK:      DebugScope
678 ; CHECK-NEXT: OpLine {{%\d+}} 100 0
679 ; CHECK:      OpLoopMerge
680 
681 ; CHECK:      OpStore [[return_in_loop:%\w+]] %true
682 ; CHECK-NEXT: DebugScope
683 ; CHECK-NEXT: OpLine {{%\d+}} 200 0
684 ; CHECK-NEXT: OpBranch [[check_early_return:%\w+]]
685 
686 ; CHECK:      [[check_early_return]] = OpLabel
687 ; CHECK-NEXT: [[early_return:%\w+]] = OpLoad %bool [[return_in_loop]]
688 ; CHECK-NEXT: OpSelectionMerge [[not_early_return:%\w+]] None
689 ; CHECK-NEXT: OpBranchConditional [[early_return]] {{%\d+}} [[not_early_return]]
690 
691 ; CHECK:      [[not_early_return]] = OpLabel
692 ; CHECK-NEXT: DebugScope
693 ; CHECK-NEXT: OpLine {{%\d+}} 400 0
694 ; CHECK:      OpSelectionMerge [[merge2:%\w+]] None
695 
696 ; CHECK:      [[merge2]] = OpLabel
697 ; CHECK-NEXT: DebugScope
698 ; CHECK-NEXT: OpLine {{%\d+}} 600 0
699 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %bool %false {{%\d+}} %true [[not_early_return]]
700 ; CHECK-NEXT: DebugValue {{%\d+}} [[phi]]
701 
702                OpCapability Addresses
703                OpCapability Shader
704                OpCapability Linkage
705         %ext = OpExtInstImport "OpenCL.DebugInfo.100"
706                OpMemoryModel Logical GLSL450
707                OpEntryPoint GLCompute %1 "simple_shader"
708          %tn = OpString "test"
709        %void = OpTypeVoid
710        %bool = OpTypeBool
711        %uint = OpTypeInt 32 0
712      %uint_8 = OpConstant %uint 8
713       %false = OpConstantFalse %bool
714        %true = OpConstantTrue %bool
715           %6 = OpTypeFunction %void
716         %src = OpExtInst %void %ext DebugSource %tn
717          %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
718          %ty = OpExtInst %void %ext DebugTypeBasic %tn %uint_8 Boolean
719           %v = OpExtInst %void %ext DebugLocalVariable %tn %ty %src 0 0 %cu FlagIsLocal
720        %expr = OpExtInst %void %ext DebugExpression
721           %1 = OpFunction %void None %6
722           %7 = OpLabel
723          %s0 = OpExtInst %void %ext DebugScope %cu
724                OpLine %tn 100 0
725                OpLoopMerge %merge %cont None
726                OpBranchConditional %false %9 %merge
727           %9 = OpLabel
728          %s1 = OpExtInst %void %ext DebugScope %cu
729                OpLine %tn 200 0
730                OpReturn
731        %cont = OpLabel
732          %s2 = OpExtInst %void %ext DebugScope %cu
733                OpLine %tn 300 0
734                OpBranch %7
735       %merge = OpLabel
736          %s3 = OpExtInst %void %ext DebugScope %cu
737                OpLine %tn 400 0
738                OpSelectionMerge %merge2 None
739                OpBranchConditional %false %if %merge2
740          %if = OpLabel
741          %s4 = OpExtInst %void %ext DebugScope %cu
742                OpLine %tn 500 0
743                OpBranch %merge2
744      %merge2 = OpLabel
745          %s5 = OpExtInst %void %ext DebugScope %cu
746                OpLine %tn 600 0
747          %12 = OpPhi %bool %false %if %true %merge
748          %dv = OpExtInst %void %ext DebugValue %v %12 %expr
749                OpLine %tn 900 0
750                OpReturn
751                OpFunctionEnd
752 )";
753 
754   SinglePassRunAndMatch<MergeReturnPass>(before, false);
755 }
756 
757 // TODO(#1861): Reenable these test when the breaks from selection constructs
758 // are reenabled.
759 /*
760 TEST_F(MergeReturnPassTest, UpdateOrderWhenPredicating) {
761   const std::string before =
762       R"(
763 ; CHECK: OpFunction
764 ; CHECK: OpFunction
765 ; CHECK: OpSelectionMerge [[m1:%\w+]] None
766 ; CHECK-NOT: OpReturn
767 ; CHECK: [[m1]] = OpLabel
768 ; CHECK: OpSelectionMerge [[m2:%\w+]] None
769 ; CHECK: OpSelectionMerge [[m3:%\w+]] None
770 ; CHECK: OpSelectionMerge [[m4:%\w+]] None
771 ; CHECK: OpLabel
772 ; CHECK-NEXT: OpStore
773 ; CHECK-NEXT: OpBranch [[m4]]
774 ; CHECK: [[m4]] = OpLabel
775 ; CHECK-NEXT: [[ld4:%\w+]] = OpLoad %bool
776 ; CHECK-NEXT: OpBranchConditional [[ld4]] [[m3]]
777 ; CHECK: [[m3]] = OpLabel
778 ; CHECK-NEXT: [[ld3:%\w+]] = OpLoad %bool
779 ; CHECK-NEXT: OpBranchConditional [[ld3]] [[m2]]
780 ; CHECK: [[m2]] = OpLabel
781                OpCapability SampledBuffer
782                OpCapability StorageImageExtendedFormats
783                OpCapability Shader
784                OpMemoryModel Logical GLSL450
785                OpEntryPoint Fragment %1 "PS_DebugTiles"
786                OpExecutionMode %1 OriginUpperLeft
787                OpSource HLSL 600
788        %void = OpTypeVoid
789           %3 = OpTypeFunction %void
790        %bool = OpTypeBool
791           %1 = OpFunction %void None %3
792           %5 = OpLabel
793           %6 = OpFunctionCall %void %7
794                OpReturn
795                OpFunctionEnd
796           %7 = OpFunction %void None %3
797           %8 = OpLabel
798           %9 = OpUndef %bool
799                OpSelectionMerge %10 None
800                OpBranchConditional %9 %11 %10
801          %11 = OpLabel
802                OpReturn
803          %10 = OpLabel
804          %12 = OpUndef %bool
805                OpSelectionMerge %13 None
806                OpBranchConditional %12 %14 %15
807          %15 = OpLabel
808          %16 = OpUndef %bool
809                OpSelectionMerge %17 None
810                OpBranchConditional %16 %18 %17
811          %18 = OpLabel
812                OpReturn
813          %17 = OpLabel
814                OpBranch %13
815          %14 = OpLabel
816                OpReturn
817          %13 = OpLabel
818                OpReturn
819                OpFunctionEnd
820 )";
821 
822   SinglePassRunAndMatch<MergeReturnPass>(before, false);
823 }
824 */
825 
TEST_F(MergeReturnPassTest,StructuredControlFlowBothMergeAndHeader)826 TEST_F(MergeReturnPassTest, StructuredControlFlowBothMergeAndHeader) {
827   const std::string test =
828       R"(
829 ; CHECK: OpFunction
830 ; CHECK: [[ret_flag:%\w+]] = OpVariable %_ptr_Function_bool Function %false
831 ; CHECK: OpSelectionMerge [[single_case_switch_merge:%\w+]]
832 ; CHECK: OpLoopMerge [[loop1_merge:%\w+]] {{%\w+}}
833 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_lab:%\w+]] {{%\w+}}
834 ; CHECK: [[if_lab]] = OpLabel
835 ; CHECK: OpStore [[ret_flag]] %true
836 ; CHECK-NEXT: OpBranch [[loop1_merge]]
837 ; CHECK: [[loop1_merge]] = OpLabel
838 ; CHECK-NEXT: [[ld:%\w+]] = OpLoad %bool [[ret_flag]]
839 ; CHECK-NOT: OpLabel
840 ; CHECK: OpBranchConditional [[ld]] [[single_case_switch_merge]] [[empty_block:%\w+]]
841 ; CHECK: [[empty_block]] = OpLabel
842 ; CHECK-NEXT: OpBranch [[loop2:%\w+]]
843 ; CHECK: [[loop2]] = OpLabel
844 ; CHECK-NOT: OpLabel
845 ; CHECK: OpLoopMerge
846                OpCapability Addresses
847                OpCapability Shader
848                OpCapability Linkage
849                OpMemoryModel Logical GLSL450
850                OpEntryPoint GLCompute %1 "simple_shader"
851        %void = OpTypeVoid
852        %bool = OpTypeBool
853        %uint = OpTypeInt 32 0
854      %uint_0 = OpConstant %uint 0
855       %false = OpConstantFalse %bool
856           %7 = OpTypeFunction %void
857           %1 = OpFunction %void None %7
858           %8 = OpLabel
859                OpBranch %9
860           %9 = OpLabel
861                OpLoopMerge %10 %11 None
862                OpBranchConditional %false %12 %13
863          %12 = OpLabel
864                OpReturn
865          %13 = OpLabel
866                OpBranch %10
867          %11 = OpLabel
868                OpBranch %9
869          %10 = OpLabel
870                OpLoopMerge %14 %15 None
871                OpBranch %15
872          %15 = OpLabel
873          %16 = OpIAdd %uint %uint_0 %uint_0
874                OpBranchConditional %false %10 %14
875          %14 = OpLabel
876          %17 = OpIAdd %uint %16 %16
877                OpReturn
878                OpFunctionEnd
879 
880 )";
881 
882   const std::string after =
883       R"(OpCapability Addresses
884 OpCapability Shader
885 OpCapability Linkage
886 OpMemoryModel Logical GLSL450
887 OpEntryPoint GLCompute %1 "simple_shader"
888 %void = OpTypeVoid
889 %bool = OpTypeBool
890 %uint = OpTypeInt 32 0
891 %uint_0 = OpConstant %uint 0
892 %false = OpConstantFalse %bool
893 %7 = OpTypeFunction %void
894 %_ptr_Function_bool = OpTypePointer Function %bool
895 %true = OpConstantTrue %bool
896 %1 = OpFunction %void None %7
897 %8 = OpLabel
898 %18 = OpVariable %_ptr_Function_bool Function %false
899 OpSelectionMerge %9 None
900 OpBranchConditional %false %10 %11
901 %10 = OpLabel
902 OpStore %18 %true
903 OpBranch %9
904 %11 = OpLabel
905 OpBranch %9
906 %9 = OpLabel
907 %23 = OpLoad %bool %18
908 OpSelectionMerge %22 None
909 OpBranchConditional %23 %22 %21
910 %21 = OpLabel
911 OpBranch %20
912 %20 = OpLabel
913 OpLoopMerge %12 %13 None
914 OpBranch %13
915 %13 = OpLabel
916 %14 = OpIAdd %uint %uint_0 %uint_0
917 OpBranchConditional %false %20 %12
918 %12 = OpLabel
919 %15 = OpIAdd %uint %14 %14
920 OpStore %18 %true
921 OpBranch %22
922 %22 = OpLabel
923 OpBranch %16
924 %16 = OpLabel
925 OpReturn
926 OpFunctionEnd
927 )";
928 
929   SinglePassRunAndMatch<MergeReturnPass>(test, false);
930 }
931 
932 // TODO(#1861): Reenable these test when the breaks from selection constructs
933 // are reenabled.
934 /*
935 TEST_F(MergeReturnPassTest, NestedSelectionMerge) {
936   const std::string before =
937       R"(
938                OpCapability Addresses
939                OpCapability Shader
940                OpCapability Linkage
941                OpMemoryModel Logical GLSL450
942                OpEntryPoint GLCompute %1 "simple_shader"
943        %void = OpTypeVoid
944        %bool = OpTypeBool
945        %uint = OpTypeInt 32 0
946      %uint_0 = OpConstant %uint 0
947       %false = OpConstantFalse %bool
948           %7 = OpTypeFunction %void
949           %1 = OpFunction %void None %7
950           %8 = OpLabel
951                OpSelectionMerge %9 None
952                OpBranchConditional %false %10 %11
953          %10 = OpLabel
954                OpReturn
955          %11 = OpLabel
956                OpSelectionMerge %12 None
957                OpBranchConditional %false %13 %14
958          %13 = OpLabel
959          %15 = OpIAdd %uint %uint_0 %uint_0
960                OpBranch %12
961          %14 = OpLabel
962                OpReturn
963          %12 = OpLabel
964                OpBranch %9
965           %9 = OpLabel
966          %16 = OpIAdd %uint %15 %15
967                OpReturn
968                OpFunctionEnd
969 )";
970 
971   const std::string after =
972       R"(OpCapability Addresses
973 OpCapability Shader
974 OpCapability Linkage
975 OpMemoryModel Logical GLSL450
976 OpEntryPoint GLCompute %1 "simple_shader"
977 %void = OpTypeVoid
978 %bool = OpTypeBool
979 %uint = OpTypeInt 32 0
980 %uint_0 = OpConstant %uint 0
981 %false = OpConstantFalse %bool
982 %7 = OpTypeFunction %void
983 %_ptr_Function_bool = OpTypePointer Function %bool
984 %true = OpConstantTrue %bool
985 %26 = OpUndef %uint
986 %1 = OpFunction %void None %7
987 %8 = OpLabel
988 %19 = OpVariable %_ptr_Function_bool Function %false
989 OpSelectionMerge %9 None
990 OpBranchConditional %false %10 %11
991 %10 = OpLabel
992 OpStore %19 %true
993 OpBranch %9
994 %11 = OpLabel
995 OpSelectionMerge %12 None
996 OpBranchConditional %false %13 %14
997 %13 = OpLabel
998 %15 = OpIAdd %uint %uint_0 %uint_0
999 OpBranch %12
1000 %14 = OpLabel
1001 OpStore %19 %true
1002 OpBranch %12
1003 %12 = OpLabel
1004 %27 = OpPhi %uint %15 %13 %26 %14
1005 %22 = OpLoad %bool %19
1006 OpBranchConditional %22 %9 %21
1007 %21 = OpLabel
1008 OpBranch %9
1009 %9 = OpLabel
1010 %28 = OpPhi %uint %27 %21 %26 %10 %26 %12
1011 %25 = OpLoad %bool %19
1012 OpSelectionMerge %24 None
1013 OpBranchConditional %25 %24 %23
1014 %23 = OpLabel
1015 %16 = OpIAdd %uint %28 %28
1016 OpStore %19 %true
1017 OpBranch %24
1018 %24 = OpLabel
1019 OpBranch %17
1020 %17 = OpLabel
1021 OpReturn
1022 OpFunctionEnd
1023 )";
1024 
1025   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1026   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
1027 }
1028 
1029 // This is essentially the same as NestedSelectionMerge, except
1030 // the order of the first branch is changed.  This is to make sure things
1031 // work even if the order of the traversals change.
1032 TEST_F(MergeReturnPassTest, NestedSelectionMerge2) {
1033   const std::string before =
1034       R"(      OpCapability Addresses
1035                OpCapability Shader
1036                OpCapability Linkage
1037                OpMemoryModel Logical GLSL450
1038                OpEntryPoint GLCompute %1 "simple_shader"
1039        %void = OpTypeVoid
1040        %bool = OpTypeBool
1041        %uint = OpTypeInt 32 0
1042      %uint_0 = OpConstant %uint 0
1043       %false = OpConstantFalse %bool
1044           %7 = OpTypeFunction %void
1045           %1 = OpFunction %void None %7
1046           %8 = OpLabel
1047                OpSelectionMerge %9 None
1048                OpBranchConditional %false %10 %11
1049          %11 = OpLabel
1050                OpReturn
1051          %10 = OpLabel
1052                OpSelectionMerge %12 None
1053                OpBranchConditional %false %13 %14
1054          %13 = OpLabel
1055          %15 = OpIAdd %uint %uint_0 %uint_0
1056                OpBranch %12
1057          %14 = OpLabel
1058                OpReturn
1059          %12 = OpLabel
1060                OpBranch %9
1061           %9 = OpLabel
1062          %16 = OpIAdd %uint %15 %15
1063                OpReturn
1064                OpFunctionEnd
1065 )";
1066 
1067   const std::string after =
1068       R"(OpCapability Addresses
1069 OpCapability Shader
1070 OpCapability Linkage
1071 OpMemoryModel Logical GLSL450
1072 OpEntryPoint GLCompute %1 "simple_shader"
1073 %void = OpTypeVoid
1074 %bool = OpTypeBool
1075 %uint = OpTypeInt 32 0
1076 %uint_0 = OpConstant %uint 0
1077 %false = OpConstantFalse %bool
1078 %7 = OpTypeFunction %void
1079 %_ptr_Function_bool = OpTypePointer Function %bool
1080 %true = OpConstantTrue %bool
1081 %26 = OpUndef %uint
1082 %1 = OpFunction %void None %7
1083 %8 = OpLabel
1084 %19 = OpVariable %_ptr_Function_bool Function %false
1085 OpSelectionMerge %9 None
1086 OpBranchConditional %false %10 %11
1087 %11 = OpLabel
1088 OpStore %19 %true
1089 OpBranch %9
1090 %10 = OpLabel
1091 OpSelectionMerge %12 None
1092 OpBranchConditional %false %13 %14
1093 %13 = OpLabel
1094 %15 = OpIAdd %uint %uint_0 %uint_0
1095 OpBranch %12
1096 %14 = OpLabel
1097 OpStore %19 %true
1098 OpBranch %12
1099 %12 = OpLabel
1100 %27 = OpPhi %uint %15 %13 %26 %14
1101 %25 = OpLoad %bool %19
1102 OpBranchConditional %25 %9 %24
1103 %24 = OpLabel
1104 OpBranch %9
1105 %9 = OpLabel
1106 %28 = OpPhi %uint %27 %24 %26 %11 %26 %12
1107 %23 = OpLoad %bool %19
1108 OpSelectionMerge %22 None
1109 OpBranchConditional %23 %22 %21
1110 %21 = OpLabel
1111 %16 = OpIAdd %uint %28 %28
1112 OpStore %19 %true
1113 OpBranch %22
1114 %22 = OpLabel
1115 OpBranch %17
1116 %17 = OpLabel
1117 OpReturn
1118 OpFunctionEnd
1119 )";
1120 
1121   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
1122 }
1123 
1124 TEST_F(MergeReturnPassTest, NestedSelectionMerge3) {
1125   const std::string before =
1126       R"(      OpCapability Addresses
1127                OpCapability Shader
1128                OpCapability Linkage
1129                OpMemoryModel Logical GLSL450
1130                OpEntryPoint GLCompute %1 "simple_shader"
1131        %void = OpTypeVoid
1132        %bool = OpTypeBool
1133        %uint = OpTypeInt 32 0
1134      %uint_0 = OpConstant %uint 0
1135       %false = OpConstantFalse %bool
1136           %7 = OpTypeFunction %void
1137           %1 = OpFunction %void None %7
1138           %8 = OpLabel
1139                OpSelectionMerge %9 None
1140                OpBranchConditional %false %10 %11
1141          %11 = OpLabel
1142                OpReturn
1143          %10 = OpLabel
1144          %12 = OpIAdd %uint %uint_0 %uint_0
1145                OpSelectionMerge %13 None
1146                OpBranchConditional %false %14 %15
1147          %14 = OpLabel
1148                OpBranch %13
1149          %15 = OpLabel
1150                OpReturn
1151          %13 = OpLabel
1152                OpBranch %9
1153           %9 = OpLabel
1154          %16 = OpIAdd %uint %12 %12
1155                OpReturn
1156                OpFunctionEnd
1157 )";
1158 
1159   const std::string after =
1160       R"(OpCapability Addresses
1161 OpCapability Shader
1162 OpCapability Linkage
1163 OpMemoryModel Logical GLSL450
1164 OpEntryPoint GLCompute %1 "simple_shader"
1165 %void = OpTypeVoid
1166 %bool = OpTypeBool
1167 %uint = OpTypeInt 32 0
1168 %uint_0 = OpConstant %uint 0
1169 %false = OpConstantFalse %bool
1170 %7 = OpTypeFunction %void
1171 %_ptr_Function_bool = OpTypePointer Function %bool
1172 %true = OpConstantTrue %bool
1173 %26 = OpUndef %uint
1174 %1 = OpFunction %void None %7
1175 %8 = OpLabel
1176 %19 = OpVariable %_ptr_Function_bool Function %false
1177 OpSelectionMerge %9 None
1178 OpBranchConditional %false %10 %11
1179 %11 = OpLabel
1180 OpStore %19 %true
1181 OpBranch %9
1182 %10 = OpLabel
1183 %12 = OpIAdd %uint %uint_0 %uint_0
1184 OpSelectionMerge %13 None
1185 OpBranchConditional %false %14 %15
1186 %14 = OpLabel
1187 OpBranch %13
1188 %15 = OpLabel
1189 OpStore %19 %true
1190 OpBranch %13
1191 %13 = OpLabel
1192 %25 = OpLoad %bool %19
1193 OpBranchConditional %25 %9 %24
1194 %24 = OpLabel
1195 OpBranch %9
1196 %9 = OpLabel
1197 %27 = OpPhi %uint %12 %24 %26 %11 %26 %13
1198 %23 = OpLoad %bool %19
1199 OpSelectionMerge %22 None
1200 OpBranchConditional %23 %22 %21
1201 %21 = OpLabel
1202 %16 = OpIAdd %uint %27 %27
1203 OpStore %19 %true
1204 OpBranch %22
1205 %22 = OpLabel
1206 OpBranch %17
1207 %17 = OpLabel
1208 OpReturn
1209 OpFunctionEnd
1210 )";
1211 
1212   SinglePassRunAndCheck<MergeReturnPass>(before, after, false, true);
1213 }
1214 */
1215 
TEST_F(MergeReturnPassTest,NestedLoopMerge)1216 TEST_F(MergeReturnPassTest, NestedLoopMerge) {
1217   const std::string test =
1218       R"(
1219 ; CHECK: OpFunction
1220 ; CHECK: OpSelectionMerge [[single_case_switch_merge:%\w+]]
1221 ; CHECK: OpLoopMerge [[outer_loop_merge:%\w+]]
1222 ; CHECK: OpLoopMerge [[inner_loop_merge:%\w+]]
1223 ; CHECK: OpSelectionMerge
1224 ; CHECK-NEXT: OpBranchConditional %true [[early_exit_block:%\w+]]
1225 ; CHECK: [[early_exit_block]] = OpLabel
1226 ; CHECK-NOT: OpLabel
1227 ; CHECK: OpBranch [[inner_loop_merge]]
1228 ; CHECK: [[inner_loop_merge]] = OpLabel
1229 ; CHECK-NOT: OpLabel
1230 ; CHECK: OpBranchConditional {{%\w+}} [[outer_loop_merge]]
1231 ; CHECK: [[outer_loop_merge]] = OpLabel
1232 ; CHECK-NOT: OpLabel
1233 ; CHECK: OpBranchConditional {{%\w+}} [[single_case_switch_merge]]
1234 ; CHECK: [[single_case_switch_merge]] = OpLabel
1235 ; CHECK-NOT: OpLabel
1236 ; CHECK: OpReturn
1237                OpCapability SampledBuffer
1238                OpCapability StorageImageExtendedFormats
1239                OpCapability Shader
1240           %1 = OpExtInstImport "GLSL.std.450"
1241                OpMemoryModel Logical GLSL450
1242                OpEntryPoint GLCompute %2 "CS"
1243                OpExecutionMode %2 LocalSize 8 8 1
1244                OpSource HLSL 600
1245        %uint = OpTypeInt 32 0
1246        %void = OpTypeVoid
1247           %6 = OpTypeFunction %void
1248      %uint_0 = OpConstant %uint 0
1249      %uint_1 = OpConstant %uint 1
1250      %v3uint = OpTypeVector %uint 3
1251        %bool = OpTypeBool
1252        %true = OpConstantTrue %bool
1253 %_ptr_Function_uint = OpTypePointer Function %uint
1254           %2 = OpFunction %void None %6
1255          %14 = OpLabel
1256                OpBranch %19
1257          %19 = OpLabel
1258          %20 = OpPhi %uint %uint_0 %2 %34 %23
1259          %21 = OpULessThan %bool %20 %uint_1
1260                OpLoopMerge %22 %23 DontUnroll
1261                OpBranchConditional %21 %24 %22
1262          %24 = OpLabel
1263                OpBranch %25
1264          %25 = OpLabel
1265          %27 = OpINotEqual %bool %uint_1 %uint_0
1266                OpLoopMerge %28 %29 DontUnroll
1267                OpBranchConditional %27 %30 %28
1268          %30 = OpLabel
1269                OpSelectionMerge %31 None
1270                OpBranchConditional %true %32 %31
1271          %32 = OpLabel
1272                OpReturn
1273          %31 = OpLabel
1274                OpBranch %29
1275          %29 = OpLabel
1276                OpBranch %25
1277          %28 = OpLabel
1278                OpBranch %23
1279          %23 = OpLabel
1280          %34 = OpIAdd %uint %20 %uint_1
1281                OpBranch %19
1282          %22 = OpLabel
1283                OpReturn
1284                OpFunctionEnd
1285 )";
1286 
1287   SinglePassRunAndMatch<MergeReturnPass>(test, false);
1288 }
1289 
TEST_F(MergeReturnPassTest,ReturnValueDecoration)1290 TEST_F(MergeReturnPassTest, ReturnValueDecoration) {
1291   const std::string test =
1292       R"(
1293 ; CHECK: OpDecorate [[func:%\w+]] RelaxedPrecision
1294 ; CHECK: OpDecorate [[ret_val:%\w+]] RelaxedPrecision
1295 ; CHECK: [[func]] = OpFunction
1296 ; CHECK-NEXT: OpLabel
1297 ; CHECK-NOT: OpLabel
1298 ; CHECK: [[ret_val]] = OpVariable
1299 OpCapability Linkage
1300 OpCapability Shader
1301 OpMemoryModel Logical GLSL450
1302 OpEntryPoint GLCompute %11 "simple_shader"
1303 OpDecorate %7 RelaxedPrecision
1304 %12 = OpTypeVoid
1305 %1 = OpTypeInt 32 0
1306 %2 = OpTypeBool
1307 %3 = OpConstantFalse %2
1308 %4 = OpConstant %1 0
1309 %5 = OpConstant %1 1
1310 %6 = OpTypeFunction %1
1311 %13 = OpTypeFunction %12
1312 %11 = OpFunction %12 None %13
1313 %l1 = OpLabel
1314 %fc = OpFunctionCall %1 %7
1315 OpReturn
1316 OpFunctionEnd
1317 %7 = OpFunction %1 None %6
1318 %8 = OpLabel
1319 OpBranchConditional %3 %9 %10
1320 %9 = OpLabel
1321 OpReturnValue %4
1322 %10 = OpLabel
1323 OpReturnValue %5
1324 OpFunctionEnd
1325 )";
1326 
1327   SinglePassRunAndMatch<MergeReturnPass>(test, false);
1328 }
1329 
TEST_F(MergeReturnPassTest,StructuredControlFlowWithNonTrivialUnreachableMerge)1330 TEST_F(MergeReturnPassTest,
1331        StructuredControlFlowWithNonTrivialUnreachableMerge) {
1332   const std::string before =
1333       R"(
1334 OpCapability Addresses
1335 OpCapability Shader
1336 OpCapability Linkage
1337 OpMemoryModel Logical GLSL450
1338 OpEntryPoint GLCompute %6 "simple_shader"
1339 %2 = OpTypeVoid
1340 %3 = OpTypeBool
1341 %4 = OpConstantFalse %3
1342 %1 = OpTypeFunction %2
1343 %6 = OpFunction %2 None %1
1344 %7 = OpLabel
1345 OpSelectionMerge %10 None
1346 OpBranchConditional %4 %8 %9
1347 %8 = OpLabel
1348 OpReturn
1349 %9 = OpLabel
1350 OpReturn
1351 %10 = OpLabel
1352 %11 = OpUndef %3
1353 OpUnreachable
1354 OpFunctionEnd
1355 )";
1356 
1357   std::vector<Message> messages = {
1358       {SPV_MSG_ERROR, nullptr, 0, 0,
1359        "Module contains unreachable blocks during merge return.  Run dead "
1360        "branch elimination before merge return."}};
1361   SetMessageConsumer(GetTestMessageConsumer(messages));
1362 
1363   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1364   auto result = SinglePassRunToBinary<MergeReturnPass>(before, false);
1365   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
1366   EXPECT_TRUE(messages.empty());
1367 }
1368 
TEST_F(MergeReturnPassTest,StructuredControlFlowWithNonTrivialUnreachableContinue)1369 TEST_F(MergeReturnPassTest,
1370        StructuredControlFlowWithNonTrivialUnreachableContinue) {
1371   const std::string before =
1372       R"(
1373 OpCapability Addresses
1374 OpCapability Shader
1375 OpCapability Linkage
1376 OpMemoryModel Logical GLSL450
1377 OpEntryPoint GLCompute %6 "simple_shader"
1378 %2 = OpTypeVoid
1379 %3 = OpTypeBool
1380 %4 = OpConstantFalse %3
1381 %1 = OpTypeFunction %2
1382 %6 = OpFunction %2 None %1
1383 %7 = OpLabel
1384 OpBranch %header
1385 %header = OpLabel
1386 OpLoopMerge %merge %continue None
1387 OpBranchConditional %4 %8 %merge
1388 %8 = OpLabel
1389 OpReturn
1390 %continue = OpLabel
1391 %11 = OpUndef %3
1392 OpBranch %header
1393 %merge = OpLabel
1394 OpReturn
1395 OpFunctionEnd
1396 )";
1397 
1398   std::vector<Message> messages = {
1399       {SPV_MSG_ERROR, nullptr, 0, 0,
1400        "Module contains unreachable blocks during merge return.  Run dead "
1401        "branch elimination before merge return."}};
1402   SetMessageConsumer(GetTestMessageConsumer(messages));
1403 
1404   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1405   auto result = SinglePassRunToBinary<MergeReturnPass>(before, false);
1406   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
1407   EXPECT_TRUE(messages.empty());
1408 }
1409 
TEST_F(MergeReturnPassTest,StructuredControlFlowWithUnreachableBlock)1410 TEST_F(MergeReturnPassTest, StructuredControlFlowWithUnreachableBlock) {
1411   const std::string before =
1412       R"(
1413 OpCapability Addresses
1414 OpCapability Shader
1415 OpCapability Linkage
1416 OpMemoryModel Logical GLSL450
1417 OpEntryPoint GLCompute %6 "simple_shader"
1418 %2 = OpTypeVoid
1419 %3 = OpTypeBool
1420 %4 = OpConstantFalse %3
1421 %1 = OpTypeFunction %2
1422 %6 = OpFunction %2 None %1
1423 %7 = OpLabel
1424 OpBranch %header
1425 %header = OpLabel
1426 OpLoopMerge %merge %continue None
1427 OpBranchConditional %4 %8 %merge
1428 %8 = OpLabel
1429 OpReturn
1430 %continue = OpLabel
1431 OpBranch %header
1432 %merge = OpLabel
1433 OpReturn
1434 %unreachable = OpLabel
1435 OpUnreachable
1436 OpFunctionEnd
1437 )";
1438 
1439   std::vector<Message> messages = {
1440       {SPV_MSG_ERROR, nullptr, 0, 0,
1441        "Module contains unreachable blocks during merge return.  Run dead "
1442        "branch elimination before merge return."}};
1443   SetMessageConsumer(GetTestMessageConsumer(messages));
1444 
1445   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1446   auto result = SinglePassRunToBinary<MergeReturnPass>(before, false);
1447   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
1448   EXPECT_TRUE(messages.empty());
1449 }
1450 
TEST_F(MergeReturnPassTest,StructuredControlFlowDontChangeEntryPhi)1451 TEST_F(MergeReturnPassTest, StructuredControlFlowDontChangeEntryPhi) {
1452   const std::string before =
1453       R"(
1454 ; CHECK: OpFunction %void
1455 ; CHECK: OpLabel
1456 ; CHECK: [[pre_header:%\w+]] = OpLabel
1457 ; CHECK: [[header:%\w+]] = OpLabel
1458 ; CHECK-NEXT: OpPhi %bool {{%\w+}} [[pre_header]] [[iv:%\w+]] [[continue:%\w+]]
1459 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]]
1460 ; CHECK: [[continue]] = OpLabel
1461 ; CHECK-NEXT: [[iv]] = Op
1462 ; CHECK: [[merge]] = OpLabel
1463                OpCapability Shader
1464                OpMemoryModel Logical GLSL450
1465                OpEntryPoint Vertex %1 "main"
1466        %void = OpTypeVoid
1467        %bool = OpTypeBool
1468           %4 = OpTypeFunction %void
1469           %1 = OpFunction %void None %4
1470           %5 = OpLabel
1471           %6 = OpUndef %bool
1472                OpBranch %7
1473           %7 = OpLabel
1474           %8 = OpPhi %bool %6 %5 %9 %10
1475                OpLoopMerge %11 %10 None
1476                OpBranch %12
1477          %12 = OpLabel
1478          %13 = OpUndef %bool
1479                OpSelectionMerge %10 DontFlatten
1480                OpBranchConditional %13 %10 %14
1481          %14 = OpLabel
1482                OpReturn
1483          %10 = OpLabel
1484           %9 = OpUndef %bool
1485                OpBranchConditional %13 %7 %11
1486          %11 = OpLabel
1487                OpReturn
1488                OpFunctionEnd
1489 
1490 )";
1491 
1492   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1493   SinglePassRunAndMatch<MergeReturnPass>(before, false);
1494 }
1495 
TEST_F(MergeReturnPassTest,StructuredControlFlowPartialReplacePhi)1496 TEST_F(MergeReturnPassTest, StructuredControlFlowPartialReplacePhi) {
1497   const std::string before =
1498       R"(
1499 ; CHECK: OpFunction %void
1500 ; CHECK: OpLabel
1501 ; CHECK: [[pre_header:%\w+]] = OpLabel
1502 ; CHECK: [[header:%\w+]] = OpLabel
1503 ; CHECK-NEXT: OpPhi
1504 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]]
1505 ; CHECK: OpLabel
1506 ; CHECK: [[old_ret_block:%\w+]] = OpLabel
1507 ; CHECK: [[bb:%\w+]] = OpLabel
1508 ; CHECK-NEXT: [[val:%\w+]] = OpUndef %bool
1509 ; CHECK: [[merge]] = OpLabel
1510 ; CHECK-NEXT: [[phi1:%\w+]] = OpPhi %bool {{%\w+}} [[old_ret_block]] [[val]] [[bb]]
1511 ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} [[bb2:%\w+]]
1512 ; CHECK: [[bb2]] = OpLabel
1513 ; CHECK: OpBranch [[header2:%\w+]]
1514 ; CHECK: [[header2]] = OpLabel
1515 ; CHECK-NEXT: [[phi2:%\w+]] = OpPhi %bool [[phi1]] [[continue2:%\w+]] [[phi1]] [[bb2]]
1516 ; CHECK-NEXT: OpLoopMerge {{%\w+}} [[continue2]]
1517 ; CHECK: [[continue2]] = OpLabel
1518 ; CHECK-NEXT: OpBranch [[header2]]
1519                OpCapability Shader
1520                OpMemoryModel Logical GLSL450
1521                OpEntryPoint Vertex %1 "main"
1522        %void = OpTypeVoid
1523        %bool = OpTypeBool
1524           %4 = OpTypeFunction %void
1525           %1 = OpFunction %void None %4
1526           %5 = OpLabel
1527           %6 = OpUndef %bool
1528                OpBranch %7
1529           %7 = OpLabel
1530           %8 = OpPhi %bool %6 %5 %9 %10
1531                OpLoopMerge %11 %10 None
1532                OpBranch %12
1533          %12 = OpLabel
1534          %13 = OpUndef %bool
1535                OpSelectionMerge %10 DontFlatten
1536                OpBranchConditional %13 %10 %14
1537          %14 = OpLabel
1538                OpReturn
1539          %10 = OpLabel
1540           %9 = OpUndef %bool
1541                OpBranchConditional %13 %7 %11
1542          %11 = OpLabel
1543           %phi = OpPhi %bool %9 %10 %9 %cont
1544                OpLoopMerge %ret %cont None
1545                OpBranch %bb
1546          %bb = OpLabel
1547                OpBranchConditional %13 %ret %cont
1548          %cont = OpLabel
1549                OpBranch %11
1550          %ret = OpLabel
1551                OpReturn
1552                OpFunctionEnd
1553 )";
1554 
1555   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1556   SinglePassRunAndMatch<MergeReturnPass>(before, false);
1557 }
1558 
TEST_F(MergeReturnPassTest,GeneratePhiInOuterLoop)1559 TEST_F(MergeReturnPassTest, GeneratePhiInOuterLoop) {
1560   const std::string before =
1561       R"(
1562       ; CHECK: OpSelectionMerge
1563       ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]]
1564       ; CHECK-NEXT: [[def_bb1]] = OpLabel
1565       ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]]
1566       ; CHECK: [[continue]] = OpLabel
1567       ; CHECK-NEXT: [[undef:%\w+]] = OpUndef
1568       ; CHECK: [[merge]] = OpLabel
1569       ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %bool {{%\w+}} {{%\w+}} [[undef]] [[continue]]
1570       ; CHECK: OpCopyObject %bool [[phi]]
1571                OpCapability Shader
1572           %1 = OpExtInstImport "GLSL.std.450"
1573                OpMemoryModel Logical GLSL450
1574                OpEntryPoint Fragment %4 "main"
1575                OpExecutionMode %4 OriginUpperLeft
1576                OpSource ESSL 310
1577        %void = OpTypeVoid
1578           %3 = OpTypeFunction %void
1579        %bool = OpTypeBool
1580           %8 = OpTypeFunction %bool
1581       %false = OpConstantFalse %bool
1582           %4 = OpFunction %void None %3
1583           %5 = OpLabel
1584          %63 = OpFunctionCall %bool %9
1585                OpReturn
1586                OpFunctionEnd
1587           %9 = OpFunction %bool None %8
1588          %10 = OpLabel
1589                OpBranch %31
1590          %31 = OpLabel
1591                OpLoopMerge %33 %34 None
1592                OpBranch %32
1593          %32 = OpLabel
1594                OpSelectionMerge %34 None
1595                OpBranchConditional %false %46 %34
1596          %46 = OpLabel
1597                OpLoopMerge %51 %52 None
1598                OpBranch %53
1599          %53 = OpLabel
1600                OpBranchConditional %false %50 %51
1601          %50 = OpLabel
1602                OpReturnValue %false
1603          %52 = OpLabel
1604                OpBranch %46
1605          %51 = OpLabel
1606                OpBranch %34
1607          %34 = OpLabel
1608          %64 = OpUndef %bool
1609                OpBranchConditional %false %31 %33
1610          %33 = OpLabel
1611                OpBranch %28
1612          %28 = OpLabel
1613          %60 = OpCopyObject %bool %64
1614                OpBranch %17
1615          %17 = OpLabel
1616                OpReturnValue %false
1617                OpFunctionEnd
1618 )";
1619 
1620   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1621   SinglePassRunAndMatch<MergeReturnPass>(before, false);
1622 }
1623 
TEST_F(MergeReturnPassTest,SerialLoopsUpdateBlockMapping)1624 TEST_F(MergeReturnPassTest, SerialLoopsUpdateBlockMapping) {
1625   // #2455: This test case triggers phi insertions that use previously inserted
1626   // phis. Without the fix, it fails to validate.
1627   const std::string spirv = R"(
1628 ; CHECK: OpSelectionMerge
1629 ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]]
1630 ; CHECK-NEXT: [[def_bb1]] = OpLabel
1631 ; CHECK: OpLoopMerge
1632 ; CHECK: OpLoopMerge
1633 ; CHECK: OpLoopMerge [[merge:%\w+]]
1634 ; CHECK: [[def:%\w+]] = OpFOrdLessThan
1635 ; CHECK: [[merge]] = OpLabel
1636 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} [[def]]
1637 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]]
1638 ; CHECK: [[cont]] = OpLabel
1639 ; CHECK-NEXT: OpBranchConditional [[phi]]
1640 ; CHECK-NOT: [[def]]
1641                OpCapability Shader
1642           %1 = OpExtInstImport "GLSL.std.450"
1643                OpMemoryModel Logical GLSL450
1644                OpEntryPoint Fragment %4 "main" %53
1645                OpExecutionMode %4 OriginUpperLeft
1646                OpSource ESSL 310
1647                OpDecorate %20 RelaxedPrecision
1648                OpDecorate %27 RelaxedPrecision
1649                OpDecorate %53 BuiltIn FragCoord
1650           %2 = OpTypeVoid
1651           %3 = OpTypeFunction %2
1652           %6 = OpTypeFloat 32
1653           %7 = OpTypeVector %6 3
1654           %8 = OpTypeFunction %7
1655          %11 = OpTypeBool
1656          %12 = OpConstantFalse %11
1657          %15 = OpConstant %6 1
1658          %16 = OpConstantComposite %7 %15 %15 %15
1659          %18 = OpTypeInt 32 1
1660          %19 = OpTypePointer Function %18
1661          %21 = OpConstant %18 1
1662          %28 = OpConstant %18 0
1663          %31 = OpTypePointer Function %11
1664          %33 = OpConstantTrue %11
1665          %51 = OpTypeVector %6 4
1666          %52 = OpTypePointer Input %51
1667          %53 = OpVariable %52 Input
1668          %54 = OpTypeInt 32 0
1669          %55 = OpConstant %54 0
1670          %56 = OpTypePointer Input %6
1671          %59 = OpConstant %6 0
1672          %76 = OpUndef %18
1673          %77 = OpUndef %11
1674          %78 = OpUndef %6
1675           %4 = OpFunction %2 None %3
1676           %5 = OpLabel
1677          %75 = OpFunctionCall %7 %9
1678                OpReturn
1679                OpFunctionEnd
1680           %9 = OpFunction %7 None %8
1681          %10 = OpLabel
1682          %20 = OpVariable %19 Function
1683                OpBranch %14
1684          %14 = OpLabel
1685                OpBranch %22
1686          %22 = OpLabel
1687          %27 = OpLoad %18 %20
1688                OpLoopMerge %24 %25 None
1689                OpBranch %24
1690          %25 = OpLabel
1691                OpBranch %22
1692          %24 = OpLabel
1693                OpBranch %34
1694          %34 = OpLabel
1695                OpLoopMerge %36 %40 None
1696                OpBranch %35
1697          %35 = OpLabel
1698                OpBranchConditional %77 %39 %40
1699          %39 = OpLabel
1700                OpReturnValue %16
1701          %40 = OpLabel
1702                OpBranchConditional %12 %34 %36
1703          %36 = OpLabel
1704                OpBranch %43
1705          %43 = OpLabel
1706                OpLoopMerge %45 %49 None
1707                OpBranch %44
1708          %44 = OpLabel
1709                OpBranchConditional %77 %48 %49
1710          %48 = OpLabel
1711                OpReturnValue %16
1712          %49 = OpLabel
1713          %60 = OpFOrdLessThan %11 %15 %59
1714                OpBranchConditional %12 %43 %45
1715          %45 = OpLabel
1716                OpBranch %62
1717          %62 = OpLabel
1718                OpLoopMerge %64 %68 None
1719                OpBranch %63
1720          %63 = OpLabel
1721                OpBranchConditional %77 %67 %68
1722          %67 = OpLabel
1723                OpReturnValue %16
1724          %68 = OpLabel
1725                OpBranchConditional %60 %62 %64
1726          %64 = OpLabel
1727                OpReturnValue %16
1728                OpFunctionEnd
1729 )";
1730 
1731   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1732   SinglePassRunAndMatch<MergeReturnPass>(spirv, true);
1733 }
1734 
TEST_F(MergeReturnPassTest,InnerLoopMergeIsOuterLoopContinue)1735 TEST_F(MergeReturnPassTest, InnerLoopMergeIsOuterLoopContinue) {
1736   const std::string before =
1737       R"(
1738       ; CHECK: OpSelectionMerge
1739       ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]]
1740       ; CHECK-NEXT: [[def_bb1]] = OpLabel
1741       ; CHECK-NEXT: OpBranch [[outer_loop_header:%\w+]]
1742       ; CHECK: [[outer_loop_header]] = OpLabel
1743       ; CHECK-NEXT: OpLoopMerge [[outer_loop_merge:%\w+]] [[outer_loop_continue:%\w+]] None
1744       ; CHECK: [[outer_loop_continue]] = OpLabel
1745       ; CHECK-NEXT: OpBranch [[outer_loop_header]]
1746                OpCapability Shader
1747           %1 = OpExtInstImport "GLSL.std.450"
1748                OpMemoryModel Logical GLSL450
1749                OpEntryPoint Fragment %2 "main"
1750                OpExecutionMode %2 OriginUpperLeft
1751                OpSource ESSL 310
1752        %void = OpTypeVoid
1753           %4 = OpTypeFunction %void
1754        %bool = OpTypeBool
1755           %6 = OpTypeFunction %bool
1756        %true = OpConstantTrue %bool
1757           %2 = OpFunction %void None %4
1758           %8 = OpLabel
1759           %9 = OpFunctionCall %bool %10
1760                OpReturn
1761                OpFunctionEnd
1762          %10 = OpFunction %bool None %6
1763          %11 = OpLabel
1764                OpBranch %12
1765          %12 = OpLabel
1766                OpLoopMerge %13 %14 None
1767                OpBranchConditional %true %15 %13
1768          %15 = OpLabel
1769                OpLoopMerge %14 %16 None
1770                OpBranchConditional %true %17 %14
1771          %17 = OpLabel
1772                OpReturnValue %true
1773          %16 = OpLabel
1774                OpBranch %15
1775          %14 = OpLabel
1776                OpBranch %12
1777          %13 = OpLabel
1778                OpReturnValue %true
1779                OpFunctionEnd
1780 )";
1781 
1782   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1783   SinglePassRunAndMatch<MergeReturnPass>(before, false);
1784 }
1785 
TEST_F(MergeReturnPassTest,BreakFromLoopUseNoLongerDominated)1786 TEST_F(MergeReturnPassTest, BreakFromLoopUseNoLongerDominated) {
1787   const std::string spirv = R"(
1788 ; CHECK: [[undef:%\w+]] = OpUndef
1789 ; CHECK: OpSelectionMerge
1790 ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]]
1791 ; CHECK-NEXT: [[def_bb1]] = OpLabel
1792 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]]
1793 ; CHECK-NEXT: OpBranch [[body:%\w+]]
1794 ; CHECK: [[body]] = OpLabel
1795 ; CHECK-NEXT: OpSelectionMerge [[non_ret:%\w+]]
1796 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[ret:%\w+]] [[non_ret]]
1797 ; CHECK: [[ret]] = OpLabel
1798 ; CHECK-NEXT: OpStore
1799 ; CHECK-NEXT: OpBranch [[merge]]
1800 ; CHECK: [[non_ret]] = OpLabel
1801 ; CHECK-NEXT: [[def:%\w+]] = OpLogicalNot
1802 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[break:%\w+]] [[cont]]
1803 ; CHECK: [[break]] = OpLabel
1804 ; CHECK-NEXT: OpBranch [[merge]]
1805 ; CHECK: [[cont]] = OpLabel
1806 ; CHECK-NEXT: OpBranchConditional {{%\w+}} {{%\w+}} [[merge]]
1807 ; CHECK: [[merge]] = OpLabel
1808 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} [[undef]] [[ret]] [[def]] [[break]] [[def]] [[cont]]
1809 ; CHECK: OpLogicalNot {{%\w+}} [[phi]]
1810 OpCapability Shader
1811 OpMemoryModel Logical GLSL450
1812 OpEntryPoint GLCompute %func "func"
1813 OpExecutionMode %func LocalSize 1 1 1
1814 %void = OpTypeVoid
1815 %void_fn = OpTypeFunction %void
1816 %bool = OpTypeBool
1817 %true = OpConstantTrue %bool
1818 %func = OpFunction %void None %void_fn
1819 %1 = OpLabel
1820 OpBranch %2
1821 %2 = OpLabel
1822 OpLoopMerge %8 %7 None
1823 OpBranch %3
1824 %3 = OpLabel
1825 OpSelectionMerge %5 None
1826 OpBranchConditional %true %4 %5
1827 %4 = OpLabel
1828 OpReturn
1829 %5 = OpLabel
1830 %def = OpLogicalNot %bool %true
1831 OpBranchConditional %true %6 %7
1832 %6 = OpLabel
1833 OpBranch %8
1834 %7 = OpLabel
1835 OpBranchConditional %true %2 %8
1836 %8 = OpLabel
1837 OpBranch %9
1838 %9 = OpLabel
1839 %use = OpLogicalNot %bool %def
1840 OpReturn
1841 OpFunctionEnd
1842 )";
1843 
1844   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1845   SinglePassRunAndMatch<MergeReturnPass>(spirv, true);
1846 }
1847 
TEST_F(MergeReturnPassTest,TwoBreaksFromLoopUsesNoLongerDominated)1848 TEST_F(MergeReturnPassTest, TwoBreaksFromLoopUsesNoLongerDominated) {
1849   const std::string spirv = R"(
1850 ; CHECK: [[undef:%\w+]] = OpUndef
1851 ; CHECK: OpSelectionMerge
1852 ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]]
1853 ; CHECK-NEXT: [[def_bb1]] = OpLabel
1854 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]]
1855 ; CHECK-NEXT: OpBranch [[body:%\w+]]
1856 ; CHECK: [[body]] = OpLabel
1857 ; CHECK-NEXT: OpSelectionMerge [[body2:%\w+]]
1858 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[ret1:%\w+]] [[body2]]
1859 ; CHECK: [[ret1]] = OpLabel
1860 ; CHECK-NEXT: OpStore
1861 ; CHECK-NEXT: OpBranch [[merge]]
1862 ; CHECK: [[body2]] = OpLabel
1863 ; CHECK-NEXT: [[def1:%\w+]] = OpLogicalNot
1864 ; CHECK-NEXT: OpSelectionMerge [[body3:%\w+]]
1865 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[ret2:%\w+]] [[body3:%\w+]]
1866 ; CHECK: [[ret2]] = OpLabel
1867 ; CHECK-NEXT: OpStore
1868 ; CHECK-NEXT: OpBranch [[merge]]
1869 ; CHECK: [[body3]] = OpLabel
1870 ; CHECK-NEXT: [[def2:%\w+]] = OpLogicalAnd
1871 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[break:%\w+]] [[cont]]
1872 ; CHECK: [[break]] = OpLabel
1873 ; CHECK-NEXT: OpBranch [[merge]]
1874 ; CHECK: [[cont]] = OpLabel
1875 ; CHECK-NEXT: OpBranchConditional {{%\w+}} {{%\w+}} [[merge]]
1876 ; CHECK: [[merge]] = OpLabel
1877 ; CHECK-NEXT: [[phi1:%\w+]] = OpPhi {{%\w+}} [[undef]] [[ret1]] [[undef]] [[ret2]] [[def1]] [[break]] [[def1]] [[cont]]
1878 ; CHECK-NEXT: [[phi2:%\w+]] = OpPhi {{%\w+}} [[undef]] [[ret1]] [[undef]] [[ret2]] [[def2]] [[break]] [[def2]] [[cont]]
1879 ; CHECK: OpLogicalNot {{%\w+}} [[phi1]]
1880 ; CHECK: OpLogicalAnd {{%\w+}} [[phi2]]
1881 OpCapability Shader
1882 OpMemoryModel Logical GLSL450
1883 OpEntryPoint GLCompute %func "func"
1884 OpExecutionMode %func LocalSize 1 1 1
1885 %void = OpTypeVoid
1886 %void_fn = OpTypeFunction %void
1887 %bool = OpTypeBool
1888 %true = OpConstantTrue %bool
1889 %func = OpFunction %void None %void_fn
1890 %1 = OpLabel
1891 OpBranch %2
1892 %2 = OpLabel
1893 OpLoopMerge %10 %9 None
1894 OpBranch %3
1895 %3 = OpLabel
1896 OpSelectionMerge %5 None
1897 OpBranchConditional %true %4 %5
1898 %4 = OpLabel
1899 OpReturn
1900 %5 = OpLabel
1901 %def1 = OpLogicalNot %bool %true
1902 OpSelectionMerge %7 None
1903 OpBranchConditional %true %6 %7
1904 %6 = OpLabel
1905 OpReturn
1906 %7 = OpLabel
1907 %def2 = OpLogicalAnd %bool %true %true
1908 OpBranchConditional %true %8 %9
1909 %8 = OpLabel
1910 OpBranch %10
1911 %9 = OpLabel
1912 OpBranchConditional %true %2 %10
1913 %10 = OpLabel
1914 OpBranch %11
1915 %11 = OpLabel
1916 %use1 = OpLogicalNot %bool %def1
1917 %use2 = OpLogicalAnd %bool %def2 %true
1918 OpReturn
1919 OpFunctionEnd
1920 )";
1921 
1922   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1923   SinglePassRunAndMatch<MergeReturnPass>(spirv, true);
1924 }
1925 
TEST_F(MergeReturnPassTest,PredicateBreakBlock)1926 TEST_F(MergeReturnPassTest, PredicateBreakBlock) {
1927   const std::string spirv = R"(
1928 ; IDs are being preserved so we can rely on basic block labels.
1929 ; CHECK: [[undef:%\w+]] = OpUndef
1930 ; CHECK: [[undef:%\w+]] = OpUndef
1931 ; CHECK: %13 = OpLabel
1932 ; CHECK-NEXT: [[def:%\w+]] = OpLogicalNot
1933 ; CHECK: %8 = OpLabel
1934 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} [[undef]] {{%\w+}} [[undef]] {{%\w+}} [[def]] %13 [[undef]] {{%\w+}}
1935 ; CHECK: OpLogicalAnd {{%\w+}} [[phi]]
1936 OpCapability Shader
1937 OpMemoryModel Logical GLSL450
1938 OpEntryPoint GLCompute %1 "func"
1939 OpExecutionMode %1 LocalSize 1 1 1
1940 %void = OpTypeVoid
1941 %3 = OpTypeFunction %void
1942 %bool = OpTypeBool
1943 %true = OpUndef %bool
1944 %1 = OpFunction %void None %3
1945 %6 = OpLabel
1946 OpBranch %7
1947 %7 = OpLabel
1948 OpLoopMerge %8 %9 None
1949 OpBranch %10
1950 %10 = OpLabel
1951 OpSelectionMerge %11 None
1952 OpBranchConditional %true %12 %13
1953 %12 = OpLabel
1954 OpLoopMerge %14 %15 None
1955 OpBranch %16
1956 %16 = OpLabel
1957 OpReturn
1958 %15 = OpLabel
1959 OpBranch %12
1960 %14 = OpLabel
1961 OpUnreachable
1962 %13 = OpLabel
1963 %17 = OpLogicalNot %bool %true
1964 OpBranch %8
1965 %11 = OpLabel
1966 OpUnreachable
1967 %9 = OpLabel
1968 OpBranch %7
1969 %8 = OpLabel
1970 OpBranch %18
1971 %18 = OpLabel
1972 %19 = OpLogicalAnd %bool %17 %true
1973 OpReturn
1974 OpFunctionEnd
1975 )";
1976 
1977   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1978   SinglePassRunAndMatch<MergeReturnPass>(spirv, true);
1979 }
1980 
TEST_F(MergeReturnPassTest,SingleReturnInLoop)1981 TEST_F(MergeReturnPassTest, SingleReturnInLoop) {
1982   const std::string predefs =
1983       R"(OpCapability Shader
1984 %1 = OpExtInstImport "GLSL.std.450"
1985 OpMemoryModel Logical GLSL450
1986 OpEntryPoint Fragment %main "main"
1987 OpExecutionMode %main OriginUpperLeft
1988 OpSource ESSL 310
1989 %void = OpTypeVoid
1990 %7 = OpTypeFunction %void
1991 %float = OpTypeFloat 32
1992 %9 = OpTypeFunction %float
1993 %float_1 = OpConstant %float 1
1994 )";
1995 
1996   const std::string caller =
1997       R"(
1998 ; CHECK: OpFunction
1999 ; CHECK: OpFunctionEnd
2000 %main = OpFunction %void None %7
2001 %22 = OpLabel
2002 %30 = OpFunctionCall %float %f_
2003 OpReturn
2004 OpFunctionEnd
2005 )";
2006 
2007   const std::string callee =
2008       R"(
2009 ; CHECK: OpFunction
2010 ; CHECK: OpLoopMerge [[merge:%\w+]]
2011 ; CHECK: [[merge]] = OpLabel
2012 ; CHECK: OpReturnValue
2013 ; CHECK-NEXT: OpFunctionEnd
2014 %f_ = OpFunction %float None %9
2015 %33 = OpLabel
2016 OpBranch %34
2017 %34 = OpLabel
2018 OpLoopMerge %35 %36 None
2019 OpBranch %37
2020 %37 = OpLabel
2021 OpReturnValue %float_1
2022 %36 = OpLabel
2023 OpBranch %34
2024 %35 = OpLabel
2025 OpUnreachable
2026 OpFunctionEnd
2027 )";
2028 
2029   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2030   SinglePassRunAndMatch<MergeReturnPass>(predefs + caller + callee, true);
2031 }
2032 
TEST_F(MergeReturnPassTest,MergeToMergeBranch)2033 TEST_F(MergeReturnPassTest, MergeToMergeBranch) {
2034   const std::string text =
2035       R"(
2036 ; CHECK: [[new_undef:%\w+]] = OpUndef %uint
2037 ; CHECK: OpSelectionMerge
2038 ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]]
2039 ; CHECK-NEXT: [[def_bb1]] = OpLabel
2040 ; CHECK: OpLoopMerge [[merge1:%\w+]]
2041 ; CHECK: OpLoopMerge [[merge2:%\w+]]
2042 ; CHECK: [[merge1]] = OpLabel
2043 ; CHECK-NEXT: OpPhi %uint [[new_undef]] [[merge2]]
2044                OpCapability Shader
2045           %1 = OpExtInstImport "GLSL.std.450"
2046                OpMemoryModel Logical GLSL450
2047                OpEntryPoint GLCompute %2 "main"
2048                OpExecutionMode %2 LocalSize 100 1 1
2049                OpSource ESSL 310
2050        %void = OpTypeVoid
2051           %4 = OpTypeFunction %void
2052        %uint = OpTypeInt 32 0
2053      %uint_1 = OpConstant %uint 1
2054        %bool = OpTypeBool
2055       %false = OpConstantFalse %bool
2056      %uint_0 = OpConstant %uint 0
2057         %int = OpTypeInt 32 1
2058       %int_0 = OpConstant %int 0
2059       %int_1 = OpConstant %int 1
2060          %13 = OpUndef %bool
2061           %2 = OpFunction %void None %4
2062          %14 = OpLabel
2063                OpBranch %15
2064          %15 = OpLabel
2065                OpLoopMerge %16 %17 None
2066                OpBranch %18
2067          %18 = OpLabel
2068                OpLoopMerge %19 %20 None
2069                OpBranchConditional %13 %21 %19
2070          %21 = OpLabel
2071                OpReturn
2072          %20 = OpLabel
2073                OpBranch %18
2074          %19 = OpLabel
2075          %22 = OpUndef %uint
2076                OpBranch %23
2077          %23 = OpLabel
2078                OpBranch %16
2079          %17 = OpLabel
2080                OpBranch %15
2081          %16 = OpLabel
2082          %24 = OpCopyObject %uint %22
2083                OpReturn
2084                OpFunctionEnd
2085 )";
2086 
2087   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2088   SinglePassRunAndMatch<MergeReturnPass>(text, true);
2089 }
2090 
TEST_F(MergeReturnPassTest,PhiInSecondMerge)2091 TEST_F(MergeReturnPassTest, PhiInSecondMerge) {
2092   //  Add and use a phi in the second merge block from the return.
2093   const std::string text =
2094       R"(
2095 ; CHECK: OpSelectionMerge
2096 ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]]
2097 ; CHECK-NEXT: [[def_bb1]] = OpLabel
2098 ; CHECK: OpLoopMerge [[merge_bb:%\w+]] [[continue_bb:%\w+]]
2099 ; CHECK: [[continue_bb]] = OpLabel
2100 ; CHECK-NEXT: [[val:%\w+]] = OpUndef %float
2101 ; CHECK: [[merge_bb]] = OpLabel
2102 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[val]] [[continue_bb]]
2103 ; CHECK-NOT: OpLabel
2104 ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} [[old_merge:%\w+]]
2105 ; CHECK: [[old_merge]] = OpLabel
2106 ; CHECK-NEXT: OpConvertFToS %int [[phi]]
2107                OpCapability Shader
2108           %1 = OpExtInstImport "GLSL.std.450"
2109                OpMemoryModel Logical GLSL450
2110                OpEntryPoint Fragment %2 "main"
2111                OpExecutionMode %2 OriginUpperLeft
2112                OpSource ESSL 310
2113        %void = OpTypeVoid
2114           %4 = OpTypeFunction %void
2115         %int = OpTypeInt 32 1
2116       %float = OpTypeFloat 32
2117        %bool = OpTypeBool
2118           %8 = OpUndef %bool
2119           %2 = OpFunction %void None %4
2120           %9 = OpLabel
2121                OpBranch %10
2122          %10 = OpLabel
2123                OpLoopMerge %11 %12 None
2124                OpBranch %13
2125          %13 = OpLabel
2126                OpLoopMerge %18 %14 None
2127                OpBranchConditional %8 %15 %18
2128          %15 = OpLabel
2129                OpReturn
2130          %14 = OpLabel
2131                OpBranch %13
2132          %18 = OpLabel
2133                OpBranch %12
2134          %12 = OpLabel
2135          %16 = OpUndef %float
2136                OpBranchConditional %8 %10 %11
2137          %11 = OpLabel
2138          %17 = OpConvertFToS %int %16
2139                OpReturn
2140                OpFunctionEnd
2141 )";
2142 
2143   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2144   SinglePassRunAndMatch<MergeReturnPass>(text, true);
2145 }
2146 
TEST_F(MergeReturnPassTest,ReturnsInSwitch)2147 TEST_F(MergeReturnPassTest, ReturnsInSwitch) {
2148   //  Cannot branch directly to single case switch merge block from original
2149   //  switch. Must branch to merge block of original switch and then do
2150   //  predicated branch to merge block of single case switch.
2151   const std::string text =
2152       R"(
2153 ; CHECK: OpSelectionMerge [[single_case_switch_merge_bb:%\w+]]
2154 ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]]
2155 ; CHECK-NEXT: [[def_bb1]] = OpLabel
2156 ; CHECK: OpSelectionMerge
2157 ; CHECK-NEXT: OpSwitch {{%\w+}} [[inner_merge_bb:%\w+]] 0 {{%\w+}} 1 {{%\w+}}
2158 ; CHECK: OpBranch [[inner_merge_bb]]
2159 ; CHECK: OpBranch [[inner_merge_bb]]
2160 ; CHECK-NEXT: [[inner_merge_bb]] = OpLabel
2161 ; CHECK: OpBranchConditional {{%\w+}} [[single_case_switch_merge_bb]] {{%\w+}}
2162                OpCapability Shader
2163           %1 = OpExtInstImport "GLSL.std.450"
2164                OpMemoryModel Logical GLSL450
2165                OpEntryPoint Fragment %PSMain "PSMain" %_entryPointOutput_color
2166                OpExecutionMode %PSMain OriginUpperLeft
2167                OpSource HLSL 500
2168                OpMemberDecorate %cb 0 Offset 0
2169                OpMemberDecorate %cb 1 Offset 16
2170                OpMemberDecorate %cb 2 Offset 32
2171                OpMemberDecorate %cb 3 Offset 48
2172                OpDecorate %cb Block
2173                OpDecorate %_ DescriptorSet 0
2174                OpDecorate %_ Binding 0
2175                OpDecorate %_entryPointOutput_color Location 0
2176        %void = OpTypeVoid
2177           %3 = OpTypeFunction %void
2178       %float = OpTypeFloat 32
2179     %v4float = OpTypeVector %float 4
2180           %8 = OpTypeFunction %v4float
2181         %int = OpTypeInt 32 1
2182          %cb = OpTypeStruct %v4float %v4float %v4float %int
2183 %_ptr_Uniform_cb = OpTypePointer Uniform %cb
2184           %_ = OpVariable %_ptr_Uniform_cb Uniform
2185       %int_3 = OpConstant %int 3
2186 %_ptr_Uniform_int = OpTypePointer Uniform %int
2187       %int_0 = OpConstant %int 0
2188 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
2189       %int_1 = OpConstant %int 1
2190       %int_2 = OpConstant %int 2
2191     %float_0 = OpConstant %float 0
2192     %float_1 = OpConstant %float 1
2193          %45 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
2194 %_ptr_Function_v4float = OpTypePointer Function %v4float
2195 %_ptr_Output_v4float = OpTypePointer Output %v4float
2196 %_entryPointOutput_color = OpVariable %_ptr_Output_v4float Output
2197      %PSMain = OpFunction %void None %3
2198           %5 = OpLabel
2199          %50 = OpFunctionCall %v4float %BlendValue_
2200                OpStore %_entryPointOutput_color %50
2201                OpReturn
2202                OpFunctionEnd
2203 %BlendValue_ = OpFunction %v4float None %8
2204          %10 = OpLabel
2205          %21 = OpAccessChain %_ptr_Uniform_int %_ %int_3
2206          %22 = OpLoad %int %21
2207                OpSelectionMerge %25 None
2208                OpSwitch %22 %25 0 %23 1 %24
2209          %23 = OpLabel
2210          %28 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0
2211          %29 = OpLoad %v4float %28
2212                OpReturnValue %29
2213          %24 = OpLabel
2214          %31 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0
2215          %32 = OpLoad %v4float %31
2216          %34 = OpAccessChain %_ptr_Uniform_v4float %_ %int_1
2217          %35 = OpLoad %v4float %34
2218          %37 = OpAccessChain %_ptr_Uniform_v4float %_ %int_2
2219          %38 = OpLoad %v4float %37
2220          %39 = OpFMul %v4float %35 %38
2221          %40 = OpFAdd %v4float %32 %39
2222                OpReturnValue %40
2223          %25 = OpLabel
2224                OpReturnValue %45
2225                OpFunctionEnd
2226 )";
2227 
2228   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2229   SinglePassRunAndMatch<MergeReturnPass>(text, true);
2230 }
2231 
TEST_F(MergeReturnPassTest,UnreachableMergeAndContinue)2232 TEST_F(MergeReturnPassTest, UnreachableMergeAndContinue) {
2233   // Make sure that the pass can handle a single block that is both a merge and
2234   // a continue.
2235   const std::string text =
2236       R"(
2237                OpCapability Shader
2238           %1 = OpExtInstImport "GLSL.std.450"
2239                OpMemoryModel Logical GLSL450
2240                OpEntryPoint Fragment %2 "main"
2241                OpExecutionMode %2 OriginUpperLeft
2242                OpSource ESSL 310
2243        %void = OpTypeVoid
2244           %4 = OpTypeFunction %void
2245        %bool = OpTypeBool
2246        %true = OpConstantTrue %bool
2247           %2 = OpFunction %void None %4
2248           %7 = OpLabel
2249                OpBranch %8
2250           %8 = OpLabel
2251                OpLoopMerge %9 %10 None
2252                OpBranch %11
2253          %11 = OpLabel
2254                OpSelectionMerge %10 None
2255                OpBranchConditional %true %12 %13
2256          %12 = OpLabel
2257                OpReturn
2258          %13 = OpLabel
2259                OpReturn
2260          %10 = OpLabel
2261                OpBranch %8
2262           %9 = OpLabel
2263                OpUnreachable
2264                OpFunctionEnd
2265 )";
2266 
2267   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2268   auto result = SinglePassRunAndDisassemble<MergeReturnPass>(text, true, true);
2269 
2270   // Not looking for any particular output.  Other tests do that.
2271   // Just want to make sure the check for unreachable blocks does not emit an
2272   // error.
2273   EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
2274 }
2275 
TEST_F(MergeReturnPassTest,SingleReturnInMiddle)2276 TEST_F(MergeReturnPassTest, SingleReturnInMiddle) {
2277   const std::string before =
2278       R"(
2279 ; CHECK: OpFunction
2280 ; CHECK: OpReturn
2281 ; CHECK-NEXT: OpFunctionEnd
2282                OpCapability Shader
2283                OpMemoryModel Logical GLSL450
2284                OpEntryPoint Vertex %main "main"
2285                OpSource GLSL 450
2286                OpName %main "main"
2287                OpName %foo_ "foo("
2288        %void = OpTypeVoid
2289           %4 = OpTypeFunction %void
2290        %bool = OpTypeBool
2291        %true = OpConstantTrue %bool
2292        %foo_ = OpFunction %void None %4
2293           %7 = OpLabel
2294                OpSelectionMerge %8 None
2295                OpBranchConditional %true %9 %8
2296           %8 = OpLabel
2297                OpReturn
2298           %9 = OpLabel
2299                OpBranch %8
2300                OpFunctionEnd
2301        %main = OpFunction %void None %4
2302          %10 = OpLabel
2303          %11 = OpFunctionCall %void %foo_
2304                OpReturn
2305                OpFunctionEnd
2306 )";
2307 
2308   SinglePassRunAndMatch<MergeReturnPass>(before, false);
2309 }
2310 
TEST_F(MergeReturnPassTest,PhiWithTooManyEntries)2311 TEST_F(MergeReturnPassTest, PhiWithTooManyEntries) {
2312   // Check that the OpPhi node has the correct number of entries.  This is
2313   // checked by doing validation with the match.
2314   const std::string before =
2315       R"(
2316 ; CHECK: OpLoopMerge [[merge:%\w+]]
2317 ; CHECK: [[merge]] = OpLabel
2318 ; CHECK-NEXT: {{%\w+}} = OpPhi %int {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
2319                OpCapability Shader
2320           %1 = OpExtInstImport "GLSL.std.450"
2321                OpMemoryModel Logical GLSL450
2322                OpEntryPoint Fragment %2 "main"
2323                OpExecutionMode %2 OriginUpperLeft
2324        %void = OpTypeVoid
2325           %4 = OpTypeFunction %void
2326         %int = OpTypeInt 32 1
2327           %6 = OpTypeFunction %int
2328        %bool = OpTypeBool
2329       %int_1 = OpConstant %int 1
2330       %false = OpConstantFalse %bool
2331           %2 = OpFunction %void None %4
2332          %10 = OpLabel
2333          %11 = OpFunctionCall %int %12
2334                OpReturn
2335                OpFunctionEnd
2336          %12 = OpFunction %int None %6
2337          %13 = OpLabel
2338                OpBranch %14
2339          %14 = OpLabel
2340          %15 = OpPhi %int %int_1 %13 %16 %17
2341                OpLoopMerge %18 %17 None
2342                OpBranch %19
2343          %19 = OpLabel
2344          %20 = OpUndef %bool
2345                OpBranch %21
2346          %21 = OpLabel
2347                OpLoopMerge %22 %23 None
2348                OpBranch %24
2349          %24 = OpLabel
2350                OpSelectionMerge %25 None
2351                OpBranchConditional %20 %22 %25
2352          %25 = OpLabel
2353                OpReturnValue %int_1
2354          %23 = OpLabel
2355                OpBranch %21
2356          %22 = OpLabel
2357                OpSelectionMerge %26 None
2358                OpBranchConditional %20 %27 %26
2359          %27 = OpLabel
2360                OpBranch %28
2361          %28 = OpLabel
2362                OpLoopMerge %29 %30 None
2363                OpBranch %31
2364          %31 = OpLabel
2365                OpReturnValue %int_1
2366          %30 = OpLabel
2367                OpBranch %28
2368          %29 = OpLabel
2369                OpUnreachable
2370          %26 = OpLabel
2371                OpBranch %17
2372          %17 = OpLabel
2373          %16 = OpPhi %int %15 %26
2374                OpBranchConditional %false %14 %18
2375          %18 = OpLabel
2376                OpReturnValue %16
2377                OpFunctionEnd
2378 )";
2379 
2380   SinglePassRunAndMatch<MergeReturnPass>(before, true);
2381 }
2382 
TEST_F(MergeReturnPassTest,PointerUsedAfterLoop)2383 TEST_F(MergeReturnPassTest, PointerUsedAfterLoop) {
2384   // Make sure that a Phi instruction is not generated for an id whose type is a
2385   // pointer.  It needs to be regenerated.
2386   const std::string before =
2387       R"(
2388 ; CHECK: OpFunction %void
2389 ; CHECK: OpFunction %void
2390 ; CHECK-NEXT: [[param:%\w+]] = OpFunctionParameter %_ptr_Function_v2uint
2391 ; CHECK: OpLoopMerge [[merge_bb:%\w+]]
2392 ; CHECK: [[merge_bb]] = OpLabel
2393 ; CHECK-NEXT: [[ac:%\w+]] = OpAccessChain %_ptr_Function_uint [[param]] %uint_1
2394 ; CHECK: OpStore [[ac]] %uint_1
2395                OpCapability Shader
2396           %1 = OpExtInstImport "GLSL.std.450"
2397                OpMemoryModel Logical GLSL450
2398                OpEntryPoint Fragment %2 "main"
2399                OpExecutionMode %2 OriginUpperLeft
2400                OpSource ESSL 310
2401        %void = OpTypeVoid
2402           %4 = OpTypeFunction %void
2403        %uint = OpTypeInt 32 0
2404      %v2uint = OpTypeVector %uint 2
2405 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
2406           %8 = OpTypeFunction %void %_ptr_Function_v2uint
2407      %uint_1 = OpConstant %uint 1
2408        %bool = OpTypeBool
2409 %_ptr_Function_uint = OpTypePointer Function %uint
2410       %false = OpConstantFalse %bool
2411           %2 = OpFunction %void None %4
2412          %13 = OpLabel
2413          %14 = OpVariable %_ptr_Function_v2uint Function
2414          %15 = OpFunctionCall %void %16 %14
2415                OpReturn
2416                OpFunctionEnd
2417          %16 = OpFunction %void None %8
2418          %17 = OpFunctionParameter %_ptr_Function_v2uint
2419          %18 = OpLabel
2420                OpBranch %19
2421          %19 = OpLabel
2422                OpLoopMerge %20 %21 None
2423                OpBranch %22
2424          %22 = OpLabel
2425                OpSelectionMerge %23 None
2426                OpBranchConditional %false %24 %23
2427          %24 = OpLabel
2428                OpReturn
2429          %23 = OpLabel
2430                OpBranch %21
2431          %21 = OpLabel
2432          %25 = OpAccessChain %_ptr_Function_uint %17 %uint_1
2433                OpBranchConditional %false %19 %20
2434          %20 = OpLabel
2435                OpStore %25 %uint_1
2436                OpReturn
2437                OpFunctionEnd
2438 )";
2439 
2440   SinglePassRunAndMatch<MergeReturnPass>(before, true);
2441 }
2442 
TEST_F(MergeReturnPassTest,VariablePointerFunctionScope)2443 TEST_F(MergeReturnPassTest, VariablePointerFunctionScope) {
2444   // Make sure that a Phi instruction is not generated for an id whose type is a
2445   // function scope pointer, even if the VariablePointers capability is
2446   // available.  It needs to be regenerated.
2447   const std::string before =
2448       R"(
2449 ; CHECK: OpFunction %void
2450 ; CHECK: OpFunction %void
2451 ; CHECK-NEXT: [[param:%\w+]] = OpFunctionParameter %_ptr_Function_v2uint
2452 ; CHECK: OpLoopMerge [[merge_bb:%\w+]]
2453 ; CHECK: [[merge_bb]] = OpLabel
2454 ; CHECK-NEXT: [[ac:%\w+]] = OpAccessChain %_ptr_Function_uint [[param]] %uint_1
2455 ; CHECK: OpStore [[ac]] %uint_1
2456                OpCapability Shader
2457                OpCapability VariablePointers
2458           %1 = OpExtInstImport "GLSL.std.450"
2459                OpMemoryModel Logical GLSL450
2460                OpEntryPoint Fragment %2 "main"
2461                OpExecutionMode %2 OriginUpperLeft
2462                OpSource ESSL 310
2463        %void = OpTypeVoid
2464           %4 = OpTypeFunction %void
2465        %uint = OpTypeInt 32 0
2466      %v2uint = OpTypeVector %uint 2
2467 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
2468           %8 = OpTypeFunction %void %_ptr_Function_v2uint
2469      %uint_1 = OpConstant %uint 1
2470        %bool = OpTypeBool
2471 %_ptr_Function_uint = OpTypePointer Function %uint
2472       %false = OpConstantFalse %bool
2473           %2 = OpFunction %void None %4
2474          %13 = OpLabel
2475          %14 = OpVariable %_ptr_Function_v2uint Function
2476          %15 = OpFunctionCall %void %16 %14
2477                OpReturn
2478                OpFunctionEnd
2479          %16 = OpFunction %void None %8
2480          %17 = OpFunctionParameter %_ptr_Function_v2uint
2481          %18 = OpLabel
2482                OpBranch %19
2483          %19 = OpLabel
2484                OpLoopMerge %20 %21 None
2485                OpBranch %22
2486          %22 = OpLabel
2487                OpSelectionMerge %23 None
2488                OpBranchConditional %false %24 %23
2489          %24 = OpLabel
2490                OpReturn
2491          %23 = OpLabel
2492                OpBranch %21
2493          %21 = OpLabel
2494          %25 = OpAccessChain %_ptr_Function_uint %17 %uint_1
2495                OpBranchConditional %false %19 %20
2496          %20 = OpLabel
2497                OpStore %25 %uint_1
2498                OpReturn
2499                OpFunctionEnd
2500 )";
2501 
2502   SinglePassRunAndMatch<MergeReturnPass>(before, true);
2503 }
2504 
TEST_F(MergeReturnPassTest,ChainedPointerUsedAfterLoop)2505 TEST_F(MergeReturnPassTest, ChainedPointerUsedAfterLoop) {
2506   // Make sure that a Phi instruction is not generated for an id whose type is a
2507   // pointer.  It needs to be regenerated.
2508   const std::string before =
2509       R"(
2510 ; CHECK: OpFunction %void
2511 ; CHECK: OpFunction %void
2512 ; CHECK-NEXT: [[param:%\w+]] = OpFunctionParameter %_ptr_Function_
2513 ; CHECK: OpLoopMerge [[merge_bb:%\w+]]
2514 ; CHECK: [[merge_bb]] = OpLabel
2515 ; CHECK-NEXT: [[ac1:%\w+]] = OpAccessChain %_ptr_Function_v2uint [[param]] %uint_1
2516 ; CHECK-NEXT: [[ac2:%\w+]] = OpAccessChain %_ptr_Function_uint [[ac1]] %uint_1
2517 ; CHECK: OpStore [[ac2]] %uint_1
2518                OpCapability Shader
2519           %1 = OpExtInstImport "GLSL.std.450"
2520                OpMemoryModel Logical GLSL450
2521                OpEntryPoint Fragment %2 "main"
2522                OpExecutionMode %2 OriginUpperLeft
2523                OpSource ESSL 310
2524        %void = OpTypeVoid
2525           %4 = OpTypeFunction %void
2526        %uint = OpTypeInt 32 0
2527      %uint_1 = OpConstant %uint 1
2528      %uint_2 = OpConstant %uint 2
2529      %v2uint = OpTypeVector %uint 2
2530 %_arr_v2uint_uint_2 = OpTypeArray %v2uint %uint_2
2531 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
2532 %_ptr_Function__arr_v2uint_uint_2 = OpTypePointer Function %_arr_v2uint_uint_2
2533 %_ptr_Function_uint = OpTypePointer Function %uint
2534          %13 = OpTypeFunction %void %_ptr_Function__arr_v2uint_uint_2
2535        %bool = OpTypeBool
2536       %false = OpConstantFalse %bool
2537           %2 = OpFunction %void None %4
2538          %16 = OpLabel
2539          %17 = OpVariable %_ptr_Function__arr_v2uint_uint_2 Function
2540          %18 = OpFunctionCall %void %19 %17
2541                OpReturn
2542                OpFunctionEnd
2543          %19 = OpFunction %void None %13
2544          %20 = OpFunctionParameter %_ptr_Function__arr_v2uint_uint_2
2545          %21 = OpLabel
2546                OpBranch %22
2547          %22 = OpLabel
2548                OpLoopMerge %23 %24 None
2549                OpBranch %25
2550          %25 = OpLabel
2551                OpSelectionMerge %26 None
2552                OpBranchConditional %false %27 %26
2553          %27 = OpLabel
2554                OpReturn
2555          %26 = OpLabel
2556                OpBranch %24
2557          %24 = OpLabel
2558          %28 = OpAccessChain %_ptr_Function_v2uint %20 %uint_1
2559          %29 = OpAccessChain %_ptr_Function_uint %28 %uint_1
2560                OpBranchConditional %false %22 %23
2561          %23 = OpLabel
2562                OpStore %29 %uint_1
2563                OpReturn
2564                OpFunctionEnd
2565 )";
2566 
2567   SinglePassRunAndMatch<MergeReturnPass>(before, true);
2568 }
2569 
TEST_F(MergeReturnPassTest,OverflowTest1)2570 TEST_F(MergeReturnPassTest, OverflowTest1) {
2571   const std::string text =
2572       R"(
2573 ; CHECK: OpReturn
2574 ; CHECK-NOT: OpReturn
2575 ; CHECK: OpFunctionEnd
2576                OpCapability ClipDistance
2577                OpMemoryModel Logical GLSL450
2578                OpEntryPoint Fragment %2 "main"
2579                OpExecutionMode %2 OriginUpperLeft
2580        %void = OpTypeVoid
2581           %6 = OpTypeFunction %void
2582           %2 = OpFunction %void None %6
2583     %4194303 = OpLabel
2584                OpBranch %18
2585          %18 = OpLabel
2586                OpLoopMerge %19 %20 None
2587                OpBranch %21
2588          %21 = OpLabel
2589                OpReturn
2590          %20 = OpLabel
2591                OpBranch %18
2592          %19 = OpLabel
2593                OpUnreachable
2594                OpFunctionEnd
2595 )";
2596 
2597   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2598   auto result =
2599       SinglePassRunToBinary<MergeReturnPass>(text, /* skip_nop = */ true);
2600   EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
2601 }
2602 
2603 }  // namespace
2604 }  // namespace opt
2605 }  // namespace spvtools
2606