• 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 <memory>
16 #include <string>
17 #include <vector>
18 
19 #include "gmock/gmock.h"
20 #include "source/opt/loop_unroller.h"
21 #include "source/opt/loop_utils.h"
22 #include "source/opt/pass.h"
23 #include "test/opt/assembly_builder.h"
24 #include "test/opt/function_utils.h"
25 #include "test/opt/pass_fixture.h"
26 #include "test/opt/pass_utils.h"
27 
28 namespace spvtools {
29 namespace opt {
30 namespace {
31 
32 using ::testing::UnorderedElementsAre;
33 using PassClassTest = PassTest<::testing::Test>;
34 
35 template <int factor>
36 class PartialUnrollerTestPass : public Pass {
37  public:
PartialUnrollerTestPass()38   PartialUnrollerTestPass() : Pass() {}
39 
name() const40   const char* name() const override { return "Loop unroller"; }
41 
Process()42   Status Process() override {
43     bool changed = false;
44     for (Function& f : *context()->module()) {
45       LoopDescriptor& loop_descriptor = *context()->GetLoopDescriptor(&f);
46       for (auto& loop : loop_descriptor) {
47         LoopUtils loop_utils{context(), &loop};
48         if (loop_utils.PartiallyUnroll(factor)) {
49           changed = true;
50         }
51       }
52     }
53 
54     if (changed) return Pass::Status::SuccessWithChange;
55     return Pass::Status::SuccessWithoutChange;
56   }
57 };
58 
59 /*
60 Generated from the following GLSL
61 #version 410 core
62 layout(location = 0) flat in int in_upper_bound;
63 void main() {
64   for (int i = 0; i < in_upper_bound; ++i) {
65     x[i] = 1.0f;
66   }
67 }
68 */
TEST_F(PassClassTest,CheckUpperBound)69 TEST_F(PassClassTest, CheckUpperBound) {
70   // clang-format off
71   // With LocalMultiStoreElimPass
72   const std::string text = R"(OpCapability Shader
73 %1 = OpExtInstImport "GLSL.std.450"
74 OpMemoryModel Logical GLSL450
75 OpEntryPoint Fragment %2 "main" %3
76 OpExecutionMode %2 OriginUpperLeft
77 OpSource GLSL 410
78 OpName %2 "main"
79 OpName %3 "in_upper_bound"
80 OpName %4 "x"
81 OpDecorate %3 Flat
82 OpDecorate %3 Location 0
83 %5 = OpTypeVoid
84 %6 = OpTypeFunction %5
85 %7 = OpTypeInt 32 1
86 %8 = OpTypePointer Function %7
87 %9 = OpConstant %7 0
88 %10 = OpTypePointer Input %7
89 %3 = OpVariable %10 Input
90 %11 = OpTypeBool
91 %12 = OpTypeFloat 32
92 %13 = OpTypeInt 32 0
93 %14 = OpConstant %13 10
94 %15 = OpTypeArray %12 %14
95 %16 = OpTypePointer Function %15
96 %17 = OpConstant %12 1
97 %18 = OpTypePointer Function %12
98 %19 = OpConstant %7 1
99 %2 = OpFunction %5 None %6
100 %20 = OpLabel
101 %4 = OpVariable %16 Function
102 OpBranch %21
103 %21 = OpLabel
104 %22 = OpPhi %7 %9 %20 %23 %24
105 OpLoopMerge %25 %24 Unroll
106 OpBranch %26
107 %26 = OpLabel
108 %27 = OpLoad %7 %3
109 %28 = OpSLessThan %11 %22 %27
110 OpBranchConditional %28 %29 %25
111 %29 = OpLabel
112 %30 = OpAccessChain %18 %4 %22
113 OpStore %30 %17
114 OpBranch %24
115 %24 = OpLabel
116 %23 = OpIAdd %7 %22 %19
117 OpBranch %21
118 %25 = OpLabel
119 OpReturn
120 OpFunctionEnd
121 )";
122   // clang-format on
123   std::unique_ptr<IRContext> context =
124       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
125                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
126   Module* module = context->module();
127   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
128                              << text << std::endl;
129 
130   LoopUnroller loop_unroller;
131   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
132 
133   // Make sure the pass doesn't run
134   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
135   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
136   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
137 }
138 
139 /*
140 Generated from the following GLSL
141 #version 410 core
142 void main() {
143     float out_array[10];
144     for (uint i = 0; i < 2; i++) {
145       for (float x = 0; x < 5; ++x) {
146         out_array[x + i*5] = i;
147       }
148     }
149 }
150 */
TEST_F(PassClassTest,UnrollNestedLoopsInvalid)151 TEST_F(PassClassTest, UnrollNestedLoopsInvalid) {
152   // clang-format off
153   // With LocalMultiStoreElimPass
154 const std::string text = R"(OpCapability Shader
155 %1 = OpExtInstImport "GLSL.std.450"
156 OpMemoryModel Logical GLSL450
157 OpEntryPoint Fragment %2 "main"
158 OpExecutionMode %2 OriginUpperLeft
159 OpSource GLSL 410
160 OpName %2 "main"
161 OpName %3 "out_array"
162 %4 = OpTypeVoid
163 %5 = OpTypeFunction %4
164 %6 = OpTypeInt 32 0
165 %7 = OpTypePointer Function %6
166 %8 = OpConstant %6 0
167 %9 = OpConstant %6 2
168 %10 = OpTypeBool
169 %11 = OpTypeInt 32 1
170 %12 = OpTypePointer Function %11
171 %13 = OpConstant %11 0
172 %14 = OpConstant %11 5
173 %15 = OpTypeFloat 32
174 %16 = OpConstant %6 10
175 %17 = OpTypeArray %15 %16
176 %18 = OpTypePointer Function %17
177 %19 = OpConstant %6 5
178 %20 = OpTypePointer Function %15
179 %21 = OpConstant %11 1
180 %22 = OpUndef %11
181 %2 = OpFunction %4 None %5
182 %23 = OpLabel
183 %3 = OpVariable %18 Function
184 OpBranch %24
185 %24 = OpLabel
186 %25 = OpPhi %6 %8 %23 %26 %27
187 %28 = OpPhi %11 %22 %23 %29 %27
188 OpLoopMerge %30 %27 Unroll
189 OpBranch %31
190 %31 = OpLabel
191 %32 = OpULessThan %10 %25 %9
192 OpBranchConditional %32 %33 %30
193 %33 = OpLabel
194 OpBranch %34
195 %34 = OpLabel
196 %29 = OpPhi %11 %13 %33 %35 %36
197 OpLoopMerge %37 %36 None
198 OpBranch %38
199 %38 = OpLabel
200 %39 = OpSLessThan %10 %29 %14
201 OpBranchConditional %39 %40 %37
202 %40 = OpLabel
203 %41 = OpBitcast %6 %29
204 %42 = OpIMul %6 %25 %19
205 %43 = OpIAdd %6 %41 %42
206 %44 = OpConvertUToF %15 %25
207 %45 = OpAccessChain %20 %3 %43
208 OpStore %45 %44
209 OpBranch %36
210 %36 = OpLabel
211 %35 = OpIAdd %11 %29 %21
212 OpBranch %34
213 %37 = OpLabel
214 OpBranch %27
215 %27 = OpLabel
216 %26 = OpIAdd %6 %25 %21
217 OpBranch %24
218 %30 = OpLabel
219 OpReturn
220 OpFunctionEnd
221 )";
222 
223   std::unique_ptr<IRContext> context =
224       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
225                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
226   Module* module = context->module();
227   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
228                              << text << std::endl;
229 
230   LoopUnroller loop_unroller;
231   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
232   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
233 }
234 
235 /*
236 Generated from the following GLSL
237 #version 440 core
238 void main(){
239   float x[10];
240   for (int i = 0; i < 10; i++) {
241     if (i == 5) {
242       break;
243     }
244     x[i] = i;
245   }
246 }
247 */
TEST_F(PassClassTest,BreakInBody)248 TEST_F(PassClassTest, BreakInBody) {
249   // clang-format off
250   // With LocalMultiStoreElimPass
251 const std::string text = R"(OpCapability Shader
252 %1 = OpExtInstImport "GLSL.std.450"
253 OpMemoryModel Logical GLSL450
254 OpEntryPoint Fragment %2 "main"
255 OpExecutionMode %2 OriginUpperLeft
256 OpSource GLSL 440
257 OpName %2 "main"
258 OpName %3 "x"
259 %4 = OpTypeVoid
260 %5 = OpTypeFunction %4
261 %6 = OpTypeInt 32 1
262 %7 = OpTypePointer Function %6
263 %8 = OpConstant %6 0
264 %9 = OpConstant %6 10
265 %10 = OpTypeBool
266 %11 = OpConstant %6 5
267 %12 = OpTypeFloat 32
268 %13 = OpTypeInt 32 0
269 %14 = OpConstant %13 10
270 %15 = OpTypeArray %12 %14
271 %16 = OpTypePointer Function %15
272 %17 = OpTypePointer Function %12
273 %18 = OpConstant %6 1
274 %2 = OpFunction %4 None %5
275 %19 = OpLabel
276 %3 = OpVariable %16 Function
277 OpBranch %20
278 %20 = OpLabel
279 %21 = OpPhi %6 %8 %19 %22 %23
280 OpLoopMerge %24 %23 Unroll
281 OpBranch %25
282 %25 = OpLabel
283 %26 = OpSLessThan %10 %21 %9
284 OpBranchConditional %26 %27 %24
285 %27 = OpLabel
286 %28 = OpIEqual %10 %21 %11
287 OpSelectionMerge %29 None
288 OpBranchConditional %28 %30 %29
289 %30 = OpLabel
290 OpBranch %24
291 %29 = OpLabel
292 %31 = OpConvertSToF %12 %21
293 %32 = OpAccessChain %17 %3 %21
294 OpStore %32 %31
295 OpBranch %23
296 %23 = OpLabel
297 %22 = OpIAdd %6 %21 %18
298 OpBranch %20
299 %24 = OpLabel
300 OpReturn
301 OpFunctionEnd
302 )";
303   // clang-format on
304   std::unique_ptr<IRContext> context =
305       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
306                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
307   Module* module = context->module();
308   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
309                              << text << std::endl;
310 
311   LoopUnroller loop_unroller;
312   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
313   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
314 }
315 
316 /*
317 Generated from the following GLSL
318 #version 440 core
319 void main(){
320   float x[10];
321   for (int i = 0; i < 10; i++) {
322     if (i == 5) {
323       continue;
324     }
325     x[i] = i;
326   }
327 }
328 */
TEST_F(PassClassTest,ContinueInBody)329 TEST_F(PassClassTest, ContinueInBody) {
330   // clang-format off
331   // With LocalMultiStoreElimPass
332 const std::string text = R"(OpCapability Shader
333 %1 = OpExtInstImport "GLSL.std.450"
334 OpMemoryModel Logical GLSL450
335 OpEntryPoint Fragment %2 "main"
336 OpExecutionMode %2 OriginUpperLeft
337 OpSource GLSL 440
338 OpName %2 "main"
339 OpName %3 "x"
340 %4 = OpTypeVoid
341 %5 = OpTypeFunction %4
342 %6 = OpTypeInt 32 1
343 %7 = OpTypePointer Function %6
344 %8 = OpConstant %6 0
345 %9 = OpConstant %6 10
346 %10 = OpTypeBool
347 %11 = OpConstant %6 5
348 %12 = OpTypeFloat 32
349 %13 = OpTypeInt 32 0
350 %14 = OpConstant %13 10
351 %15 = OpTypeArray %12 %14
352 %16 = OpTypePointer Function %15
353 %17 = OpTypePointer Function %12
354 %18 = OpConstant %6 1
355 %2 = OpFunction %4 None %5
356 %19 = OpLabel
357 %3 = OpVariable %16 Function
358 OpBranch %20
359 %20 = OpLabel
360 %21 = OpPhi %6 %8 %19 %22 %23
361 OpLoopMerge %24 %23 Unroll
362 OpBranch %25
363 %25 = OpLabel
364 %26 = OpSLessThan %10 %21 %9
365 OpBranchConditional %26 %27 %24
366 %27 = OpLabel
367 %28 = OpIEqual %10 %21 %11
368 OpSelectionMerge %29 None
369 OpBranchConditional %28 %30 %29
370 %30 = OpLabel
371 OpBranch %23
372 %29 = OpLabel
373 %31 = OpConvertSToF %12 %21
374 %32 = OpAccessChain %17 %3 %21
375 OpStore %32 %31
376 OpBranch %23
377 %23 = OpLabel
378 %22 = OpIAdd %6 %21 %18
379 OpBranch %20
380 %24 = OpLabel
381 OpReturn
382 OpFunctionEnd
383 )";
384   // clang-format on
385   std::unique_ptr<IRContext> context =
386       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
387                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
388   Module* module = context->module();
389   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
390                              << text << std::endl;
391 
392   LoopUnroller loop_unroller;
393   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
394   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
395 }
396 
397 /*
398 Generated from the following GLSL
399 #version 440 core
400 void main(){
401   float x[10];
402   for (int i = 0; i < 10; i++) {
403     if (i == 5) {
404       return;
405     }
406     x[i] = i;
407   }
408 }
409 */
TEST_F(PassClassTest,ReturnInBody)410 TEST_F(PassClassTest, ReturnInBody) {
411   // clang-format off
412   // With LocalMultiStoreElimPass
413 const std::string text = R"(OpCapability Shader
414 %1 = OpExtInstImport "GLSL.std.450"
415 OpMemoryModel Logical GLSL450
416 OpEntryPoint Fragment %2 "main"
417 OpExecutionMode %2 OriginUpperLeft
418 OpSource GLSL 440
419 OpName %2 "main"
420 OpName %3 "x"
421 %4 = OpTypeVoid
422 %5 = OpTypeFunction %4
423 %6 = OpTypeInt 32 1
424 %7 = OpTypePointer Function %6
425 %8 = OpConstant %6 0
426 %9 = OpConstant %6 10
427 %10 = OpTypeBool
428 %11 = OpConstant %6 5
429 %12 = OpTypeFloat 32
430 %13 = OpTypeInt 32 0
431 %14 = OpConstant %13 10
432 %15 = OpTypeArray %12 %14
433 %16 = OpTypePointer Function %15
434 %17 = OpTypePointer Function %12
435 %18 = OpConstant %6 1
436 %2 = OpFunction %4 None %5
437 %19 = OpLabel
438 %3 = OpVariable %16 Function
439 OpBranch %20
440 %20 = OpLabel
441 %21 = OpPhi %6 %8 %19 %22 %23
442 OpLoopMerge %24 %23 Unroll
443 OpBranch %25
444 %25 = OpLabel
445 %26 = OpSLessThan %10 %21 %9
446 OpBranchConditional %26 %27 %24
447 %27 = OpLabel
448 %28 = OpIEqual %10 %21 %11
449 OpSelectionMerge %29 None
450 OpBranchConditional %28 %30 %29
451 %30 = OpLabel
452 OpReturn
453 %29 = OpLabel
454 %31 = OpConvertSToF %12 %21
455 %32 = OpAccessChain %17 %3 %21
456 OpStore %32 %31
457 OpBranch %23
458 %23 = OpLabel
459 %22 = OpIAdd %6 %21 %18
460 OpBranch %20
461 %24 = OpLabel
462 OpReturn
463 OpFunctionEnd
464 )";
465   // clang-format on
466   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
467   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
468 }
469 
TEST_F(PassClassTest,KillInBody)470 TEST_F(PassClassTest, KillInBody) {
471   const std::string text = R"(OpCapability Shader
472 OpMemoryModel Logical Simple
473 OpEntryPoint Fragment %1 "main"
474 OpExecutionMode %1 OriginUpperLeft
475 %2 = OpTypeVoid
476 %3 = OpTypeFunction %2
477 %4 = OpTypeBool
478 %5 = OpTypeInt 32 0
479 %6 = OpConstant %5 0
480 %7 = OpConstant %5 1
481 %8 = OpConstant %5 5
482 %1 = OpFunction %2 None %3
483 %9 = OpLabel
484 OpBranch %10
485 %10 = OpLabel
486 %11 = OpPhi %5 %6 %9 %12 %13
487 %14 = OpULessThan %4 %11 %8
488 OpLoopMerge %15 %13 Unroll
489 OpBranchConditional %14 %16 %15
490 %16 = OpLabel
491 OpKill
492 %13 = OpLabel
493 %12 = OpIAdd %5 %11 %7
494 OpBranch %10
495 %15 = OpLabel
496 OpReturn
497 OpFunctionEnd
498 )";
499   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
500   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
501 }
502 
TEST_F(PassClassTest,TerminateInvocationInBody)503 TEST_F(PassClassTest, TerminateInvocationInBody) {
504   const std::string text = R"(OpCapability Shader
505 OpExtension "SPV_KHR_terminate_invocation"
506 OpMemoryModel Logical Simple
507 OpEntryPoint Fragment %1 "main"
508 OpExecutionMode %1 OriginUpperLeft
509 %2 = OpTypeVoid
510 %3 = OpTypeFunction %2
511 %4 = OpTypeBool
512 %5 = OpTypeInt 32 0
513 %6 = OpConstant %5 0
514 %7 = OpConstant %5 1
515 %8 = OpConstant %5 5
516 %1 = OpFunction %2 None %3
517 %9 = OpLabel
518 OpBranch %10
519 %10 = OpLabel
520 %11 = OpPhi %5 %6 %9 %12 %13
521 %14 = OpULessThan %4 %11 %8
522 OpLoopMerge %15 %13 Unroll
523 OpBranchConditional %14 %16 %15
524 %16 = OpLabel
525 OpTerminateInvocation
526 %13 = OpLabel
527 %12 = OpIAdd %5 %11 %7
528 OpBranch %10
529 %15 = OpLabel
530 OpReturn
531 OpFunctionEnd
532 )";
533   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
534   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
535 }
536 
537 /*
538 Generated from the following GLSL
539 #version 440 core
540 void main() {
541   int j = 0;
542   for (int i = 0; i < 10 && i > 0; i++) {
543     j++;
544   }
545 }
546 */
TEST_F(PassClassTest,MultipleConditionsSingleVariable)547 TEST_F(PassClassTest, MultipleConditionsSingleVariable) {
548   // clang-format off
549   // With LocalMultiStoreElimPass
550   const std::string text = R"(OpCapability Shader
551 %1 = OpExtInstImport "GLSL.std.450"
552 OpMemoryModel Logical GLSL450
553 OpEntryPoint Fragment %2 "main"
554 OpExecutionMode %2 OriginUpperLeft
555 OpSource GLSL 440
556 OpName %2 "main"
557 %3 = OpTypeVoid
558 %4 = OpTypeFunction %3
559 %5 = OpTypeInt 32 1
560 %6 = OpTypePointer Function %5
561 %7 = OpConstant %5 0
562 %8 = OpConstant %5 10
563 %9 = OpTypeBool
564 %10 = OpConstant %5 1
565 %2 = OpFunction %3 None %4
566 %11 = OpLabel
567 OpBranch %12
568 %12 = OpLabel
569 %13 = OpPhi %5 %7 %11 %14 %15
570 %16 = OpPhi %5 %7 %11 %17 %15
571 OpLoopMerge %18 %15 Unroll
572 OpBranch %19
573 %19 = OpLabel
574 %20 = OpSLessThan %9 %16 %8
575 %21 = OpSGreaterThan %9 %16 %7
576 %22 = OpLogicalAnd %9 %20 %21
577 OpBranchConditional %22 %23 %18
578 %23 = OpLabel
579 %14 = OpIAdd %5 %13 %10
580 OpBranch %15
581 %15 = OpLabel
582 %17 = OpIAdd %5 %16 %10
583 OpBranch %12
584 %18 = OpLabel
585 OpReturn
586 OpFunctionEnd
587 )";
588   // clang-format on
589   std::unique_ptr<IRContext> context =
590       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
591                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
592   Module* module = context->module();
593   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
594                              << text << std::endl;
595 
596   LoopUnroller loop_unroller;
597   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
598 
599   // Make sure the pass doesn't run
600   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
601   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
602   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
603 }
604 
605 /*
606 Generated from the following GLSL
607 #version 440 core
608 void main() {
609   int i = 0;
610   int j = 0;
611   int k = 0;
612   for (; i < 10 && j > 0; i++, j++) {
613     k++;
614   }
615 }
616 */
TEST_F(PassClassTest,MultipleConditionsMultipleVariables)617 TEST_F(PassClassTest, MultipleConditionsMultipleVariables) {
618   // clang-format off
619   // With LocalMultiStoreElimPass
620   const std::string text = R"(OpCapability Shader
621 %1 = OpExtInstImport "GLSL.std.450"
622 OpMemoryModel Logical GLSL450
623 OpEntryPoint Fragment %2 "main"
624 OpExecutionMode %2 OriginUpperLeft
625 OpSource GLSL 440
626 OpName %2 "main"
627 %3 = OpTypeVoid
628 %4 = OpTypeFunction %3
629 %5 = OpTypeInt 32 1
630 %6 = OpTypePointer Function %5
631 %7 = OpConstant %5 0
632 %8 = OpConstant %5 10
633 %9 = OpTypeBool
634 %10 = OpConstant %5 1
635 %2 = OpFunction %3 None %4
636 %11 = OpLabel
637 OpBranch %12
638 %12 = OpLabel
639 %13 = OpPhi %5 %7 %11 %14 %15
640 %16 = OpPhi %5 %7 %11 %17 %15
641 %18 = OpPhi %5 %7 %11 %19 %15
642 OpLoopMerge %20 %15 Unroll
643 OpBranch %21
644 %21 = OpLabel
645 %22 = OpSLessThan %9 %13 %8
646 %23 = OpSGreaterThan %9 %16 %7
647 %24 = OpLogicalAnd %9 %22 %23
648 OpBranchConditional %24 %25 %20
649 %25 = OpLabel
650 %19 = OpIAdd %5 %18 %10
651 OpBranch %15
652 %15 = OpLabel
653 %14 = OpIAdd %5 %13 %10
654 %17 = OpIAdd %5 %16 %10
655 OpBranch %12
656 %20 = OpLabel
657 OpReturn
658 OpFunctionEnd
659 )";
660   // clang-format on
661   std::unique_ptr<IRContext> context =
662       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
663                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
664   Module* module = context->module();
665   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
666                              << text << std::endl;
667 
668   LoopUnroller loop_unroller;
669   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
670 
671   // Make sure the pass doesn't run
672   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
673   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
674   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
675 }
676 
677 /*
678 Generated from the following GLSL
679 #version 440 core
680 void main() {
681   float i = 0.0;
682   int j = 0;
683   for (; i < 10; i++) {
684     j++;
685   }
686 }
687 */
TEST_F(PassClassTest,FloatingPointLoop)688 TEST_F(PassClassTest, FloatingPointLoop) {
689   // clang-format off
690   // With LocalMultiStoreElimPass
691   const std::string text = R"(OpCapability Shader
692 %1 = OpExtInstImport "GLSL.std.450"
693 OpMemoryModel Logical GLSL450
694 OpEntryPoint Fragment %2 "main"
695 OpExecutionMode %2 OriginUpperLeft
696 OpSource GLSL 440
697 OpName %2 "main"
698 %3 = OpTypeVoid
699 %4 = OpTypeFunction %3
700 %5 = OpTypeFloat 32
701 %6 = OpTypePointer Function %5
702 %7 = OpConstant %5 0
703 %8 = OpTypeInt 32 1
704 %9 = OpTypePointer Function %8
705 %10 = OpConstant %8 0
706 %11 = OpConstant %5 10
707 %12 = OpTypeBool
708 %13 = OpConstant %8 1
709 %14 = OpConstant %5 1
710 %2 = OpFunction %3 None %4
711 %15 = OpLabel
712 OpBranch %16
713 %16 = OpLabel
714 %17 = OpPhi %5 %7 %15 %18 %19
715 %20 = OpPhi %8 %10 %15 %21 %19
716 OpLoopMerge %22 %19 Unroll
717 OpBranch %23
718 %23 = OpLabel
719 %24 = OpFOrdLessThan %12 %17 %11
720 OpBranchConditional %24 %25 %22
721 %25 = OpLabel
722 %21 = OpIAdd %8 %20 %13
723 OpBranch %19
724 %19 = OpLabel
725 %18 = OpFAdd %5 %17 %14
726 OpBranch %16
727 %22 = OpLabel
728 OpReturn
729 OpFunctionEnd
730 )";
731   // clang-format on
732   std::unique_ptr<IRContext> context =
733       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
734                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
735   Module* module = context->module();
736   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
737                              << text << std::endl;
738 
739   LoopUnroller loop_unroller;
740   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
741 
742   // Make sure the pass doesn't run
743   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
744   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
745   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
746 }
747 
748 /*
749 Generated from the following GLSL
750 #version 440 core
751 void main() {
752   int i = 2;
753   int j = 0;
754   if (j == 0) { i = 5; }
755   for (; i < 3; ++i) {
756     j++;
757   }
758 }
759 */
TEST_F(PassClassTest,InductionPhiOutsideLoop)760 TEST_F(PassClassTest, InductionPhiOutsideLoop) {
761   // clang-format off
762   // With LocalMultiStoreElimPass
763   const std::string text = R"(OpCapability Shader
764 %1 = OpExtInstImport "GLSL.std.450"
765 OpMemoryModel Logical GLSL450
766 OpEntryPoint Fragment %2 "main"
767 OpExecutionMode %2 OriginUpperLeft
768 OpSource GLSL 440
769 OpName %2 "main"
770 %3 = OpTypeVoid
771 %4 = OpTypeFunction %3
772 %5 = OpTypeInt 32 1
773 %6 = OpTypePointer Function %5
774 %7 = OpConstant %5 2
775 %8 = OpConstant %5 0
776 %9 = OpTypeBool
777 %10 = OpConstant %5 5
778 %11 = OpConstant %5 3
779 %12 = OpConstant %5 1
780 %2 = OpFunction %3 None %4
781 %13 = OpLabel
782 %14 = OpIEqual %9 %8 %8
783 OpSelectionMerge %15 None
784 OpBranchConditional %14 %16 %15
785 %16 = OpLabel
786 OpBranch %15
787 %15 = OpLabel
788 %17 = OpPhi %5 %7 %13 %10 %16
789 OpBranch %18
790 %18 = OpLabel
791 %19 = OpPhi %5 %17 %15 %20 %21
792 %22 = OpPhi %5 %8 %15 %23 %21
793 OpLoopMerge %24 %21 Unroll
794 OpBranch %25
795 %25 = OpLabel
796 %26 = OpSLessThan %9 %19 %11
797 OpBranchConditional %26 %27 %24
798 %27 = OpLabel
799 %23 = OpIAdd %5 %22 %12
800 OpBranch %21
801 %21 = OpLabel
802 %20 = OpIAdd %5 %19 %12
803 OpBranch %18
804 %24 = OpLabel
805 OpReturn
806 OpFunctionEnd
807 )";
808   // clang-format on
809   std::unique_ptr<IRContext> context =
810       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
811                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
812   Module* module = context->module();
813   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
814                              << text << std::endl;
815 
816   LoopUnroller loop_unroller;
817   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
818 
819   // Make sure the pass doesn't run
820   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
821   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
822   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
823 }
824 
825 /*
826 Generated from the following GLSL
827 #version 440 core
828 void main() {
829   int j = 0;
830   for (int i = 0; i == 0; ++i) {
831     ++j;
832   }
833   for (int i = 0; i != 3; ++i) {
834     ++j;
835   }
836   for (int i = 0; i < 3; i *= 2) {
837     ++j;
838   }
839   for (int i = 10; i > 3; i /= 2) {
840     ++j;
841   }
842   for (int i = 10; i > 3; i |= 2) {
843     ++j;
844   }
845   for (int i = 10; i > 3; i &= 2) {
846     ++j;
847   }
848   for (int i = 10; i > 3; i ^= 2) {
849     ++j;
850   }
851   for (int i = 0; i < 3; i << 2) {
852     ++j;
853   }
854   for (int i = 10; i > 3; i >> 2) {
855     ++j;
856   }
857 }
858 */
TEST_F(PassClassTest,UnsupportedLoopTypes)859 TEST_F(PassClassTest, UnsupportedLoopTypes) {
860   // clang-format off
861   // With LocalMultiStoreElimPass
862   const std::string text = R"(OpCapability Shader
863 %1 = OpExtInstImport "GLSL.std.450"
864 OpMemoryModel Logical GLSL450
865 OpEntryPoint Fragment %2 "main"
866 OpExecutionMode %2 OriginUpperLeft
867 OpSource GLSL 440
868 OpName %2 "main"
869 %3 = OpTypeVoid
870 %4 = OpTypeFunction %3
871 %5 = OpTypeInt 32 1
872 %6 = OpTypePointer Function %5
873 %7 = OpConstant %5 0
874 %8 = OpTypeBool
875 %9 = OpConstant %5 1
876 %10 = OpConstant %5 3
877 %11 = OpConstant %5 2
878 %12 = OpConstant %5 10
879 %2 = OpFunction %3 None %4
880 %13 = OpLabel
881 OpBranch %14
882 %14 = OpLabel
883 %15 = OpPhi %5 %7 %13 %16 %17
884 %18 = OpPhi %5 %7 %13 %19 %17
885 OpLoopMerge %20 %17 Unroll
886 OpBranch %21
887 %21 = OpLabel
888 %22 = OpIEqual %8 %18 %7
889 OpBranchConditional %22 %23 %20
890 %23 = OpLabel
891 %16 = OpIAdd %5 %15 %9
892 OpBranch %17
893 %17 = OpLabel
894 %19 = OpIAdd %5 %18 %9
895 OpBranch %14
896 %20 = OpLabel
897 OpBranch %24
898 %24 = OpLabel
899 %25 = OpPhi %5 %15 %20 %26 %27
900 %28 = OpPhi %5 %7 %20 %29 %27
901 OpLoopMerge %30 %27 Unroll
902 OpBranch %31
903 %31 = OpLabel
904 %32 = OpINotEqual %8 %28 %10
905 OpBranchConditional %32 %33 %30
906 %33 = OpLabel
907 %26 = OpIAdd %5 %25 %9
908 OpBranch %27
909 %27 = OpLabel
910 %29 = OpIAdd %5 %28 %9
911 OpBranch %24
912 %30 = OpLabel
913 OpBranch %34
914 %34 = OpLabel
915 %35 = OpPhi %5 %25 %30 %36 %37
916 %38 = OpPhi %5 %7 %30 %39 %37
917 OpLoopMerge %40 %37 Unroll
918 OpBranch %41
919 %41 = OpLabel
920 %42 = OpSLessThan %8 %38 %10
921 OpBranchConditional %42 %43 %40
922 %43 = OpLabel
923 %36 = OpIAdd %5 %35 %9
924 OpBranch %37
925 %37 = OpLabel
926 %39 = OpIMul %5 %38 %11
927 OpBranch %34
928 %40 = OpLabel
929 OpBranch %44
930 %44 = OpLabel
931 %45 = OpPhi %5 %35 %40 %46 %47
932 %48 = OpPhi %5 %12 %40 %49 %47
933 OpLoopMerge %50 %47 Unroll
934 OpBranch %51
935 %51 = OpLabel
936 %52 = OpSGreaterThan %8 %48 %10
937 OpBranchConditional %52 %53 %50
938 %53 = OpLabel
939 %46 = OpIAdd %5 %45 %9
940 OpBranch %47
941 %47 = OpLabel
942 %49 = OpSDiv %5 %48 %11
943 OpBranch %44
944 %50 = OpLabel
945 OpBranch %54
946 %54 = OpLabel
947 %55 = OpPhi %5 %45 %50 %56 %57
948 %58 = OpPhi %5 %12 %50 %59 %57
949 OpLoopMerge %60 %57 Unroll
950 OpBranch %61
951 %61 = OpLabel
952 %62 = OpSGreaterThan %8 %58 %10
953 OpBranchConditional %62 %63 %60
954 %63 = OpLabel
955 %56 = OpIAdd %5 %55 %9
956 OpBranch %57
957 %57 = OpLabel
958 %59 = OpBitwiseOr %5 %58 %11
959 OpBranch %54
960 %60 = OpLabel
961 OpBranch %64
962 %64 = OpLabel
963 %65 = OpPhi %5 %55 %60 %66 %67
964 %68 = OpPhi %5 %12 %60 %69 %67
965 OpLoopMerge %70 %67 Unroll
966 OpBranch %71
967 %71 = OpLabel
968 %72 = OpSGreaterThan %8 %68 %10
969 OpBranchConditional %72 %73 %70
970 %73 = OpLabel
971 %66 = OpIAdd %5 %65 %9
972 OpBranch %67
973 %67 = OpLabel
974 %69 = OpBitwiseAnd %5 %68 %11
975 OpBranch %64
976 %70 = OpLabel
977 OpBranch %74
978 %74 = OpLabel
979 %75 = OpPhi %5 %65 %70 %76 %77
980 %78 = OpPhi %5 %12 %70 %79 %77
981 OpLoopMerge %80 %77 Unroll
982 OpBranch %81
983 %81 = OpLabel
984 %82 = OpSGreaterThan %8 %78 %10
985 OpBranchConditional %82 %83 %80
986 %83 = OpLabel
987 %76 = OpIAdd %5 %75 %9
988 OpBranch %77
989 %77 = OpLabel
990 %79 = OpBitwiseXor %5 %78 %11
991 OpBranch %74
992 %80 = OpLabel
993 OpBranch %84
994 %84 = OpLabel
995 %85 = OpPhi %5 %75 %80 %86 %87
996 OpLoopMerge %88 %87 Unroll
997 OpBranch %89
998 %89 = OpLabel
999 %90 = OpSLessThan %8 %7 %10
1000 OpBranchConditional %90 %91 %88
1001 %91 = OpLabel
1002 %86 = OpIAdd %5 %85 %9
1003 OpBranch %87
1004 %87 = OpLabel
1005 %92 = OpShiftLeftLogical %5 %7 %11
1006 OpBranch %84
1007 %88 = OpLabel
1008 OpBranch %93
1009 %93 = OpLabel
1010 %94 = OpPhi %5 %85 %88 %95 %96
1011 OpLoopMerge %97 %96 Unroll
1012 OpBranch %98
1013 %98 = OpLabel
1014 %99 = OpSGreaterThan %8 %12 %10
1015 OpBranchConditional %99 %100 %97
1016 %100 = OpLabel
1017 %95 = OpIAdd %5 %94 %9
1018 OpBranch %96
1019 %96 = OpLabel
1020 %101 = OpShiftRightArithmetic %5 %12 %11
1021 OpBranch %93
1022 %97 = OpLabel
1023 OpReturn
1024 OpFunctionEnd
1025 )";
1026   // clang-format on
1027   std::unique_ptr<IRContext> context =
1028       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1029                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1030   Module* module = context->module();
1031   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1032                              << text << std::endl;
1033 
1034   LoopUnroller loop_unroller;
1035   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1036 
1037   // Make sure the pass doesn't run
1038   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1039   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1040   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1041 }
1042 
1043 /*
1044 #version 430
1045 
1046 layout(location = 0) out float o;
1047 
1048 void main(void) {
1049     for (int j = 2; j < 0; j += 1) {
1050       o += 1.0;
1051     }
1052 }
1053 */
TEST_F(PassClassTest,NegativeNumberOfIterations)1054 TEST_F(PassClassTest, NegativeNumberOfIterations) {
1055   // clang-format off
1056   // With LocalMultiStoreElimPass
1057   const std::string text = R"(OpCapability Shader
1058 %1 = OpExtInstImport "GLSL.std.450"
1059 OpMemoryModel Logical GLSL450
1060 OpEntryPoint Fragment %2 "main" %3
1061 OpExecutionMode %2 OriginUpperLeft
1062 OpSource GLSL 430
1063 OpName %2 "main"
1064 OpName %3 "o"
1065 OpDecorate %3 Location 0
1066 %4 = OpTypeVoid
1067 %5 = OpTypeFunction %4
1068 %6 = OpTypeInt 32 1
1069 %7 = OpTypePointer Function %6
1070 %8 = OpConstant %6 2
1071 %9 = OpConstant %6 0
1072 %10 = OpTypeBool
1073 %11 = OpTypeFloat 32
1074 %12 = OpTypePointer Output %11
1075 %3 = OpVariable %12 Output
1076 %13 = OpConstant %11 1
1077 %14 = OpConstant %6 1
1078 %2 = OpFunction %4 None %5
1079 %15 = OpLabel
1080 OpBranch %16
1081 %16 = OpLabel
1082 %17 = OpPhi %6 %8 %15 %18 %19
1083 OpLoopMerge %20 %19 None
1084 OpBranch %21
1085 %21 = OpLabel
1086 %22 = OpSLessThan %10 %17 %9
1087 OpBranchConditional %22 %23 %20
1088 %23 = OpLabel
1089 %24 = OpLoad %11 %3
1090 %25 = OpFAdd %11 %24 %13
1091 OpStore %3 %25
1092 OpBranch %19
1093 %19 = OpLabel
1094 %18 = OpIAdd %6 %17 %14
1095 OpBranch %16
1096 %20 = OpLabel
1097 OpReturn
1098 OpFunctionEnd
1099 )";
1100   // clang-format on
1101   std::unique_ptr<IRContext> context =
1102       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1103                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1104   Module* module = context->module();
1105   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1106                              << text << std::endl;
1107 
1108   LoopUnroller loop_unroller;
1109   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1110 
1111   // Make sure the pass doesn't run
1112   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1113   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1114   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1115 }
1116 
1117 /*
1118 #version 430
1119 
1120 layout(location = 0) out float o;
1121 
1122 void main(void) {
1123   float s = 0.0;
1124   for (int j = 0; j < 3; j += 1) {
1125     s += 1.0;
1126     j += 1;
1127   }
1128   o = s;
1129 }
1130 */
TEST_F(PassClassTest,MultipleStepOperations)1131 TEST_F(PassClassTest, MultipleStepOperations) {
1132   // clang-format off
1133   // With LocalMultiStoreElimPass
1134 const std::string text = R"(OpCapability Shader
1135 %1 = OpExtInstImport "GLSL.std.450"
1136 OpMemoryModel Logical GLSL450
1137 OpEntryPoint Fragment %2 "main" %3
1138 OpExecutionMode %2 OriginUpperLeft
1139 OpSource GLSL 430
1140 OpName %2 "main"
1141 OpName %3 "o"
1142 OpDecorate %3 Location 0
1143 %4 = OpTypeVoid
1144 %5 = OpTypeFunction %4
1145 %6 = OpTypeFloat 32
1146 %7 = OpTypePointer Function %6
1147 %8 = OpConstant %6 0
1148 %9 = OpTypeInt 32 1
1149 %10 = OpTypePointer Function %9
1150 %11 = OpConstant %9 0
1151 %12 = OpConstant %9 3
1152 %13 = OpTypeBool
1153 %14 = OpConstant %6 1
1154 %15 = OpConstant %9 1
1155 %16 = OpTypePointer Output %6
1156 %3 = OpVariable %16 Output
1157 %2 = OpFunction %4 None %5
1158 %17 = OpLabel
1159 OpBranch %18
1160 %18 = OpLabel
1161 %19 = OpPhi %6 %8 %17 %20 %21
1162 %22 = OpPhi %9 %11 %17 %23 %21
1163 OpLoopMerge %24 %21 Unroll
1164 OpBranch %25
1165 %25 = OpLabel
1166 %26 = OpSLessThan %13 %22 %12
1167 OpBranchConditional %26 %27 %24
1168 %27 = OpLabel
1169 %20 = OpFAdd %6 %19 %14
1170 %28 = OpIAdd %9 %22 %15
1171 OpBranch %21
1172 %21 = OpLabel
1173 %23 = OpIAdd %9 %28 %15
1174 OpBranch %18
1175 %24 = OpLabel
1176 OpStore %3 %19
1177 OpReturn
1178 OpFunctionEnd
1179 )";
1180   // clang-format on
1181   std::unique_ptr<IRContext> context =
1182       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1183                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1184   Module* module = context->module();
1185   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1186                              << text << std::endl;
1187 
1188   LoopUnroller loop_unroller;
1189   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1190 
1191   // Make sure the pass doesn't run
1192   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1193   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1194   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1195 }
1196 
1197 /*
1198 #version 430
1199 
1200 layout(location = 0) out float o;
1201 
1202 void main(void) {
1203   float s = 0.0;
1204   for (int j = 10; j > 20; j -= 1) {
1205     s += 1.0;
1206   }
1207   o = s;
1208 }
1209 */
1210 
TEST_F(PassClassTest,ConditionFalseFromStartGreaterThan)1211 TEST_F(PassClassTest, ConditionFalseFromStartGreaterThan) {
1212   // clang-format off
1213   // With LocalMultiStoreElimPass
1214 const std::string text = R"(OpCapability Shader
1215 %1 = OpExtInstImport "GLSL.std.450"
1216 OpMemoryModel Logical GLSL450
1217 OpEntryPoint Fragment %2 "main" %3
1218 OpExecutionMode %2 OriginUpperLeft
1219 OpSource GLSL 430
1220 OpName %2 "main"
1221 OpName %3 "o"
1222 OpDecorate %3 Location 0
1223 %4 = OpTypeVoid
1224 %5 = OpTypeFunction %4
1225 %6 = OpTypeFloat 32
1226 %7 = OpTypePointer Function %6
1227 %8 = OpConstant %6 0
1228 %9 = OpTypeInt 32 1
1229 %10 = OpTypePointer Function %9
1230 %11 = OpConstant %9 10
1231 %12 = OpConstant %9 20
1232 %13 = OpTypeBool
1233 %14 = OpConstant %6 1
1234 %15 = OpConstant %9 1
1235 %16 = OpTypePointer Output %6
1236 %3 = OpVariable %16 Output
1237 %2 = OpFunction %4 None %5
1238 %17 = OpLabel
1239 OpBranch %18
1240 %18 = OpLabel
1241 %19 = OpPhi %6 %8 %17 %20 %21
1242 %22 = OpPhi %9 %11 %17 %23 %21
1243 OpLoopMerge %24 %21 Unroll
1244 OpBranch %25
1245 %25 = OpLabel
1246 %26 = OpSGreaterThan %13 %22 %12
1247 OpBranchConditional %26 %27 %24
1248 %27 = OpLabel
1249 %20 = OpFAdd %6 %19 %14
1250 OpBranch %21
1251 %21 = OpLabel
1252 %23 = OpISub %9 %22 %15
1253 OpBranch %18
1254 %24 = OpLabel
1255 OpStore %3 %19
1256 OpReturn
1257 OpFunctionEnd
1258 )";
1259   // clang-format on
1260   std::unique_ptr<IRContext> context =
1261       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1262                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1263   Module* module = context->module();
1264   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1265                              << text << std::endl;
1266 
1267   LoopUnroller loop_unroller;
1268   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1269 
1270   // Make sure the pass doesn't run
1271   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1272   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1273   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1274 }
1275 
1276 /*
1277 #version 430
1278 
1279 layout(location = 0) out float o;
1280 
1281 void main(void) {
1282   float s = 0.0;
1283   for (int j = 10; j >= 20; j -= 1) {
1284     s += 1.0;
1285   }
1286   o = s;
1287 }
1288 */
TEST_F(PassClassTest,ConditionFalseFromStartGreaterThanOrEqual)1289 TEST_F(PassClassTest, ConditionFalseFromStartGreaterThanOrEqual) {
1290   // clang-format off
1291   // With LocalMultiStoreElimPass
1292 const std::string text = R"(OpCapability Shader
1293 %1 = OpExtInstImport "GLSL.std.450"
1294 OpMemoryModel Logical GLSL450
1295 OpEntryPoint Fragment %2 "main" %3
1296 OpExecutionMode %2 OriginUpperLeft
1297 OpSource GLSL 430
1298 OpName %2 "main"
1299 OpName %3 "o"
1300 OpDecorate %3 Location 0
1301 %4 = OpTypeVoid
1302 %5 = OpTypeFunction %4
1303 %6 = OpTypeFloat 32
1304 %7 = OpTypePointer Function %6
1305 %8 = OpConstant %6 0
1306 %9 = OpTypeInt 32 1
1307 %10 = OpTypePointer Function %9
1308 %11 = OpConstant %9 10
1309 %12 = OpConstant %9 20
1310 %13 = OpTypeBool
1311 %14 = OpConstant %6 1
1312 %15 = OpConstant %9 1
1313 %16 = OpTypePointer Output %6
1314 %3 = OpVariable %16 Output
1315 %2 = OpFunction %4 None %5
1316 %17 = OpLabel
1317 OpBranch %18
1318 %18 = OpLabel
1319 %19 = OpPhi %6 %8 %17 %20 %21
1320 %22 = OpPhi %9 %11 %17 %23 %21
1321 OpLoopMerge %24 %21 Unroll
1322 OpBranch %25
1323 %25 = OpLabel
1324 %26 = OpSGreaterThanEqual %13 %22 %12
1325 OpBranchConditional %26 %27 %24
1326 %27 = OpLabel
1327 %20 = OpFAdd %6 %19 %14
1328 OpBranch %21
1329 %21 = OpLabel
1330 %23 = OpISub %9 %22 %15
1331 OpBranch %18
1332 %24 = OpLabel
1333 OpStore %3 %19
1334 OpReturn
1335 OpFunctionEnd
1336 )";
1337 
1338   // clang-format on
1339   std::unique_ptr<IRContext> context =
1340       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1341                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1342   Module* module = context->module();
1343   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1344                              << text << std::endl;
1345 
1346   LoopUnroller loop_unroller;
1347   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1348 
1349   // Make sure the pass doesn't run
1350   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1351   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1352   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1353 }
1354 
1355 /*
1356 #version 430
1357 
1358 layout(location = 0) out float o;
1359 
1360 void main(void) {
1361   float s = 0.0;
1362   for (int j = 20; j < 10; j -= 1) {
1363     s += 1.0;
1364   }
1365   o = s;
1366 }
1367 */
TEST_F(PassClassTest,ConditionFalseFromStartLessThan)1368 TEST_F(PassClassTest, ConditionFalseFromStartLessThan) {
1369   // clang-format off
1370   // With LocalMultiStoreElimPass
1371 const std::string text = R"(OpCapability Shader
1372 %1 = OpExtInstImport "GLSL.std.450"
1373 OpMemoryModel Logical GLSL450
1374 OpEntryPoint Fragment %2 "main" %3
1375 OpExecutionMode %2 OriginUpperLeft
1376 OpSource GLSL 430
1377 OpName %2 "main"
1378 OpName %3 "o"
1379 OpDecorate %3 Location 0
1380 %4 = OpTypeVoid
1381 %5 = OpTypeFunction %4
1382 %6 = OpTypeFloat 32
1383 %7 = OpTypePointer Function %6
1384 %8 = OpConstant %6 0
1385 %9 = OpTypeInt 32 1
1386 %10 = OpTypePointer Function %9
1387 %11 = OpConstant %9 20
1388 %12 = OpConstant %9 10
1389 %13 = OpTypeBool
1390 %14 = OpConstant %6 1
1391 %15 = OpConstant %9 1
1392 %16 = OpTypePointer Output %6
1393 %3 = OpVariable %16 Output
1394 %2 = OpFunction %4 None %5
1395 %17 = OpLabel
1396 OpBranch %18
1397 %18 = OpLabel
1398 %19 = OpPhi %6 %8 %17 %20 %21
1399 %22 = OpPhi %9 %11 %17 %23 %21
1400 OpLoopMerge %24 %21 Unroll
1401 OpBranch %25
1402 %25 = OpLabel
1403 %26 = OpSLessThan %13 %22 %12
1404 OpBranchConditional %26 %27 %24
1405 %27 = OpLabel
1406 %20 = OpFAdd %6 %19 %14
1407 OpBranch %21
1408 %21 = OpLabel
1409 %23 = OpISub %9 %22 %15
1410 OpBranch %18
1411 %24 = OpLabel
1412 OpStore %3 %19
1413 OpReturn
1414 OpFunctionEnd
1415 )";
1416 
1417   // clang-format on
1418   std::unique_ptr<IRContext> context =
1419       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1420                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1421   Module* module = context->module();
1422   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1423                              << text << std::endl;
1424 
1425   LoopUnroller loop_unroller;
1426   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1427 
1428   // Make sure the pass doesn't run
1429   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1430   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1431   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1432 }
1433 
1434 /*
1435 #version 430
1436 
1437 layout(location = 0) out float o;
1438 
1439 void main(void) {
1440   float s = 0.0;
1441   for (int j = 20; j <= 10; j -= 1) {
1442     s += 1.0;
1443   }
1444   o = s;
1445 }
1446 */
TEST_F(PassClassTest,ConditionFalseFromStartLessThanEqual)1447 TEST_F(PassClassTest, ConditionFalseFromStartLessThanEqual) {
1448   // clang-format off
1449   // With LocalMultiStoreElimPass
1450 const std::string text = R"(OpCapability Shader
1451 %1 = OpExtInstImport "GLSL.std.450"
1452 OpMemoryModel Logical GLSL450
1453 OpEntryPoint Fragment %2 "main" %3
1454 OpExecutionMode %2 OriginUpperLeft
1455 OpSource GLSL 430
1456 OpName %2 "main"
1457 OpName %3 "o"
1458 OpDecorate %3 Location 0
1459 %4 = OpTypeVoid
1460 %5 = OpTypeFunction %4
1461 %6 = OpTypeFloat 32
1462 %7 = OpTypePointer Function %6
1463 %8 = OpConstant %6 0
1464 %9 = OpTypeInt 32 1
1465 %10 = OpTypePointer Function %9
1466 %11 = OpConstant %9 20
1467 %12 = OpConstant %9 10
1468 %13 = OpTypeBool
1469 %14 = OpConstant %6 1
1470 %15 = OpConstant %9 1
1471 %16 = OpTypePointer Output %6
1472 %3 = OpVariable %16 Output
1473 %2 = OpFunction %4 None %5
1474 %17 = OpLabel
1475 OpBranch %18
1476 %18 = OpLabel
1477 %19 = OpPhi %6 %8 %17 %20 %21
1478 %22 = OpPhi %9 %11 %17 %23 %21
1479 OpLoopMerge %24 %21 Unroll
1480 OpBranch %25
1481 %25 = OpLabel
1482 %26 = OpSLessThanEqual %13 %22 %12
1483 OpBranchConditional %26 %27 %24
1484 %27 = OpLabel
1485 %20 = OpFAdd %6 %19 %14
1486 OpBranch %21
1487 %21 = OpLabel
1488 %23 = OpISub %9 %22 %15
1489 OpBranch %18
1490 %24 = OpLabel
1491 OpStore %3 %19
1492 OpReturn
1493 OpFunctionEnd
1494 )";
1495 
1496   // clang-format on
1497   std::unique_ptr<IRContext> context =
1498       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1499                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1500   Module* module = context->module();
1501   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1502                              << text << std::endl;
1503 
1504   LoopUnroller loop_unroller;
1505   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1506 
1507   // Make sure the pass doesn't run
1508   SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1509   SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1510   SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1511 }
1512 
1513 }  // namespace
1514 }  // namespace opt
1515 }  // namespace spvtools
1516