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