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