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