• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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