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