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 "effcee/effcee.h"
18 #include "gmock/gmock.h"
19 #include "test/opt/pass_fixture.h"
20
21 namespace spvtools {
22 namespace opt {
23 namespace {
24
25 using UnswitchTest = PassTest<::testing::Test>;
26
27 /*
28 Generated from the following GLSL + --eliminate-local-multi-store
29
30 #version 450 core
31 uniform vec4 c;
32 void main() {
33 int i = 0;
34 int j = 0;
35 bool cond = c[0] == 0;
36 for (; i < 10; i++, j++) {
37 if (cond) {
38 i++;
39 }
40 else {
41 j++;
42 }
43 }
44 }
45 */
TEST_F(UnswitchTest,SimpleUnswitch)46 TEST_F(UnswitchTest, SimpleUnswitch) {
47 const std::string text = R"(
48 ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
49 ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
50 ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
51
52 ; Loop specialized for false.
53 ; CHECK: [[loop_f]] = OpLabel
54 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
55 ; CHECK: [[loop]] = OpLabel
56 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_i:%\w+]] [[continue:%\w+]]
57 ; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_j:%\w+]] [[continue]]
58 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
59 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
60 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
61 ; [[loop_body]] = OpLabel
62 ; CHECK: OpSelectionMerge [[sel_merge:%\w+]] None
63 ; CHECK: OpBranchConditional %false [[bb1:%\w+]] [[bb2:%\w+]]
64 ; CHECK: [[bb2]] = OpLabel
65 ; CHECK-NEXT: [[inc_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1
66 ; CHECK-NEXT: OpBranch [[sel_merge]]
67 ; CHECK: [[bb1]] = OpLabel
68 ; CHECK-NEXT: [[inc_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
69 ; CHECK-NEXT: OpBranch [[sel_merge]]
70 ; CHECK: [[sel_merge]] = OpLabel
71 ; CHECK: OpBranch [[if_merge]]
72
73 ; Loop specialized for true.
74 ; CHECK: [[loop_t]] = OpLabel
75 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
76 ; CHECK: [[loop]] = OpLabel
77 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
78 ; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_j:%\w+]] [[continue]]
79 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
80 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
81 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
82 ; [[loop_body]] = OpLabel
83 ; CHECK: OpSelectionMerge [[sel_merge:%\w+]] None
84 ; CHECK: OpBranchConditional %true [[bb1:%\w+]] [[bb2:%\w+]]
85 ; CHECK: [[bb1]] = OpLabel
86 ; CHECK-NEXT: [[inc_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
87 ; CHECK-NEXT: OpBranch [[sel_merge]]
88 ; CHECK: [[bb2]] = OpLabel
89 ; CHECK-NEXT: [[inc_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1
90 ; CHECK-NEXT: OpBranch [[sel_merge]]
91 ; CHECK: [[sel_merge]] = OpLabel
92 ; CHECK: OpBranch [[if_merge]]
93
94 ; CHECK: [[if_merge]] = OpLabel
95 ; CHECK-NEXT: OpReturn
96
97 OpCapability Shader
98 %1 = OpExtInstImport "GLSL.std.450"
99 OpMemoryModel Logical GLSL450
100 OpEntryPoint Fragment %main "main"
101 OpExecutionMode %main OriginLowerLeft
102 OpSource GLSL 450
103 OpName %main "main"
104 OpName %c "c"
105 OpDecorate %c Location 0
106 OpDecorate %c DescriptorSet 0
107 %void = OpTypeVoid
108 %3 = OpTypeFunction %void
109 %int = OpTypeInt 32 1
110 %_ptr_Function_int = OpTypePointer Function %int
111 %int_0 = OpConstant %int 0
112 %bool = OpTypeBool
113 %_ptr_Function_bool = OpTypePointer Function %bool
114 %float = OpTypeFloat 32
115 %v4float = OpTypeVector %float 4
116 %_ptr_UniformConstant_v4float = OpTypePointer UniformConstant %v4float
117 %c = OpVariable %_ptr_UniformConstant_v4float UniformConstant
118 %uint = OpTypeInt 32 0
119 %uint_0 = OpConstant %uint 0
120 %_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
121 %float_0 = OpConstant %float 0
122 %int_10 = OpConstant %int 10
123 %int_1 = OpConstant %int 1
124 %main = OpFunction %void None %3
125 %5 = OpLabel
126 %21 = OpAccessChain %_ptr_UniformConstant_float %c %uint_0
127 %22 = OpLoad %float %21
128 %24 = OpFOrdEqual %bool %22 %float_0
129 OpBranch %25
130 %25 = OpLabel
131 %46 = OpPhi %int %int_0 %5 %43 %28
132 %47 = OpPhi %int %int_0 %5 %45 %28
133 OpLoopMerge %27 %28 None
134 OpBranch %29
135 %29 = OpLabel
136 %32 = OpSLessThan %bool %46 %int_10
137 OpBranchConditional %32 %26 %27
138 %26 = OpLabel
139 OpSelectionMerge %35 None
140 OpBranchConditional %24 %34 %39
141 %34 = OpLabel
142 %38 = OpIAdd %int %46 %int_1
143 OpBranch %35
144 %39 = OpLabel
145 %41 = OpIAdd %int %47 %int_1
146 OpBranch %35
147 %35 = OpLabel
148 %48 = OpPhi %int %38 %34 %46 %39
149 %49 = OpPhi %int %47 %34 %41 %39
150 OpBranch %28
151 %28 = OpLabel
152 %43 = OpIAdd %int %48 %int_1
153 %45 = OpIAdd %int %49 %int_1
154 OpBranch %25
155 %27 = OpLabel
156 OpReturn
157 OpFunctionEnd
158 )";
159
160 SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
161 }
162
163 /*
164 Generated from the following GLSL + --eliminate-local-multi-store
165
166 #version 330 core
167 in vec4 c;
168 void main() {
169 int i = 0;
170 bool cond = c[0] == 0;
171 for (; i < 10; i++) {
172 if (cond) {
173 i++;
174 }
175 else {
176 return;
177 }
178 }
179 }
180 */
TEST_F(UnswitchTest,UnswitchExit)181 TEST_F(UnswitchTest, UnswitchExit) {
182 const std::string text = R"(
183 ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
184 ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
185 ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
186
187 ; Loop specialized for false.
188 ; CHECK: [[loop_f]] = OpLabel
189 ; CHECK: OpReturn
190
191 ; Loop specialized for true.
192 ; CHECK: [[loop_t]] = OpLabel
193 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
194 ; CHECK: [[loop]] = OpLabel
195 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
196 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
197 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
198 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]]
199 ; Check that we have i+=2.
200 ; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
201 ; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1
202 ; CHECK: [[merge]] = OpLabel
203 ; CHECK-NEXT: OpBranch [[if_merge]]
204
205 ; CHECK: [[if_merge]] = OpLabel
206 ; CHECK-NEXT: OpReturn
207
208 OpCapability Shader
209 %1 = OpExtInstImport "GLSL.std.450"
210 OpMemoryModel Logical GLSL450
211 OpEntryPoint Fragment %main "main" %c
212 OpExecutionMode %main OriginUpperLeft
213 OpSource GLSL 330
214 OpName %main "main"
215 OpName %c "c"
216 OpDecorate %c Location 0
217 OpDecorate %23 Uniform
218 %void = OpTypeVoid
219 %3 = OpTypeFunction %void
220 %int = OpTypeInt 32 1
221 %_ptr_Function_int = OpTypePointer Function %int
222 %int_0 = OpConstant %int 0
223 %bool = OpTypeBool
224 %_ptr_Function_bool = OpTypePointer Function %bool
225 %float = OpTypeFloat 32
226 %v4float = OpTypeVector %float 4
227 %_ptr_Input_v4float = OpTypePointer Input %v4float
228 %c = OpVariable %_ptr_Input_v4float Input
229 %uint = OpTypeInt 32 0
230 %uint_0 = OpConstant %uint 0
231 %_ptr_Input_float = OpTypePointer Input %float
232 %float_0 = OpConstant %float 0
233 %int_10 = OpConstant %int 10
234 %int_1 = OpConstant %int 1
235 %main = OpFunction %void None %3
236 %5 = OpLabel
237 %20 = OpAccessChain %_ptr_Input_float %c %uint_0
238 %21 = OpLoad %float %20
239 %23 = OpFOrdEqual %bool %21 %float_0
240 OpBranch %24
241 %24 = OpLabel
242 %42 = OpPhi %int %int_0 %5 %41 %27
243 OpLoopMerge %26 %27 None
244 OpBranch %28
245 %28 = OpLabel
246 %31 = OpSLessThan %bool %42 %int_10
247 OpBranchConditional %31 %25 %26
248 %25 = OpLabel
249 OpSelectionMerge %34 None
250 OpBranchConditional %23 %33 %38
251 %33 = OpLabel
252 %37 = OpIAdd %int %42 %int_1
253 OpBranch %34
254 %38 = OpLabel
255 OpReturn
256 %34 = OpLabel
257 OpBranch %27
258 %27 = OpLabel
259 %41 = OpIAdd %int %37 %int_1
260 OpBranch %24
261 %26 = OpLabel
262 OpReturn
263 OpFunctionEnd
264 )";
265
266 SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
267 }
268
269 /*
270 Generated from the following GLSL + --eliminate-local-multi-store
271
272 #version 330 core
273 in vec4 c;
274 void main() {
275 int i = 0;
276 bool cond = c[0] == 0;
277 for (; i < 10; i++) {
278 if (cond) {
279 continue;
280 }
281 else {
282 i++;
283 }
284 }
285 }
286 */
TEST_F(UnswitchTest,UnswitchContinue)287 TEST_F(UnswitchTest, UnswitchContinue) {
288 const std::string text = R"(
289 ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
290 ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
291 ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
292
293 ; Loop specialized for false.
294 ; CHECK: [[loop_f]] = OpLabel
295 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
296 ; CHECK: [[loop]] = OpLabel
297 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_i:%\w+]] [[continue:%\w+]]
298 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
299 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
300 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
301 ; CHECK: [[loop_body:%\w+]] = OpLabel
302 ; CHECK-NEXT: OpSelectionMerge
303 ; CHECK-NEXT: OpBranchConditional %false
304 ; CHECK: [[merge]] = OpLabel
305 ; CHECK-NEXT: OpBranch [[if_merge]]
306
307 ; Loop specialized for true.
308 ; CHECK: [[loop_t]] = OpLabel
309 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
310 ; CHECK: [[loop]] = OpLabel
311 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
312 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
313 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
314 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
315 ; CHECK: [[loop_body:%\w+]] = OpLabel
316 ; CHECK-NEXT: OpSelectionMerge
317 ; CHECK-NEXT: OpBranchConditional %true
318 ; CHECK: [[merge]] = OpLabel
319 ; CHECK-NEXT: OpBranch [[if_merge]]
320
321 ; CHECK: [[if_merge]] = OpLabel
322 ; CHECK-NEXT: OpReturn
323
324 OpCapability Shader
325 %1 = OpExtInstImport "GLSL.std.450"
326 OpMemoryModel Logical GLSL450
327 OpEntryPoint Fragment %main "main" %c
328 OpExecutionMode %main OriginUpperLeft
329 OpSource GLSL 330
330 OpName %main "main"
331 OpName %c "c"
332 OpDecorate %c Location 0
333 OpDecorate %23 Uniform
334 %void = OpTypeVoid
335 %3 = OpTypeFunction %void
336 %int = OpTypeInt 32 1
337 %_ptr_Function_int = OpTypePointer Function %int
338 %int_0 = OpConstant %int 0
339 %bool = OpTypeBool
340 %_ptr_Function_bool = OpTypePointer Function %bool
341 %float = OpTypeFloat 32
342 %v4float = OpTypeVector %float 4
343 %_ptr_Input_v4float = OpTypePointer Input %v4float
344 %c = OpVariable %_ptr_Input_v4float Input
345 %uint = OpTypeInt 32 0
346 %uint_0 = OpConstant %uint 0
347 %_ptr_Input_float = OpTypePointer Input %float
348 %float_0 = OpConstant %float 0
349 %int_10 = OpConstant %int 10
350 %int_1 = OpConstant %int 1
351 %main = OpFunction %void None %3
352 %5 = OpLabel
353 %20 = OpAccessChain %_ptr_Input_float %c %uint_0
354 %21 = OpLoad %float %20
355 %23 = OpFOrdEqual %bool %21 %float_0
356 OpBranch %24
357 %24 = OpLabel
358 %42 = OpPhi %int %int_0 %5 %41 %27
359 OpLoopMerge %26 %27 None
360 OpBranch %28
361 %28 = OpLabel
362 %31 = OpSLessThan %bool %42 %int_10
363 OpBranchConditional %31 %25 %26
364 %25 = OpLabel
365 OpSelectionMerge %34 None
366 OpBranchConditional %23 %33 %36
367 %33 = OpLabel
368 OpBranch %27
369 %36 = OpLabel
370 %39 = OpIAdd %int %42 %int_1
371 OpBranch %34
372 %34 = OpLabel
373 OpBranch %27
374 %27 = OpLabel
375 %43 = OpPhi %int %42 %33 %39 %34
376 %41 = OpIAdd %int %43 %int_1
377 OpBranch %24
378 %26 = OpLabel
379 OpReturn
380 OpFunctionEnd
381 )";
382
383 SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
384 }
385
386 /*
387 Generated from the following GLSL + --eliminate-local-multi-store
388
389 #version 330 core
390 in vec4 c;
391 void main() {
392 int i = 0;
393 bool cond = c[0] == 0;
394 for (; i < 10; i++) {
395 if (cond) {
396 i++;
397 }
398 else {
399 break;
400 }
401 }
402 }
403 */
TEST_F(UnswitchTest,UnswitchKillLoop)404 TEST_F(UnswitchTest, UnswitchKillLoop) {
405 const std::string text = R"(
406 ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
407 ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
408 ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
409
410 ; Loop specialized for false.
411 ; CHECK: [[loop_f]] = OpLabel
412 ; CHECK: OpBranch [[if_merge]]
413
414 ; Loop specialized for true.
415 ; CHECK: [[loop_t]] = OpLabel
416 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
417 ; CHECK: [[loop]] = OpLabel
418 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
419 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
420 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
421 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]]
422 ; Check that we have i+=2.
423 ; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
424 ; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1
425 ; CHECK: [[merge]] = OpLabel
426 ; CHECK-NEXT: OpBranch [[if_merge]]
427
428 ; CHECK: [[if_merge]] = OpLabel
429 ; CHECK-NEXT: OpReturn
430
431 OpCapability Shader
432 %1 = OpExtInstImport "GLSL.std.450"
433 OpMemoryModel Logical GLSL450
434 OpEntryPoint Fragment %main "main" %c
435 OpExecutionMode %main OriginUpperLeft
436 OpSource GLSL 330
437 OpName %main "main"
438 OpName %c "c"
439 OpDecorate %c Location 0
440 OpDecorate %23 Uniform
441 %void = OpTypeVoid
442 %3 = OpTypeFunction %void
443 %int = OpTypeInt 32 1
444 %_ptr_Function_int = OpTypePointer Function %int
445 %int_0 = OpConstant %int 0
446 %bool = OpTypeBool
447 %_ptr_Function_bool = OpTypePointer Function %bool
448 %float = OpTypeFloat 32
449 %v4float = OpTypeVector %float 4
450 %_ptr_Input_v4float = OpTypePointer Input %v4float
451 %c = OpVariable %_ptr_Input_v4float Input
452 %uint = OpTypeInt 32 0
453 %uint_0 = OpConstant %uint 0
454 %_ptr_Input_float = OpTypePointer Input %float
455 %float_0 = OpConstant %float 0
456 %int_10 = OpConstant %int 10
457 %int_1 = OpConstant %int 1
458 %main = OpFunction %void None %3
459 %5 = OpLabel
460 %20 = OpAccessChain %_ptr_Input_float %c %uint_0
461 %21 = OpLoad %float %20
462 %23 = OpFOrdEqual %bool %21 %float_0
463 OpBranch %24
464 %24 = OpLabel
465 %42 = OpPhi %int %int_0 %5 %41 %27
466 OpLoopMerge %26 %27 None
467 OpBranch %28
468 %28 = OpLabel
469 %31 = OpSLessThan %bool %42 %int_10
470 OpBranchConditional %31 %25 %26
471 %25 = OpLabel
472 OpSelectionMerge %34 None
473 OpBranchConditional %23 %33 %38
474 %33 = OpLabel
475 %37 = OpIAdd %int %42 %int_1
476 OpBranch %34
477 %38 = OpLabel
478 OpBranch %26
479 %34 = OpLabel
480 OpBranch %27
481 %27 = OpLabel
482 %41 = OpIAdd %int %37 %int_1
483 OpBranch %24
484 %26 = OpLabel
485 OpReturn
486 OpFunctionEnd
487 )";
488
489 SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
490 }
491
492 /*
493 Generated from the following GLSL + --eliminate-local-multi-store
494
495 #version 330 core
496 in vec4 c;
497 void main() {
498 int i = 0;
499 int cond = int(c[0]);
500 for (; i < 10; i++) {
501 switch (cond) {
502 case 0:
503 return;
504 case 1:
505 discard;
506 case 2:
507 break;
508 default:
509 break;
510 }
511 }
512 bool cond2 = i == 9;
513 }
514 */
TEST_F(UnswitchTest,UnswitchSwitch)515 TEST_F(UnswitchTest, UnswitchSwitch) {
516 const std::string text = R"(
517 ; CHECK: [[cst_cond:%\w+]] = OpConvertFToS
518 ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
519 ; CHECK-NEXT: OpSwitch [[cst_cond]] [[default:%\w+]] 0 [[loop_0:%\w+]] 1 [[loop_1:%\w+]] 2 [[loop_2:%\w+]]
520
521 ; Loop specialized for 2.
522 ; CHECK: [[loop_2]] = OpLabel
523 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
524 ; CHECK: [[loop]] = OpLabel
525 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_2]] [[iv_i:%\w+]] [[continue:%\w+]]
526 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
527 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
528 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
529 ; CHECK: [[loop_body]] = OpLabel
530 ; CHECK-NEXT: OpSelectionMerge
531 ; CHECK-NEXT: OpSwitch %int_2
532 ; CHECK: [[merge]] = OpLabel
533 ; CHECK-NEXT: OpBranch [[if_merge]]
534
535 ; Loop specialized for 1.
536 ; CHECK: [[loop_1]] = OpLabel
537 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
538 ; CHECK: [[loop]] = OpLabel
539 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_1]] [[iv_i:%\w+]] [[continue:%\w+]]
540 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
541 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
542 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
543 ; CHECK: [[loop_body]] = OpLabel
544 ; CHECK-NEXT: OpSelectionMerge
545 ; CHECK-NEXT: OpSwitch %int_1
546 ; CHECK: [[merge]] = OpLabel
547 ; CHECK-NEXT: OpBranch [[if_merge]]
548
549 ; Loop specialized for 0.
550 ; CHECK: [[loop_0]] = OpLabel
551 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
552 ; CHECK: [[loop]] = OpLabel
553 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_0]] [[iv_i:%\w+]] [[continue:%\w+]]
554 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
555 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
556 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
557 ; CHECK: [[loop_body]] = OpLabel
558 ; CHECK-NEXT: OpSelectionMerge
559 ; CHECK-NEXT: OpSwitch %int_0
560 ; CHECK: [[merge]] = OpLabel
561 ; CHECK-NEXT: OpBranch [[if_merge]]
562
563 ; Loop specialized for the default case.
564 ; CHECK: [[default]] = OpLabel
565 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
566 ; CHECK: [[loop]] = OpLabel
567 ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[default]] [[iv_i:%\w+]] [[continue:%\w+]]
568 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
569 ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
570 ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
571 ; CHECK: [[loop_body]] = OpLabel
572 ; CHECK-NEXT: OpSelectionMerge
573 ; CHECK-NEXT: OpSwitch %uint_3
574 ; CHECK: [[merge]] = OpLabel
575 ; CHECK-NEXT: OpBranch [[if_merge]]
576
577 ; CHECK: [[if_merge]] = OpLabel
578 ; CHECK-NEXT: OpReturn
579 OpCapability Shader
580 %1 = OpExtInstImport "GLSL.std.450"
581 OpMemoryModel Logical GLSL450
582 OpEntryPoint Fragment %main "main" %c
583 OpExecutionMode %main OriginUpperLeft
584 OpSource GLSL 330
585 OpName %main "main"
586 OpName %c "c"
587 OpDecorate %c Location 0
588 OpDecorate %20 Uniform
589 %void = OpTypeVoid
590 %3 = OpTypeFunction %void
591 %int = OpTypeInt 32 1
592 %_ptr_Function_int = OpTypePointer Function %int
593 %int_0 = OpConstant %int 0
594 %float = OpTypeFloat 32
595 %v4float = OpTypeVector %float 4
596 %_ptr_Input_v4float = OpTypePointer Input %v4float
597 %c = OpVariable %_ptr_Input_v4float Input
598 %uint = OpTypeInt 32 0
599 %uint_0 = OpConstant %uint 0
600 %_ptr_Input_float = OpTypePointer Input %float
601 %int_10 = OpConstant %int 10
602 %bool = OpTypeBool
603 %int_1 = OpConstant %int 1
604 %_ptr_Function_bool = OpTypePointer Function %bool
605 %main = OpFunction %void None %3
606 %5 = OpLabel
607 %18 = OpAccessChain %_ptr_Input_float %c %uint_0
608 %19 = OpLoad %float %18
609 %20 = OpConvertFToS %int %19
610 OpBranch %21
611 %21 = OpLabel
612 %49 = OpPhi %int %int_0 %5 %43 %24
613 OpLoopMerge %23 %24 None
614 OpBranch %25
615 %25 = OpLabel
616 %29 = OpSLessThan %bool %49 %int_10
617 OpBranchConditional %29 %22 %23
618 %22 = OpLabel
619 OpSelectionMerge %35 None
620 OpSwitch %20 %34 0 %31 1 %32 2 %33
621 %34 = OpLabel
622 OpBranch %35
623 %31 = OpLabel
624 OpReturn
625 %32 = OpLabel
626 OpKill
627 %33 = OpLabel
628 OpBranch %35
629 %35 = OpLabel
630 OpBranch %24
631 %24 = OpLabel
632 %43 = OpIAdd %int %49 %int_1
633 OpBranch %21
634 %23 = OpLabel
635 OpReturn
636 OpFunctionEnd
637 )";
638
639 SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
640 }
641
642 /*
643 Generated from the following GLSL + --eliminate-local-multi-store
644
645 #version 440 core
646 layout(location = 0)in vec4 c;
647 void main() {
648 int i = 0;
649 int j = 0;
650 int k = 0;
651 bool cond = c[0] == 0;
652 for (; i < 10; i++) {
653 for (; j < 10; j++) {
654 if (cond) {
655 i++;
656 } else {
657 j++;
658 }
659 }
660 }
661 }
662 */
TEST_F(UnswitchTest,UnSwitchNested)663 TEST_F(UnswitchTest, UnSwitchNested) {
664 // Test that an branch can be unswitched out of two nested loops.
665 const std::string text = R"(
666 ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
667 ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
668 ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
669
670 ; Loop specialized for false
671 ; CHECK: [[loop_f]] = OpLabel
672 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
673 ; CHECK: [[loop]] = OpLabel
674 ; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_f]] {{%\w+}} [[continue:%\w+]]
675 ; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_f]] {{%\w+}} [[continue]]
676 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
677 ; CHECK-NOT: [[merge]] = OpLabel
678 ; CHECK: OpLoopMerge
679 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
680 ; CHECK: [[bb1]] = OpLabel
681 ; CHECK-NEXT: OpSLessThan
682 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb2:%\w+]]
683 ; CHECK: [[bb2]] = OpLabel
684 ; CHECK-NEXT: OpSelectionMerge
685 ; CHECK-NEXT: OpBranchConditional %false
686 ; CHECK: [[merge]] = OpLabel
687
688 ; Loop specialized for true. Same as first loop except the branch condition is true.
689 ; CHECK: [[loop_t]] = OpLabel
690 ; CHECK-NEXT: OpBranch [[loop:%\w+]]
691 ; CHECK: [[loop]] = OpLabel
692 ; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_t]] {{%\w+}} [[continue:%\w+]]
693 ; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_t]] {{%\w+}} [[continue]]
694 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
695 ; CHECK-NOT: [[merge]] = OpLabel
696 ; CHECK: OpLoopMerge
697 ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
698 ; CHECK: [[bb1]] = OpLabel
699 ; CHECK-NEXT: OpSLessThan
700 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb2:%\w+]]
701 ; CHECK: [[bb2]] = OpLabel
702 ; CHECK-NEXT: OpSelectionMerge
703 ; CHECK-NEXT: OpBranchConditional %true
704 ; CHECK: [[merge]] = OpLabel
705
706 OpCapability Shader
707 %1 = OpExtInstImport "GLSL.std.450"
708 OpMemoryModel Logical GLSL450
709 OpEntryPoint Fragment %main "main" %c
710 OpExecutionMode %main OriginUpperLeft
711 OpSource GLSL 440
712 OpName %main "main"
713 OpName %c "c"
714 OpDecorate %c Location 0
715 OpDecorate %25 Uniform
716 %void = OpTypeVoid
717 %3 = OpTypeFunction %void
718 %int = OpTypeInt 32 1
719 %_ptr_Function_int = OpTypePointer Function %int
720 %int_0 = OpConstant %int 0
721 %bool = OpTypeBool
722 %_ptr_Function_bool = OpTypePointer Function %bool
723 %float = OpTypeFloat 32
724 %v4float = OpTypeVector %float 4
725 %_ptr_Input_v4float = OpTypePointer Input %v4float
726 %c = OpVariable %_ptr_Input_v4float Input
727 %uint = OpTypeInt 32 0
728 %uint_0 = OpConstant %uint 0
729 %_ptr_Input_float = OpTypePointer Input %float
730 %float_0 = OpConstant %float 0
731 %int_10 = OpConstant %int 10
732 %int_1 = OpConstant %int 1
733 %main = OpFunction %void None %3
734 %5 = OpLabel
735 %22 = OpAccessChain %_ptr_Input_float %c %uint_0
736 %23 = OpLoad %float %22
737 %25 = OpFOrdEqual %bool %23 %float_0
738 OpBranch %26
739 %26 = OpLabel
740 %67 = OpPhi %int %int_0 %5 %52 %29
741 %68 = OpPhi %int %int_0 %5 %70 %29
742 OpLoopMerge %28 %29 None
743 OpBranch %30
744 %30 = OpLabel
745 %33 = OpSLessThan %bool %67 %int_10
746 OpBranchConditional %33 %27 %28
747 %27 = OpLabel
748 OpBranch %34
749 %34 = OpLabel
750 %69 = OpPhi %int %67 %27 %46 %37
751 %70 = OpPhi %int %68 %27 %50 %37
752 OpLoopMerge %36 %37 None
753 OpBranch %38
754 %38 = OpLabel
755 %40 = OpSLessThan %bool %70 %int_10
756 OpBranchConditional %40 %35 %36
757 %35 = OpLabel
758 OpSelectionMerge %43 None
759 OpBranchConditional %25 %42 %47
760 %42 = OpLabel
761 %46 = OpIAdd %int %69 %int_1
762 OpBranch %43
763 %47 = OpLabel
764 OpReturn
765 %43 = OpLabel
766 OpBranch %37
767 %37 = OpLabel
768 %50 = OpIAdd %int %70 %int_1
769 OpBranch %34
770 %36 = OpLabel
771 OpBranch %29
772 %29 = OpLabel
773 %52 = OpIAdd %int %69 %int_1
774 OpBranch %26
775 %28 = OpLabel
776 OpReturn
777 OpFunctionEnd
778 )";
779
780 SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
781 }
782
783 /*
784 Generated from the following GLSL + --eliminate-local-multi-store
785
786 #version 330 core
787 in vec4 c;
788 void main() {
789 bool cond = false;
790 if (c[0] == 0) {
791 cond = c[1] == 0;
792 } else {
793 cond = c[2] == 0;
794 }
795 for (int i = 0; i < 10; i++) {
796 if (cond) {
797 i++;
798 }
799 }
800 }
801 */
TEST_F(UnswitchTest,UnswitchNotUniform)802 TEST_F(UnswitchTest, UnswitchNotUniform) {
803 // Check that the unswitch is not triggered (condition loop invariant but not
804 // uniform)
805 const std::string text = R"(
806 OpCapability Shader
807 %1 = OpExtInstImport "GLSL.std.450"
808 OpMemoryModel Logical GLSL450
809 OpEntryPoint Fragment %main "main" %c
810 OpExecutionMode %main OriginUpperLeft
811 OpSource GLSL 330
812 OpName %main "main"
813 OpName %c "c"
814 OpDecorate %c Location 0
815 %void = OpTypeVoid
816 %3 = OpTypeFunction %void
817 %bool = OpTypeBool
818 %_ptr_Function_bool = OpTypePointer Function %bool
819 %float = OpTypeFloat 32
820 %v4float = OpTypeVector %float 4
821 %_ptr_Input_v4float = OpTypePointer Input %v4float
822 %c = OpVariable %_ptr_Input_v4float Input
823 %uint = OpTypeInt 32 0
824 %uint_0 = OpConstant %uint 0
825 %_ptr_Input_float = OpTypePointer Input %float
826 %float_0 = OpConstant %float 0
827 %uint_1 = OpConstant %uint 1
828 %uint_2 = OpConstant %uint 2
829 %int = OpTypeInt 32 1
830 %_ptr_Function_int = OpTypePointer Function %int
831 %int_0 = OpConstant %int 0
832 %int_10 = OpConstant %int 10
833 %int_1 = OpConstant %int 1
834 %main = OpFunction %void None %3
835 %5 = OpLabel
836 %17 = OpAccessChain %_ptr_Input_float %c %uint_0
837 %18 = OpLoad %float %17
838 %20 = OpFOrdEqual %bool %18 %float_0
839 OpSelectionMerge %22 None
840 OpBranchConditional %20 %21 %27
841 %21 = OpLabel
842 %24 = OpAccessChain %_ptr_Input_float %c %uint_1
843 %25 = OpLoad %float %24
844 %26 = OpFOrdEqual %bool %25 %float_0
845 OpBranch %22
846 %27 = OpLabel
847 %29 = OpAccessChain %_ptr_Input_float %c %uint_2
848 %30 = OpLoad %float %29
849 %31 = OpFOrdEqual %bool %30 %float_0
850 OpBranch %22
851 %22 = OpLabel
852 %52 = OpPhi %bool %26 %21 %31 %27
853 OpBranch %36
854 %36 = OpLabel
855 %53 = OpPhi %int %int_0 %22 %51 %39
856 OpLoopMerge %38 %39 None
857 OpBranch %40
858 %40 = OpLabel
859 %43 = OpSLessThan %bool %53 %int_10
860 OpBranchConditional %43 %37 %38
861 %37 = OpLabel
862 OpSelectionMerge %46 None
863 OpBranchConditional %52 %45 %46
864 %45 = OpLabel
865 %49 = OpIAdd %int %53 %int_1
866 OpBranch %46
867 %46 = OpLabel
868 %54 = OpPhi %int %53 %37 %49 %45
869 OpBranch %39
870 %39 = OpLabel
871 %51 = OpIAdd %int %54 %int_1
872 OpBranch %36
873 %38 = OpLabel
874 OpReturn
875 OpFunctionEnd
876 )";
877
878 auto result =
879 SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
880
881 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
882 }
883
TEST_F(UnswitchTest,DontUnswitchLatch)884 TEST_F(UnswitchTest, DontUnswitchLatch) {
885 // Check that the unswitch is not triggered for the latch branch.
886 const std::string text = R"(
887 OpCapability Shader
888 %1 = OpExtInstImport "GLSL.std.450"
889 OpMemoryModel Logical GLSL450
890 OpEntryPoint Fragment %4 "main"
891 OpExecutionMode %4 OriginUpperLeft
892 OpSource ESSL 310
893 %void = OpTypeVoid
894 %3 = OpTypeFunction %void
895 %bool = OpTypeBool
896 %false = OpConstantFalse %bool
897 %4 = OpFunction %void None %3
898 %5 = OpLabel
899 OpBranch %6
900 %6 = OpLabel
901 OpLoopMerge %8 %9 None
902 OpBranch %7
903 %7 = OpLabel
904 OpBranch %9
905 %9 = OpLabel
906 OpBranchConditional %false %6 %8
907 %8 = OpLabel
908 OpReturn
909 OpFunctionEnd
910 )";
911
912 auto result =
913 SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
914 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
915 }
916
TEST_F(UnswitchTest,DontUnswitchConstantCondition)917 TEST_F(UnswitchTest, DontUnswitchConstantCondition) {
918 const std::string text = R"(
919 OpCapability Shader
920 %1 = OpExtInstImport "GLSL.std.450"
921 OpMemoryModel Logical GLSL450
922 OpEntryPoint Fragment %main "main"
923 OpExecutionMode %main OriginLowerLeft
924 OpSource GLSL 450
925 OpName %main "main"
926 %void = OpTypeVoid
927 %4 = OpTypeFunction %void
928 %int = OpTypeInt 32 1
929 %int_0 = OpConstant %int 0
930 %bool = OpTypeBool
931 %true = OpConstantTrue %bool
932 %int_1 = OpConstant %int 1
933 %main = OpFunction %void None %4
934 %10 = OpLabel
935 OpBranch %11
936 %11 = OpLabel
937 %12 = OpPhi %int %int_0 %10 %13 %14
938 OpLoopMerge %15 %14 None
939 OpBranch %16
940 %16 = OpLabel
941 %17 = OpSLessThan %bool %12 %int_1
942 OpBranchConditional %17 %18 %15
943 %18 = OpLabel
944 OpSelectionMerge %19 None
945 OpBranchConditional %true %20 %19
946 %20 = OpLabel
947 %21 = OpIAdd %int %12 %int_1
948 OpBranch %19
949 %19 = OpLabel
950 %22 = OpPhi %int %21 %20 %12 %18
951 OpBranch %14
952 %14 = OpLabel
953 %13 = OpIAdd %int %22 %int_1
954 OpBranch %11
955 %15 = OpLabel
956 OpReturn
957 OpFunctionEnd
958 )";
959
960 auto result =
961 SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
962 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
963 }
964
965 } // namespace
966 } // namespace opt
967 } // namespace spvtools
968