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