1 // Copyright (c) 2018 Google LLC
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 "test/opt/pass_fixture.h"
18 #include "test/opt/pass_utils.h"
19 
20 namespace spvtools {
21 namespace opt {
22 namespace {
23 
24 using IfConversionTest = PassTest<::testing::Test>;
25 
TEST_F(IfConversionTest,TestSimpleIfThenElse)26 TEST_F(IfConversionTest, TestSimpleIfThenElse) {
27   const std::string text = R"(
28 ; CHECK: OpSelectionMerge [[merge:%\w+]]
29 ; CHECK: [[merge]] = OpLabel
30 ; CHECK-NOT: OpPhi
31 ; CHECK: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
32 ; CHECK OpStore {{%\w+}} [[sel]]
33 OpCapability Shader
34 OpMemoryModel Logical GLSL450
35 OpEntryPoint Vertex %1 "func" %2
36 %void = OpTypeVoid
37 %bool = OpTypeBool
38 %true = OpConstantTrue %bool
39 %uint = OpTypeInt 32 0
40 %uint_0 = OpConstant %uint 0
41 %uint_1 = OpConstant %uint 1
42 %_ptr_Output_uint = OpTypePointer Output %uint
43 %2 = OpVariable %_ptr_Output_uint Output
44 %11 = OpTypeFunction %void
45 %1 = OpFunction %void None %11
46 %12 = OpLabel
47 OpSelectionMerge %14 None
48 OpBranchConditional %true %15 %16
49 %15 = OpLabel
50 OpBranch %14
51 %16 = OpLabel
52 OpBranch %14
53 %14 = OpLabel
54 %18 = OpPhi %uint %uint_0 %15 %uint_1 %16
55 OpStore %2 %18
56 OpReturn
57 OpFunctionEnd
58 )";
59 
60   SinglePassRunAndMatch<IfConversion>(text, true);
61 }
62 
TEST_F(IfConversionTest,TestSimpleHalfIfTrue)63 TEST_F(IfConversionTest, TestSimpleHalfIfTrue) {
64   const std::string text = R"(
65 ; CHECK: OpSelectionMerge [[merge:%\w+]]
66 ; CHECK: [[merge]] = OpLabel
67 ; CHECK-NOT: OpPhi
68 ; CHECK: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
69 ; CHECK OpStore {{%\w+}} [[sel]]
70 OpCapability Shader
71 OpMemoryModel Logical GLSL450
72 OpEntryPoint Vertex %1 "func" %2
73 %void = OpTypeVoid
74 %bool = OpTypeBool
75 %true = OpConstantTrue %bool
76 %uint = OpTypeInt 32 0
77 %uint_0 = OpConstant %uint 0
78 %uint_1 = OpConstant %uint 1
79 %_ptr_Output_uint = OpTypePointer Output %uint
80 %2 = OpVariable %_ptr_Output_uint Output
81 %11 = OpTypeFunction %void
82 %1 = OpFunction %void None %11
83 %12 = OpLabel
84 OpSelectionMerge %14 None
85 OpBranchConditional %true %15 %14
86 %15 = OpLabel
87 OpBranch %14
88 %14 = OpLabel
89 %18 = OpPhi %uint %uint_0 %15 %uint_1 %12
90 OpStore %2 %18
91 OpReturn
92 OpFunctionEnd
93 )";
94 
95   SinglePassRunAndMatch<IfConversion>(text, true);
96 }
97 
TEST_F(IfConversionTest,TestSimpleHalfIfExtraBlock)98 TEST_F(IfConversionTest, TestSimpleHalfIfExtraBlock) {
99   const std::string text = R"(
100 ; CHECK: OpSelectionMerge [[merge:%\w+]]
101 ; CHECK: [[merge]] = OpLabel
102 ; CHECK-NOT: OpPhi
103 ; CHECK: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
104 ; CHECK OpStore {{%\w+}} [[sel]]
105 OpCapability Shader
106 OpMemoryModel Logical GLSL450
107 OpEntryPoint Vertex %1 "func" %2
108 %void = OpTypeVoid
109 %bool = OpTypeBool
110 %true = OpConstantTrue %bool
111 %uint = OpTypeInt 32 0
112 %uint_0 = OpConstant %uint 0
113 %uint_1 = OpConstant %uint 1
114 %_ptr_Output_uint = OpTypePointer Output %uint
115 %2 = OpVariable %_ptr_Output_uint Output
116 %11 = OpTypeFunction %void
117 %1 = OpFunction %void None %11
118 %12 = OpLabel
119 OpSelectionMerge %14 None
120 OpBranchConditional %true %15 %14
121 %15 = OpLabel
122 OpBranch %16
123 %16 = OpLabel
124 OpBranch %14
125 %14 = OpLabel
126 %18 = OpPhi %uint %uint_0 %15 %uint_1 %12
127 OpStore %2 %18
128 OpReturn
129 OpFunctionEnd
130 )";
131 
132   SinglePassRunAndMatch<IfConversion>(text, true);
133 }
134 
TEST_F(IfConversionTest,TestSimpleHalfIfFalse)135 TEST_F(IfConversionTest, TestSimpleHalfIfFalse) {
136   const std::string text = R"(
137 ; CHECK: OpSelectionMerge [[merge:%\w+]]
138 ; CHECK: [[merge]] = OpLabel
139 ; CHECK-NOT: OpPhi
140 ; CHECK: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
141 ; CHECK OpStore {{%\w+}} [[sel]]
142 OpCapability Shader
143 OpMemoryModel Logical GLSL450
144 OpEntryPoint Vertex %1 "func" %2
145 %void = OpTypeVoid
146 %bool = OpTypeBool
147 %true = OpConstantTrue %bool
148 %uint = OpTypeInt 32 0
149 %uint_0 = OpConstant %uint 0
150 %uint_1 = OpConstant %uint 1
151 %_ptr_Output_uint = OpTypePointer Output %uint
152 %2 = OpVariable %_ptr_Output_uint Output
153 %11 = OpTypeFunction %void
154 %1 = OpFunction %void None %11
155 %12 = OpLabel
156 OpSelectionMerge %14 None
157 OpBranchConditional %true %14 %15
158 %15 = OpLabel
159 OpBranch %14
160 %14 = OpLabel
161 %18 = OpPhi %uint %uint_0 %12 %uint_1 %15
162 OpStore %2 %18
163 OpReturn
164 OpFunctionEnd
165 )";
166 
167   SinglePassRunAndMatch<IfConversion>(text, true);
168 }
169 
TEST_F(IfConversionTest,TestVectorSplat)170 TEST_F(IfConversionTest, TestVectorSplat) {
171   const std::string text = R"(
172 ; CHECK: [[bool_vec:%\w+]] = OpTypeVector %bool 2
173 ; CHECK: OpSelectionMerge [[merge:%\w+]]
174 ; CHECK: [[merge]] = OpLabel
175 ; CHECK-NOT: OpPhi
176 ; CHECK: [[comp:%\w+]] = OpCompositeConstruct [[bool_vec]] %true %true
177 ; CHECK: [[sel:%\w+]] = OpSelect {{%\w+}} [[comp]]
178 ; CHECK OpStore {{%\w+}} [[sel]]
179 OpCapability Shader
180 OpMemoryModel Logical GLSL450
181 OpEntryPoint Vertex %1 "func" %2
182 %void = OpTypeVoid
183 %bool = OpTypeBool
184 %true = OpConstantTrue %bool
185 %uint = OpTypeInt 32 0
186 %uint_0 = OpConstant %uint 0
187 %uint_1 = OpConstant %uint 1
188 %uint_vec2 = OpTypeVector %uint 2
189 %vec2_01 = OpConstantComposite %uint_vec2 %uint_0 %uint_1
190 %vec2_10 = OpConstantComposite %uint_vec2 %uint_1 %uint_0
191 %_ptr_Output_uint = OpTypePointer Output %uint_vec2
192 %2 = OpVariable %_ptr_Output_uint Output
193 %11 = OpTypeFunction %void
194 %1 = OpFunction %void None %11
195 %12 = OpLabel
196 OpSelectionMerge %14 None
197 OpBranchConditional %true %15 %16
198 %15 = OpLabel
199 OpBranch %14
200 %16 = OpLabel
201 OpBranch %14
202 %14 = OpLabel
203 %18 = OpPhi %uint_vec2 %vec2_01 %15 %vec2_10 %16
204 OpStore %2 %18
205 OpReturn
206 OpFunctionEnd
207 )";
208 
209   SinglePassRunAndMatch<IfConversion>(text, true);
210 }
211 
TEST_F(IfConversionTest,CodeMotionSameValue)212 TEST_F(IfConversionTest, CodeMotionSameValue) {
213   const std::string text = R"(
214 ; CHECK: [[var:%\w+]] = OpVariable
215 ; CHECK: OpFunction
216 ; CHECK: OpLabel
217 ; CHECK-NOT: OpLabel
218 ; CHECK: [[add:%\w+]] = OpIAdd %uint %uint_0 %uint_1
219 ; CHECK: OpSelectionMerge [[merge_lab:%\w+]] None
220 ; CHECK-NEXT: OpBranchConditional
221 ; CHECK: [[merge_lab]] = OpLabel
222 ; CHECK-NOT: OpLabel
223 ; CHECK: OpStore [[var]] [[add]]
224                     OpCapability Shader
225                     OpMemoryModel Logical GLSL450
226                     OpEntryPoint Vertex %1 "func" %2
227             %void = OpTypeVoid
228             %uint = OpTypeInt 32 0
229           %uint_0 = OpConstant %uint 0
230           %uint_1 = OpConstant %uint 1
231 %_ptr_Output_uint = OpTypePointer Output %uint
232                %2 = OpVariable %_ptr_Output_uint Output
233                %8 = OpTypeFunction %void
234             %bool = OpTypeBool
235             %true = OpConstantTrue %bool
236                %1 = OpFunction %void None %8
237               %11 = OpLabel
238                     OpSelectionMerge %12 None
239                     OpBranchConditional %true %13 %15
240               %13 = OpLabel
241               %14 = OpIAdd %uint %uint_0 %uint_1
242                     OpBranch %12
243               %15 = OpLabel
244               %16 = OpIAdd %uint %uint_0 %uint_1
245                     OpBranch %12
246               %12 = OpLabel
247               %17 = OpPhi %uint %16 %15 %14 %13
248                     OpStore %2 %17
249                     OpReturn
250                     OpFunctionEnd
251 )";
252 
253   SinglePassRunAndMatch<IfConversion>(text, true);
254 }
255 
TEST_F(IfConversionTest,CodeMotionMultipleInstructions)256 TEST_F(IfConversionTest, CodeMotionMultipleInstructions) {
257   const std::string text = R"(
258 ; CHECK: [[var:%\w+]] = OpVariable
259 ; CHECK: OpFunction
260 ; CHECK: OpLabel
261 ; CHECK-NOT: OpLabel
262 ; CHECK: [[a1:%\w+]] = OpIAdd %uint %uint_0 %uint_1
263 ; CHECK: [[a2:%\w+]] = OpIAdd %uint [[a1]] %uint_1
264 ; CHECK: OpSelectionMerge [[merge_lab:%\w+]] None
265 ; CHECK-NEXT: OpBranchConditional
266 ; CHECK: [[merge_lab]] = OpLabel
267 ; CHECK-NOT: OpLabel
268 ; CHECK: OpStore [[var]] [[a2]]
269                     OpCapability Shader
270                     OpMemoryModel Logical GLSL450
271                     OpEntryPoint Vertex %1 "func" %2
272             %void = OpTypeVoid
273             %uint = OpTypeInt 32 0
274           %uint_0 = OpConstant %uint 0
275           %uint_1 = OpConstant %uint 1
276 %_ptr_Output_uint = OpTypePointer Output %uint
277                %2 = OpVariable %_ptr_Output_uint Output
278                %8 = OpTypeFunction %void
279             %bool = OpTypeBool
280             %true = OpConstantTrue %bool
281                %1 = OpFunction %void None %8
282               %11 = OpLabel
283                     OpSelectionMerge %12 None
284                     OpBranchConditional %true %13 %15
285               %13 = OpLabel
286               %a1 = OpIAdd %uint %uint_0 %uint_1
287               %a2 = OpIAdd %uint %a1 %uint_1
288                     OpBranch %12
289               %15 = OpLabel
290               %b1 = OpIAdd %uint %uint_0 %uint_1
291               %b2 = OpIAdd %uint %b1 %uint_1
292                     OpBranch %12
293               %12 = OpLabel
294               %17 = OpPhi %uint %b2 %15 %a2 %13
295                     OpStore %2 %17
296                     OpReturn
297                     OpFunctionEnd
298 )";
299 
300   SinglePassRunAndMatch<IfConversion>(text, true);
301 }
302 
TEST_F(IfConversionTest,NoCommonDominator)303 TEST_F(IfConversionTest, NoCommonDominator) {
304   const std::string text = R"(OpCapability Shader
305 OpMemoryModel Logical GLSL450
306 OpEntryPoint Vertex %1 "func" %2
307 %void = OpTypeVoid
308 %uint = OpTypeInt 32 0
309 %uint_0 = OpConstant %uint 0
310 %uint_1 = OpConstant %uint 1
311 %_ptr_Output_uint = OpTypePointer Output %uint
312 %2 = OpVariable %_ptr_Output_uint Output
313 %8 = OpTypeFunction %void
314 %1 = OpFunction %void None %8
315 %9 = OpLabel
316 OpBranch %10
317 %11 = OpLabel
318 OpBranch %10
319 %10 = OpLabel
320 %12 = OpPhi %uint %uint_0 %9 %uint_1 %11
321 OpStore %2 %12
322 OpReturn
323 OpFunctionEnd
324 )";
325 
326   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
327 }
328 
TEST_F(IfConversionTest,DontFlatten)329 TEST_F(IfConversionTest, DontFlatten) {
330   const std::string text = R"(OpCapability Shader
331 OpMemoryModel Logical GLSL450
332 OpEntryPoint Vertex %1 "func" %2
333 %void = OpTypeVoid
334 %bool = OpTypeBool
335 %true = OpConstantTrue %bool
336 %uint = OpTypeInt 32 0
337 %uint_0 = OpConstant %uint 0
338 %uint_1 = OpConstant %uint 1
339 %v2uint = OpTypeVector %uint 2
340 %10 = OpConstantComposite %v2uint %uint_0 %uint_1
341 %11 = OpConstantComposite %v2uint %uint_1 %uint_0
342 %_ptr_Output_v2uint = OpTypePointer Output %v2uint
343 %2 = OpVariable %_ptr_Output_v2uint Output
344 %13 = OpTypeFunction %void
345 %1 = OpFunction %void None %13
346 %14 = OpLabel
347 OpSelectionMerge %15 DontFlatten
348 OpBranchConditional %true %16 %17
349 %16 = OpLabel
350 OpBranch %15
351 %17 = OpLabel
352 OpBranch %15
353 %15 = OpLabel
354 %18 = OpPhi %v2uint %10 %16 %11 %17
355 OpStore %2 %18
356 OpReturn
357 OpFunctionEnd
358 )";
359 
360   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
361 }
362 
TEST_F(IfConversionTest,LoopUntouched)363 TEST_F(IfConversionTest, LoopUntouched) {
364   const std::string text = R"(OpCapability Shader
365 OpMemoryModel Logical GLSL450
366 OpEntryPoint Vertex %1 "func" %2
367 %void = OpTypeVoid
368 %uint = OpTypeInt 32 0
369 %uint_0 = OpConstant %uint 0
370 %uint_1 = OpConstant %uint 1
371 %_ptr_Output_uint = OpTypePointer Output %uint
372 %2 = OpVariable %_ptr_Output_uint Output
373 %8 = OpTypeFunction %void
374 %bool = OpTypeBool
375 %true = OpConstantTrue %bool
376 %1 = OpFunction %void None %8
377 %11 = OpLabel
378 OpBranch %12
379 %12 = OpLabel
380 %13 = OpPhi %uint %uint_0 %11 %uint_1 %12
381 OpLoopMerge %14 %12 None
382 OpBranchConditional %true %14 %12
383 %14 = OpLabel
384 OpStore %2 %13
385 OpReturn
386 OpFunctionEnd
387 )";
388 
389   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
390 }
391 
TEST_F(IfConversionTest,TooManyPredecessors)392 TEST_F(IfConversionTest, TooManyPredecessors) {
393   const std::string text = R"(OpCapability Shader
394 OpMemoryModel Logical GLSL450
395 OpEntryPoint Vertex %1 "func" %2
396 %void = OpTypeVoid
397 %uint = OpTypeInt 32 0
398 %uint_0 = OpConstant %uint 0
399 %uint_1 = OpConstant %uint 1
400 %_ptr_Output_uint = OpTypePointer Output %uint
401 %2 = OpVariable %_ptr_Output_uint Output
402 %8 = OpTypeFunction %void
403 %bool = OpTypeBool
404 %true = OpConstantTrue %bool
405 %1 = OpFunction %void None %8
406 %11 = OpLabel
407 OpSelectionMerge %12 None
408 OpBranchConditional %true %13 %12
409 %13 = OpLabel
410 OpBranchConditional %true %14 %12
411 %14 = OpLabel
412 OpBranch %12
413 %12 = OpLabel
414 %15 = OpPhi %uint %uint_0 %11 %uint_0 %13 %uint_1 %14
415 OpStore %2 %15
416 OpReturn
417 OpFunctionEnd
418 )";
419 
420   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
421 }
422 
TEST_F(IfConversionTest,NoCodeMotion)423 TEST_F(IfConversionTest, NoCodeMotion) {
424   const std::string text = R"(OpCapability Shader
425 OpMemoryModel Logical GLSL450
426 OpEntryPoint Vertex %1 "func" %2
427 %void = OpTypeVoid
428 %uint = OpTypeInt 32 0
429 %uint_0 = OpConstant %uint 0
430 %uint_1 = OpConstant %uint 1
431 %_ptr_Output_uint = OpTypePointer Output %uint
432 %2 = OpVariable %_ptr_Output_uint Output
433 %8 = OpTypeFunction %void
434 %bool = OpTypeBool
435 %true = OpConstantTrue %bool
436 %1 = OpFunction %void None %8
437 %11 = OpLabel
438 OpSelectionMerge %12 None
439 OpBranchConditional %true %13 %12
440 %13 = OpLabel
441 %14 = OpIAdd %uint %uint_0 %uint_1
442 OpBranch %12
443 %12 = OpLabel
444 %15 = OpPhi %uint %uint_0 %11 %14 %13
445 OpStore %2 %15
446 OpReturn
447 OpFunctionEnd
448 )";
449 
450   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
451 }
452 
TEST_F(IfConversionTest,NoCodeMotionImmovableInst)453 TEST_F(IfConversionTest, NoCodeMotionImmovableInst) {
454   const std::string text = R"(OpCapability Shader
455 OpMemoryModel Logical GLSL450
456 OpEntryPoint Vertex %1 "func" %2
457 %void = OpTypeVoid
458 %uint = OpTypeInt 32 0
459 %uint_0 = OpConstant %uint 0
460 %uint_1 = OpConstant %uint 1
461 %_ptr_Output_uint = OpTypePointer Output %uint
462 %2 = OpVariable %_ptr_Output_uint Output
463 %8 = OpTypeFunction %void
464 %bool = OpTypeBool
465 %true = OpConstantTrue %bool
466 %1 = OpFunction %void None %8
467 %11 = OpLabel
468 OpSelectionMerge %12 None
469 OpBranchConditional %true %13 %14
470 %13 = OpLabel
471 OpSelectionMerge %15 None
472 OpBranchConditional %true %16 %15
473 %16 = OpLabel
474 %17 = OpIAdd %uint %uint_0 %uint_1
475 OpBranch %15
476 %15 = OpLabel
477 %18 = OpPhi %uint %uint_0 %13 %17 %16
478 %19 = OpIAdd %uint %18 %uint_1
479 OpBranch %12
480 %14 = OpLabel
481 OpSelectionMerge %20 None
482 OpBranchConditional %true %21 %20
483 %21 = OpLabel
484 %22 = OpIAdd %uint %uint_0 %uint_1
485 OpBranch %20
486 %20 = OpLabel
487 %23 = OpPhi %uint %uint_0 %14 %22 %21
488 %24 = OpIAdd %uint %23 %uint_1
489 OpBranch %12
490 %12 = OpLabel
491 %25 = OpPhi %uint %24 %20 %19 %15
492 OpStore %2 %25
493 OpReturn
494 OpFunctionEnd
495 )";
496 
497   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
498 }
499 
TEST_F(IfConversionTest,InvalidCommonDominator)500 TEST_F(IfConversionTest, InvalidCommonDominator) {
501   const std::string text = R"(OpCapability Shader
502 OpCapability Linkage
503 OpMemoryModel Logical GLSL450
504 %void = OpTypeVoid
505 %float = OpTypeFloat 32
506 %float_0 = OpConstant %float 0
507 %float_1 = OpConstant %float 1
508 %bool = OpTypeBool
509 %true = OpConstantTrue %bool
510 %1 = OpTypeFunction %void
511 %2 = OpFunction %void None %1
512 %3 = OpLabel
513 OpBranch %4
514 %4 = OpLabel
515 OpLoopMerge %5 %6 None
516 OpBranch %7
517 %7 = OpLabel
518 OpSelectionMerge %8 None
519 OpBranchConditional %true %8 %9
520 %9 = OpLabel
521 OpSelectionMerge %10 None
522 OpBranchConditional %true %10 %5
523 %10 = OpLabel
524 OpBranch %8
525 %8 = OpLabel
526 OpBranch %6
527 %6 = OpLabel
528 OpBranchConditional %true %4 %5
529 %5 = OpLabel
530 %11 = OpPhi %float %float_0 %6 %float_1 %9
531 OpReturn
532 OpFunctionEnd
533 )";
534 
535   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
536   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
537 }
538 
TEST_F(IfConversionTest,DebugInfoSimpleIfThenElse)539 TEST_F(IfConversionTest, DebugInfoSimpleIfThenElse) {
540   // When it replaces an OpPhi with OpSelect, the new OpSelect must have
541   // the same scope and line information with the OpPhi.
542   const std::string text = R"(
543 ; CHECK: OpSelectionMerge [[merge:%\w+]]
544 ; CHECK: [[merge]] = OpLabel
545 ; CHECK-NOT: OpPhi
546 ; CHECK: DebugScope
547 ; CHECK-NEXT: OpLine {{%\w+}} 3 7
548 ; CHECK-NEXT: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
549 ; CHECK-NEXT: DebugValue {{%\w+}} [[sel]]
550 ; CHECK: OpStore {{%\w+}} [[sel]]
551 OpCapability Shader
552 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
553 OpMemoryModel Logical GLSL450
554 OpEntryPoint Vertex %1 "func" %2
555 %name = OpString "test"
556 %void = OpTypeVoid
557 %bool = OpTypeBool
558 %true = OpConstantTrue %bool
559 %uint = OpTypeInt 32 0
560 %uint_0 = OpConstant %uint 0
561 %uint_1 = OpConstant %uint 1
562 %uint_32 = OpConstant %uint 32
563 %_ptr_Output_uint = OpTypePointer Output %uint
564 %2 = OpVariable %_ptr_Output_uint Output
565 %11 = OpTypeFunction %void
566 %null_expr = OpExtInst %void %ext DebugExpression
567 %src = OpExtInst %void %ext DebugSource %name
568 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
569 %dbg_tf = OpExtInst %void %ext DebugTypeBasic %name %uint_32 Float
570 %dbg_f = OpExtInst %void %ext DebugLocalVariable %name %dbg_tf %src 0 0 %cu FlagIsLocal
571 %1 = OpFunction %void None %11
572 %12 = OpLabel
573 OpSelectionMerge %14 None
574 OpBranchConditional %true %15 %16
575 %15 = OpLabel
576 OpBranch %14
577 %16 = OpLabel
578 OpBranch %14
579 %14 = OpLabel
580 %scope = OpExtInst %void %ext DebugScope %cu
581 OpLine %name 3 7
582 %18 = OpPhi %uint %uint_0 %15 %uint_1 %16
583 %value = OpExtInst %void %ext DebugValue %dbg_f %18 %null_expr
584 OpStore %2 %18
585 OpReturn
586 OpFunctionEnd
587 )";
588 
589   SinglePassRunAndMatch<IfConversion>(text, true);
590 }
591 
TEST_F(IfConversionTest,MultipleEdgesFromSameBlock)592 TEST_F(IfConversionTest, MultipleEdgesFromSameBlock) {
593   // If a block has two out going edges that go to the same block, then there
594   // can be an OpPhi instruction with fewer entries than the number of incoming
595   // edges.  This must be handled.
596   const std::string text = R"(OpCapability Shader
597 %1 = OpExtInstImport "GLSL.std.450"
598 OpMemoryModel Logical GLSL450
599 OpEntryPoint Fragment %2 "main"
600 OpExecutionMode %2 OriginUpperLeft
601 %void = OpTypeVoid
602 %4 = OpTypeFunction %void
603 %bool = OpTypeBool
604 %true = OpConstantTrue %bool
605 %true_0 = OpConstantTrue %bool
606 %2 = OpFunction %void None %4
607 %8 = OpLabel
608 OpSelectionMerge %9 None
609 OpBranchConditional %true_0 %9 %9
610 %9 = OpLabel
611 %10 = OpPhi %bool %true %8
612 OpReturn
613 OpFunctionEnd
614 )";
615 
616   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
617 }
618 
619 }  // namespace
620 }  // namespace opt
621 }  // namespace spvtools
622