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
470 /*
471 Generated from the following GLSL
472 #version 440 core
473 void main() {
474 int j = 0;
475 for (int i = 0; i < 10 && i > 0; i++) {
476 j++;
477 }
478 }
479 */
TEST_F(PassClassTest,MultipleConditionsSingleVariable)480 TEST_F(PassClassTest, MultipleConditionsSingleVariable) {
481 // clang-format off
482 // With LocalMultiStoreElimPass
483 const std::string text = R"(OpCapability Shader
484 %1 = OpExtInstImport "GLSL.std.450"
485 OpMemoryModel Logical GLSL450
486 OpEntryPoint Fragment %2 "main"
487 OpExecutionMode %2 OriginUpperLeft
488 OpSource GLSL 440
489 OpName %2 "main"
490 %3 = OpTypeVoid
491 %4 = OpTypeFunction %3
492 %5 = OpTypeInt 32 1
493 %6 = OpTypePointer Function %5
494 %7 = OpConstant %5 0
495 %8 = OpConstant %5 10
496 %9 = OpTypeBool
497 %10 = OpConstant %5 1
498 %2 = OpFunction %3 None %4
499 %11 = OpLabel
500 OpBranch %12
501 %12 = OpLabel
502 %13 = OpPhi %5 %7 %11 %14 %15
503 %16 = OpPhi %5 %7 %11 %17 %15
504 OpLoopMerge %18 %15 Unroll
505 OpBranch %19
506 %19 = OpLabel
507 %20 = OpSLessThan %9 %16 %8
508 %21 = OpSGreaterThan %9 %16 %7
509 %22 = OpLogicalAnd %9 %20 %21
510 OpBranchConditional %22 %23 %18
511 %23 = OpLabel
512 %14 = OpIAdd %5 %13 %10
513 OpBranch %15
514 %15 = OpLabel
515 %17 = OpIAdd %5 %16 %10
516 OpBranch %12
517 %18 = OpLabel
518 OpReturn
519 OpFunctionEnd
520 )";
521 // clang-format on
522 std::unique_ptr<IRContext> context =
523 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
524 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
525 Module* module = context->module();
526 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
527 << text << std::endl;
528
529 LoopUnroller loop_unroller;
530 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
531
532 // Make sure the pass doesn't run
533 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
534 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
535 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
536 }
537
538 /*
539 Generated from the following GLSL
540 #version 440 core
541 void main() {
542 int i = 0;
543 int j = 0;
544 int k = 0;
545 for (; i < 10 && j > 0; i++, j++) {
546 k++;
547 }
548 }
549 */
TEST_F(PassClassTest,MultipleConditionsMultipleVariables)550 TEST_F(PassClassTest, MultipleConditionsMultipleVariables) {
551 // clang-format off
552 // With LocalMultiStoreElimPass
553 const std::string text = R"(OpCapability Shader
554 %1 = OpExtInstImport "GLSL.std.450"
555 OpMemoryModel Logical GLSL450
556 OpEntryPoint Fragment %2 "main"
557 OpExecutionMode %2 OriginUpperLeft
558 OpSource GLSL 440
559 OpName %2 "main"
560 %3 = OpTypeVoid
561 %4 = OpTypeFunction %3
562 %5 = OpTypeInt 32 1
563 %6 = OpTypePointer Function %5
564 %7 = OpConstant %5 0
565 %8 = OpConstant %5 10
566 %9 = OpTypeBool
567 %10 = OpConstant %5 1
568 %2 = OpFunction %3 None %4
569 %11 = OpLabel
570 OpBranch %12
571 %12 = OpLabel
572 %13 = OpPhi %5 %7 %11 %14 %15
573 %16 = OpPhi %5 %7 %11 %17 %15
574 %18 = OpPhi %5 %7 %11 %19 %15
575 OpLoopMerge %20 %15 Unroll
576 OpBranch %21
577 %21 = OpLabel
578 %22 = OpSLessThan %9 %13 %8
579 %23 = OpSGreaterThan %9 %16 %7
580 %24 = OpLogicalAnd %9 %22 %23
581 OpBranchConditional %24 %25 %20
582 %25 = OpLabel
583 %19 = OpIAdd %5 %18 %10
584 OpBranch %15
585 %15 = OpLabel
586 %14 = OpIAdd %5 %13 %10
587 %17 = OpIAdd %5 %16 %10
588 OpBranch %12
589 %20 = OpLabel
590 OpReturn
591 OpFunctionEnd
592 )";
593 // clang-format on
594 std::unique_ptr<IRContext> context =
595 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
596 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
597 Module* module = context->module();
598 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
599 << text << std::endl;
600
601 LoopUnroller loop_unroller;
602 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
603
604 // Make sure the pass doesn't run
605 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
606 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
607 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
608 }
609
610 /*
611 Generated from the following GLSL
612 #version 440 core
613 void main() {
614 float i = 0.0;
615 int j = 0;
616 for (; i < 10; i++) {
617 j++;
618 }
619 }
620 */
TEST_F(PassClassTest,FloatingPointLoop)621 TEST_F(PassClassTest, FloatingPointLoop) {
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 = OpTypeFloat 32
634 %6 = OpTypePointer Function %5
635 %7 = OpConstant %5 0
636 %8 = OpTypeInt 32 1
637 %9 = OpTypePointer Function %8
638 %10 = OpConstant %8 0
639 %11 = OpConstant %5 10
640 %12 = OpTypeBool
641 %13 = OpConstant %8 1
642 %14 = OpConstant %5 1
643 %2 = OpFunction %3 None %4
644 %15 = OpLabel
645 OpBranch %16
646 %16 = OpLabel
647 %17 = OpPhi %5 %7 %15 %18 %19
648 %20 = OpPhi %8 %10 %15 %21 %19
649 OpLoopMerge %22 %19 Unroll
650 OpBranch %23
651 %23 = OpLabel
652 %24 = OpFOrdLessThan %12 %17 %11
653 OpBranchConditional %24 %25 %22
654 %25 = OpLabel
655 %21 = OpIAdd %8 %20 %13
656 OpBranch %19
657 %19 = OpLabel
658 %18 = OpFAdd %5 %17 %14
659 OpBranch %16
660 %22 = 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 int i = 2;
686 int j = 0;
687 if (j == 0) { i = 5; }
688 for (; i < 3; ++i) {
689 j++;
690 }
691 }
692 */
TEST_F(PassClassTest,InductionPhiOutsideLoop)693 TEST_F(PassClassTest, InductionPhiOutsideLoop) {
694 // clang-format off
695 // With LocalMultiStoreElimPass
696 const std::string text = R"(OpCapability Shader
697 %1 = OpExtInstImport "GLSL.std.450"
698 OpMemoryModel Logical GLSL450
699 OpEntryPoint Fragment %2 "main"
700 OpExecutionMode %2 OriginUpperLeft
701 OpSource GLSL 440
702 OpName %2 "main"
703 %3 = OpTypeVoid
704 %4 = OpTypeFunction %3
705 %5 = OpTypeInt 32 1
706 %6 = OpTypePointer Function %5
707 %7 = OpConstant %5 2
708 %8 = OpConstant %5 0
709 %9 = OpTypeBool
710 %10 = OpConstant %5 5
711 %11 = OpConstant %5 3
712 %12 = OpConstant %5 1
713 %2 = OpFunction %3 None %4
714 %13 = OpLabel
715 %14 = OpIEqual %9 %8 %8
716 OpSelectionMerge %15 None
717 OpBranchConditional %14 %16 %15
718 %16 = OpLabel
719 OpBranch %15
720 %15 = OpLabel
721 %17 = OpPhi %5 %7 %13 %10 %16
722 OpBranch %18
723 %18 = OpLabel
724 %19 = OpPhi %5 %17 %15 %20 %21
725 %22 = OpPhi %5 %8 %15 %23 %21
726 OpLoopMerge %24 %21 Unroll
727 OpBranch %25
728 %25 = OpLabel
729 %26 = OpSLessThan %9 %19 %11
730 OpBranchConditional %26 %27 %24
731 %27 = OpLabel
732 %23 = OpIAdd %5 %22 %12
733 OpBranch %21
734 %21 = OpLabel
735 %20 = OpIAdd %5 %19 %12
736 OpBranch %18
737 %24 = OpLabel
738 OpReturn
739 OpFunctionEnd
740 )";
741 // clang-format on
742 std::unique_ptr<IRContext> context =
743 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
744 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
745 Module* module = context->module();
746 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
747 << text << std::endl;
748
749 LoopUnroller loop_unroller;
750 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
751
752 // Make sure the pass doesn't run
753 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
754 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
755 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
756 }
757
758 /*
759 Generated from the following GLSL
760 #version 440 core
761 void main() {
762 int j = 0;
763 for (int i = 0; i == 0; ++i) {
764 ++j;
765 }
766 for (int i = 0; i != 3; ++i) {
767 ++j;
768 }
769 for (int i = 0; i < 3; i *= 2) {
770 ++j;
771 }
772 for (int i = 10; i > 3; i /= 2) {
773 ++j;
774 }
775 for (int i = 10; i > 3; i |= 2) {
776 ++j;
777 }
778 for (int i = 10; i > 3; i &= 2) {
779 ++j;
780 }
781 for (int i = 10; i > 3; i ^= 2) {
782 ++j;
783 }
784 for (int i = 0; i < 3; i << 2) {
785 ++j;
786 }
787 for (int i = 10; i > 3; i >> 2) {
788 ++j;
789 }
790 }
791 */
TEST_F(PassClassTest,UnsupportedLoopTypes)792 TEST_F(PassClassTest, UnsupportedLoopTypes) {
793 // clang-format off
794 // With LocalMultiStoreElimPass
795 const std::string text = R"(OpCapability Shader
796 %1 = OpExtInstImport "GLSL.std.450"
797 OpMemoryModel Logical GLSL450
798 OpEntryPoint Fragment %2 "main"
799 OpExecutionMode %2 OriginUpperLeft
800 OpSource GLSL 440
801 OpName %2 "main"
802 %3 = OpTypeVoid
803 %4 = OpTypeFunction %3
804 %5 = OpTypeInt 32 1
805 %6 = OpTypePointer Function %5
806 %7 = OpConstant %5 0
807 %8 = OpTypeBool
808 %9 = OpConstant %5 1
809 %10 = OpConstant %5 3
810 %11 = OpConstant %5 2
811 %12 = OpConstant %5 10
812 %2 = OpFunction %3 None %4
813 %13 = OpLabel
814 OpBranch %14
815 %14 = OpLabel
816 %15 = OpPhi %5 %7 %13 %16 %17
817 %18 = OpPhi %5 %7 %13 %19 %17
818 OpLoopMerge %20 %17 Unroll
819 OpBranch %21
820 %21 = OpLabel
821 %22 = OpIEqual %8 %18 %7
822 OpBranchConditional %22 %23 %20
823 %23 = OpLabel
824 %16 = OpIAdd %5 %15 %9
825 OpBranch %17
826 %17 = OpLabel
827 %19 = OpIAdd %5 %18 %9
828 OpBranch %14
829 %20 = OpLabel
830 OpBranch %24
831 %24 = OpLabel
832 %25 = OpPhi %5 %15 %20 %26 %27
833 %28 = OpPhi %5 %7 %20 %29 %27
834 OpLoopMerge %30 %27 Unroll
835 OpBranch %31
836 %31 = OpLabel
837 %32 = OpINotEqual %8 %28 %10
838 OpBranchConditional %32 %33 %30
839 %33 = OpLabel
840 %26 = OpIAdd %5 %25 %9
841 OpBranch %27
842 %27 = OpLabel
843 %29 = OpIAdd %5 %28 %9
844 OpBranch %24
845 %30 = OpLabel
846 OpBranch %34
847 %34 = OpLabel
848 %35 = OpPhi %5 %25 %30 %36 %37
849 %38 = OpPhi %5 %7 %30 %39 %37
850 OpLoopMerge %40 %37 Unroll
851 OpBranch %41
852 %41 = OpLabel
853 %42 = OpSLessThan %8 %38 %10
854 OpBranchConditional %42 %43 %40
855 %43 = OpLabel
856 %36 = OpIAdd %5 %35 %9
857 OpBranch %37
858 %37 = OpLabel
859 %39 = OpIMul %5 %38 %11
860 OpBranch %34
861 %40 = OpLabel
862 OpBranch %44
863 %44 = OpLabel
864 %45 = OpPhi %5 %35 %40 %46 %47
865 %48 = OpPhi %5 %12 %40 %49 %47
866 OpLoopMerge %50 %47 Unroll
867 OpBranch %51
868 %51 = OpLabel
869 %52 = OpSGreaterThan %8 %48 %10
870 OpBranchConditional %52 %53 %50
871 %53 = OpLabel
872 %46 = OpIAdd %5 %45 %9
873 OpBranch %47
874 %47 = OpLabel
875 %49 = OpSDiv %5 %48 %11
876 OpBranch %44
877 %50 = OpLabel
878 OpBranch %54
879 %54 = OpLabel
880 %55 = OpPhi %5 %45 %50 %56 %57
881 %58 = OpPhi %5 %12 %50 %59 %57
882 OpLoopMerge %60 %57 Unroll
883 OpBranch %61
884 %61 = OpLabel
885 %62 = OpSGreaterThan %8 %58 %10
886 OpBranchConditional %62 %63 %60
887 %63 = OpLabel
888 %56 = OpIAdd %5 %55 %9
889 OpBranch %57
890 %57 = OpLabel
891 %59 = OpBitwiseOr %5 %58 %11
892 OpBranch %54
893 %60 = OpLabel
894 OpBranch %64
895 %64 = OpLabel
896 %65 = OpPhi %5 %55 %60 %66 %67
897 %68 = OpPhi %5 %12 %60 %69 %67
898 OpLoopMerge %70 %67 Unroll
899 OpBranch %71
900 %71 = OpLabel
901 %72 = OpSGreaterThan %8 %68 %10
902 OpBranchConditional %72 %73 %70
903 %73 = OpLabel
904 %66 = OpIAdd %5 %65 %9
905 OpBranch %67
906 %67 = OpLabel
907 %69 = OpBitwiseAnd %5 %68 %11
908 OpBranch %64
909 %70 = OpLabel
910 OpBranch %74
911 %74 = OpLabel
912 %75 = OpPhi %5 %65 %70 %76 %77
913 %78 = OpPhi %5 %12 %70 %79 %77
914 OpLoopMerge %80 %77 Unroll
915 OpBranch %81
916 %81 = OpLabel
917 %82 = OpSGreaterThan %8 %78 %10
918 OpBranchConditional %82 %83 %80
919 %83 = OpLabel
920 %76 = OpIAdd %5 %75 %9
921 OpBranch %77
922 %77 = OpLabel
923 %79 = OpBitwiseXor %5 %78 %11
924 OpBranch %74
925 %80 = OpLabel
926 OpBranch %84
927 %84 = OpLabel
928 %85 = OpPhi %5 %75 %80 %86 %87
929 OpLoopMerge %88 %87 Unroll
930 OpBranch %89
931 %89 = OpLabel
932 %90 = OpSLessThan %8 %7 %10
933 OpBranchConditional %90 %91 %88
934 %91 = OpLabel
935 %86 = OpIAdd %5 %85 %9
936 OpBranch %87
937 %87 = OpLabel
938 %92 = OpShiftLeftLogical %5 %7 %11
939 OpBranch %84
940 %88 = OpLabel
941 OpBranch %93
942 %93 = OpLabel
943 %94 = OpPhi %5 %85 %88 %95 %96
944 OpLoopMerge %97 %96 Unroll
945 OpBranch %98
946 %98 = OpLabel
947 %99 = OpSGreaterThan %8 %12 %10
948 OpBranchConditional %99 %100 %97
949 %100 = OpLabel
950 %95 = OpIAdd %5 %94 %9
951 OpBranch %96
952 %96 = OpLabel
953 %101 = OpShiftRightArithmetic %5 %12 %11
954 OpBranch %93
955 %97 = OpLabel
956 OpReturn
957 OpFunctionEnd
958 )";
959 // clang-format on
960 std::unique_ptr<IRContext> context =
961 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
962 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
963 Module* module = context->module();
964 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
965 << text << std::endl;
966
967 LoopUnroller loop_unroller;
968 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
969
970 // Make sure the pass doesn't run
971 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
972 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
973 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
974 }
975
976 /*
977 #version 430
978
979 layout(location = 0) out float o;
980
981 void main(void) {
982 for (int j = 2; j < 0; j += 1) {
983 o += 1.0;
984 }
985 }
986 */
TEST_F(PassClassTest,NegativeNumberOfIterations)987 TEST_F(PassClassTest, NegativeNumberOfIterations) {
988 // clang-format off
989 // With LocalMultiStoreElimPass
990 const std::string text = R"(OpCapability Shader
991 %1 = OpExtInstImport "GLSL.std.450"
992 OpMemoryModel Logical GLSL450
993 OpEntryPoint Fragment %2 "main" %3
994 OpExecutionMode %2 OriginUpperLeft
995 OpSource GLSL 430
996 OpName %2 "main"
997 OpName %3 "o"
998 OpDecorate %3 Location 0
999 %4 = OpTypeVoid
1000 %5 = OpTypeFunction %4
1001 %6 = OpTypeInt 32 1
1002 %7 = OpTypePointer Function %6
1003 %8 = OpConstant %6 2
1004 %9 = OpConstant %6 0
1005 %10 = OpTypeBool
1006 %11 = OpTypeFloat 32
1007 %12 = OpTypePointer Output %11
1008 %3 = OpVariable %12 Output
1009 %13 = OpConstant %11 1
1010 %14 = OpConstant %6 1
1011 %2 = OpFunction %4 None %5
1012 %15 = OpLabel
1013 OpBranch %16
1014 %16 = OpLabel
1015 %17 = OpPhi %6 %8 %15 %18 %19
1016 OpLoopMerge %20 %19 None
1017 OpBranch %21
1018 %21 = OpLabel
1019 %22 = OpSLessThan %10 %17 %9
1020 OpBranchConditional %22 %23 %20
1021 %23 = OpLabel
1022 %24 = OpLoad %11 %3
1023 %25 = OpFAdd %11 %24 %13
1024 OpStore %3 %25
1025 OpBranch %19
1026 %19 = OpLabel
1027 %18 = OpIAdd %6 %17 %14
1028 OpBranch %16
1029 %20 = OpLabel
1030 OpReturn
1031 OpFunctionEnd
1032 )";
1033 // clang-format on
1034 std::unique_ptr<IRContext> context =
1035 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1036 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1037 Module* module = context->module();
1038 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1039 << text << std::endl;
1040
1041 LoopUnroller loop_unroller;
1042 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1043
1044 // Make sure the pass doesn't run
1045 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1046 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1047 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1048 }
1049
1050 /*
1051 #version 430
1052
1053 layout(location = 0) out float o;
1054
1055 void main(void) {
1056 float s = 0.0;
1057 for (int j = 0; j < 3; j += 1) {
1058 s += 1.0;
1059 j += 1;
1060 }
1061 o = s;
1062 }
1063 */
TEST_F(PassClassTest,MultipleStepOperations)1064 TEST_F(PassClassTest, MultipleStepOperations) {
1065 // clang-format off
1066 // With LocalMultiStoreElimPass
1067 const std::string text = R"(OpCapability Shader
1068 %1 = OpExtInstImport "GLSL.std.450"
1069 OpMemoryModel Logical GLSL450
1070 OpEntryPoint Fragment %2 "main" %3
1071 OpExecutionMode %2 OriginUpperLeft
1072 OpSource GLSL 430
1073 OpName %2 "main"
1074 OpName %3 "o"
1075 OpDecorate %3 Location 0
1076 %4 = OpTypeVoid
1077 %5 = OpTypeFunction %4
1078 %6 = OpTypeFloat 32
1079 %7 = OpTypePointer Function %6
1080 %8 = OpConstant %6 0
1081 %9 = OpTypeInt 32 1
1082 %10 = OpTypePointer Function %9
1083 %11 = OpConstant %9 0
1084 %12 = OpConstant %9 3
1085 %13 = OpTypeBool
1086 %14 = OpConstant %6 1
1087 %15 = OpConstant %9 1
1088 %16 = OpTypePointer Output %6
1089 %3 = OpVariable %16 Output
1090 %2 = OpFunction %4 None %5
1091 %17 = OpLabel
1092 OpBranch %18
1093 %18 = OpLabel
1094 %19 = OpPhi %6 %8 %17 %20 %21
1095 %22 = OpPhi %9 %11 %17 %23 %21
1096 OpLoopMerge %24 %21 Unroll
1097 OpBranch %25
1098 %25 = OpLabel
1099 %26 = OpSLessThan %13 %22 %12
1100 OpBranchConditional %26 %27 %24
1101 %27 = OpLabel
1102 %20 = OpFAdd %6 %19 %14
1103 %28 = OpIAdd %9 %22 %15
1104 OpBranch %21
1105 %21 = OpLabel
1106 %23 = OpIAdd %9 %28 %15
1107 OpBranch %18
1108 %24 = OpLabel
1109 OpStore %3 %19
1110 OpReturn
1111 OpFunctionEnd
1112 )";
1113 // clang-format on
1114 std::unique_ptr<IRContext> context =
1115 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1116 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1117 Module* module = context->module();
1118 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1119 << text << std::endl;
1120
1121 LoopUnroller loop_unroller;
1122 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1123
1124 // Make sure the pass doesn't run
1125 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1126 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1127 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1128 }
1129
1130 /*
1131 #version 430
1132
1133 layout(location = 0) out float o;
1134
1135 void main(void) {
1136 float s = 0.0;
1137 for (int j = 10; j > 20; j -= 1) {
1138 s += 1.0;
1139 }
1140 o = s;
1141 }
1142 */
1143
TEST_F(PassClassTest,ConditionFalseFromStartGreaterThan)1144 TEST_F(PassClassTest, ConditionFalseFromStartGreaterThan) {
1145 // clang-format off
1146 // With LocalMultiStoreElimPass
1147 const std::string text = R"(OpCapability Shader
1148 %1 = OpExtInstImport "GLSL.std.450"
1149 OpMemoryModel Logical GLSL450
1150 OpEntryPoint Fragment %2 "main" %3
1151 OpExecutionMode %2 OriginUpperLeft
1152 OpSource GLSL 430
1153 OpName %2 "main"
1154 OpName %3 "o"
1155 OpDecorate %3 Location 0
1156 %4 = OpTypeVoid
1157 %5 = OpTypeFunction %4
1158 %6 = OpTypeFloat 32
1159 %7 = OpTypePointer Function %6
1160 %8 = OpConstant %6 0
1161 %9 = OpTypeInt 32 1
1162 %10 = OpTypePointer Function %9
1163 %11 = OpConstant %9 10
1164 %12 = OpConstant %9 20
1165 %13 = OpTypeBool
1166 %14 = OpConstant %6 1
1167 %15 = OpConstant %9 1
1168 %16 = OpTypePointer Output %6
1169 %3 = OpVariable %16 Output
1170 %2 = OpFunction %4 None %5
1171 %17 = OpLabel
1172 OpBranch %18
1173 %18 = OpLabel
1174 %19 = OpPhi %6 %8 %17 %20 %21
1175 %22 = OpPhi %9 %11 %17 %23 %21
1176 OpLoopMerge %24 %21 Unroll
1177 OpBranch %25
1178 %25 = OpLabel
1179 %26 = OpSGreaterThan %13 %22 %12
1180 OpBranchConditional %26 %27 %24
1181 %27 = OpLabel
1182 %20 = OpFAdd %6 %19 %14
1183 OpBranch %21
1184 %21 = OpLabel
1185 %23 = OpISub %9 %22 %15
1186 OpBranch %18
1187 %24 = OpLabel
1188 OpStore %3 %19
1189 OpReturn
1190 OpFunctionEnd
1191 )";
1192 // clang-format on
1193 std::unique_ptr<IRContext> context =
1194 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1195 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1196 Module* module = context->module();
1197 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1198 << text << std::endl;
1199
1200 LoopUnroller loop_unroller;
1201 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1202
1203 // Make sure the pass doesn't run
1204 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1205 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1206 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1207 }
1208
1209 /*
1210 #version 430
1211
1212 layout(location = 0) out float o;
1213
1214 void main(void) {
1215 float s = 0.0;
1216 for (int j = 10; j >= 20; j -= 1) {
1217 s += 1.0;
1218 }
1219 o = s;
1220 }
1221 */
TEST_F(PassClassTest,ConditionFalseFromStartGreaterThanOrEqual)1222 TEST_F(PassClassTest, ConditionFalseFromStartGreaterThanOrEqual) {
1223 // clang-format off
1224 // With LocalMultiStoreElimPass
1225 const std::string text = R"(OpCapability Shader
1226 %1 = OpExtInstImport "GLSL.std.450"
1227 OpMemoryModel Logical GLSL450
1228 OpEntryPoint Fragment %2 "main" %3
1229 OpExecutionMode %2 OriginUpperLeft
1230 OpSource GLSL 430
1231 OpName %2 "main"
1232 OpName %3 "o"
1233 OpDecorate %3 Location 0
1234 %4 = OpTypeVoid
1235 %5 = OpTypeFunction %4
1236 %6 = OpTypeFloat 32
1237 %7 = OpTypePointer Function %6
1238 %8 = OpConstant %6 0
1239 %9 = OpTypeInt 32 1
1240 %10 = OpTypePointer Function %9
1241 %11 = OpConstant %9 10
1242 %12 = OpConstant %9 20
1243 %13 = OpTypeBool
1244 %14 = OpConstant %6 1
1245 %15 = OpConstant %9 1
1246 %16 = OpTypePointer Output %6
1247 %3 = OpVariable %16 Output
1248 %2 = OpFunction %4 None %5
1249 %17 = OpLabel
1250 OpBranch %18
1251 %18 = OpLabel
1252 %19 = OpPhi %6 %8 %17 %20 %21
1253 %22 = OpPhi %9 %11 %17 %23 %21
1254 OpLoopMerge %24 %21 Unroll
1255 OpBranch %25
1256 %25 = OpLabel
1257 %26 = OpSGreaterThanEqual %13 %22 %12
1258 OpBranchConditional %26 %27 %24
1259 %27 = OpLabel
1260 %20 = OpFAdd %6 %19 %14
1261 OpBranch %21
1262 %21 = OpLabel
1263 %23 = OpISub %9 %22 %15
1264 OpBranch %18
1265 %24 = OpLabel
1266 OpStore %3 %19
1267 OpReturn
1268 OpFunctionEnd
1269 )";
1270
1271 // clang-format on
1272 std::unique_ptr<IRContext> context =
1273 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1274 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1275 Module* module = context->module();
1276 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1277 << text << std::endl;
1278
1279 LoopUnroller loop_unroller;
1280 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1281
1282 // Make sure the pass doesn't run
1283 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1284 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1285 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1286 }
1287
1288 /*
1289 #version 430
1290
1291 layout(location = 0) out float o;
1292
1293 void main(void) {
1294 float s = 0.0;
1295 for (int j = 20; j < 10; j -= 1) {
1296 s += 1.0;
1297 }
1298 o = s;
1299 }
1300 */
TEST_F(PassClassTest,ConditionFalseFromStartLessThan)1301 TEST_F(PassClassTest, ConditionFalseFromStartLessThan) {
1302 // clang-format off
1303 // With LocalMultiStoreElimPass
1304 const std::string text = R"(OpCapability Shader
1305 %1 = OpExtInstImport "GLSL.std.450"
1306 OpMemoryModel Logical GLSL450
1307 OpEntryPoint Fragment %2 "main" %3
1308 OpExecutionMode %2 OriginUpperLeft
1309 OpSource GLSL 430
1310 OpName %2 "main"
1311 OpName %3 "o"
1312 OpDecorate %3 Location 0
1313 %4 = OpTypeVoid
1314 %5 = OpTypeFunction %4
1315 %6 = OpTypeFloat 32
1316 %7 = OpTypePointer Function %6
1317 %8 = OpConstant %6 0
1318 %9 = OpTypeInt 32 1
1319 %10 = OpTypePointer Function %9
1320 %11 = OpConstant %9 20
1321 %12 = OpConstant %9 10
1322 %13 = OpTypeBool
1323 %14 = OpConstant %6 1
1324 %15 = OpConstant %9 1
1325 %16 = OpTypePointer Output %6
1326 %3 = OpVariable %16 Output
1327 %2 = OpFunction %4 None %5
1328 %17 = OpLabel
1329 OpBranch %18
1330 %18 = OpLabel
1331 %19 = OpPhi %6 %8 %17 %20 %21
1332 %22 = OpPhi %9 %11 %17 %23 %21
1333 OpLoopMerge %24 %21 Unroll
1334 OpBranch %25
1335 %25 = OpLabel
1336 %26 = OpSLessThan %13 %22 %12
1337 OpBranchConditional %26 %27 %24
1338 %27 = OpLabel
1339 %20 = OpFAdd %6 %19 %14
1340 OpBranch %21
1341 %21 = OpLabel
1342 %23 = OpISub %9 %22 %15
1343 OpBranch %18
1344 %24 = OpLabel
1345 OpStore %3 %19
1346 OpReturn
1347 OpFunctionEnd
1348 )";
1349
1350 // clang-format on
1351 std::unique_ptr<IRContext> context =
1352 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1353 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1354 Module* module = context->module();
1355 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1356 << text << std::endl;
1357
1358 LoopUnroller loop_unroller;
1359 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1360
1361 // Make sure the pass doesn't run
1362 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1363 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1364 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1365 }
1366
1367 /*
1368 #version 430
1369
1370 layout(location = 0) out float o;
1371
1372 void main(void) {
1373 float s = 0.0;
1374 for (int j = 20; j <= 10; j -= 1) {
1375 s += 1.0;
1376 }
1377 o = s;
1378 }
1379 */
TEST_F(PassClassTest,ConditionFalseFromStartLessThanEqual)1380 TEST_F(PassClassTest, ConditionFalseFromStartLessThanEqual) {
1381 // clang-format off
1382 // With LocalMultiStoreElimPass
1383 const std::string text = R"(OpCapability Shader
1384 %1 = OpExtInstImport "GLSL.std.450"
1385 OpMemoryModel Logical GLSL450
1386 OpEntryPoint Fragment %2 "main" %3
1387 OpExecutionMode %2 OriginUpperLeft
1388 OpSource GLSL 430
1389 OpName %2 "main"
1390 OpName %3 "o"
1391 OpDecorate %3 Location 0
1392 %4 = OpTypeVoid
1393 %5 = OpTypeFunction %4
1394 %6 = OpTypeFloat 32
1395 %7 = OpTypePointer Function %6
1396 %8 = OpConstant %6 0
1397 %9 = OpTypeInt 32 1
1398 %10 = OpTypePointer Function %9
1399 %11 = OpConstant %9 20
1400 %12 = OpConstant %9 10
1401 %13 = OpTypeBool
1402 %14 = OpConstant %6 1
1403 %15 = OpConstant %9 1
1404 %16 = OpTypePointer Output %6
1405 %3 = OpVariable %16 Output
1406 %2 = OpFunction %4 None %5
1407 %17 = OpLabel
1408 OpBranch %18
1409 %18 = OpLabel
1410 %19 = OpPhi %6 %8 %17 %20 %21
1411 %22 = OpPhi %9 %11 %17 %23 %21
1412 OpLoopMerge %24 %21 Unroll
1413 OpBranch %25
1414 %25 = OpLabel
1415 %26 = OpSLessThanEqual %13 %22 %12
1416 OpBranchConditional %26 %27 %24
1417 %27 = OpLabel
1418 %20 = OpFAdd %6 %19 %14
1419 OpBranch %21
1420 %21 = OpLabel
1421 %23 = OpISub %9 %22 %15
1422 OpBranch %18
1423 %24 = OpLabel
1424 OpStore %3 %19
1425 OpReturn
1426 OpFunctionEnd
1427 )";
1428
1429 // clang-format on
1430 std::unique_ptr<IRContext> context =
1431 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1432 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1433 Module* module = context->module();
1434 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1435 << text << std::endl;
1436
1437 LoopUnroller loop_unroller;
1438 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1439
1440 // Make sure the pass doesn't run
1441 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
1442 SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
1443 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
1444 }
1445
1446 } // namespace
1447 } // namespace opt
1448 } // namespace spvtools
1449