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 "source/opt/loop_fission.h"
16
17 #include <memory>
18 #include <vector>
19
20 #include "gmock/gmock.h"
21 #include "source/opt/loop_utils.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 FissionClassTest = PassTest<::testing::Test>;
33
34 /*
35 Generated from the following GLSL
36
37 #version 430
38
39 void main(void) {
40 float A[10];
41 float B[10];
42 for (int i = 0; i < 10; i++) {
43 A[i] = B[i];
44 B[i] = A[i];
45 }
46 }
47
48 Result should be equivalent to:
49
50 void main(void) {
51 float A[10];
52 float B[10];
53 for (int i = 0; i < 10; i++) {
54 A[i] = B[i];
55 }
56
57 for (int i = 0; i < 10; i++) {
58 B[i] = A[i];
59 }
60 }
61 */
TEST_F(FissionClassTest,SimpleFission)62 TEST_F(FissionClassTest, SimpleFission) {
63 // clang-format off
64 // With LocalMultiStoreElimPass
65 const std::string source = R"(OpCapability Shader
66 %1 = OpExtInstImport "GLSL.std.450"
67 OpMemoryModel Logical GLSL450
68 OpEntryPoint Fragment %2 "main"
69 OpExecutionMode %2 OriginUpperLeft
70 OpSource GLSL 430
71 OpName %2 "main"
72 OpName %3 "i"
73 OpName %4 "A"
74 OpName %5 "B"
75 %6 = OpTypeVoid
76 %7 = OpTypeFunction %6
77 %8 = OpTypeInt 32 1
78 %9 = OpTypePointer Function %8
79 %10 = OpConstant %8 0
80 %11 = OpConstant %8 10
81 %12 = OpTypeBool
82 %13 = OpTypeFloat 32
83 %14 = OpTypeInt 32 0
84 %15 = OpConstant %14 10
85 %16 = OpTypeArray %13 %15
86 %17 = OpTypePointer Function %16
87 %18 = OpTypePointer Function %13
88 %19 = OpConstant %8 1
89 %2 = OpFunction %6 None %7
90 %20 = OpLabel
91 %3 = OpVariable %9 Function
92 %4 = OpVariable %17 Function
93 %5 = OpVariable %17 Function
94 OpBranch %21
95 %21 = OpLabel
96 %22 = OpPhi %8 %10 %20 %23 %24
97 OpLoopMerge %25 %24 None
98 OpBranch %26
99 %26 = OpLabel
100 %27 = OpSLessThan %12 %22 %11
101 OpBranchConditional %27 %28 %25
102 %28 = OpLabel
103 %29 = OpAccessChain %18 %5 %22
104 %30 = OpLoad %13 %29
105 %31 = OpAccessChain %18 %4 %22
106 OpStore %31 %30
107 %32 = OpAccessChain %18 %4 %22
108 %33 = OpLoad %13 %32
109 %34 = OpAccessChain %18 %5 %22
110 OpStore %34 %33
111 OpBranch %24
112 %24 = OpLabel
113 %23 = OpIAdd %8 %22 %19
114 OpBranch %21
115 %25 = OpLabel
116 OpReturn
117 OpFunctionEnd
118 )";
119
120 const std::string expected = R"(OpCapability Shader
121 %1 = OpExtInstImport "GLSL.std.450"
122 OpMemoryModel Logical GLSL450
123 OpEntryPoint Fragment %2 "main"
124 OpExecutionMode %2 OriginUpperLeft
125 OpSource GLSL 430
126 OpName %2 "main"
127 OpName %3 "i"
128 OpName %4 "A"
129 OpName %5 "B"
130 %6 = OpTypeVoid
131 %7 = OpTypeFunction %6
132 %8 = OpTypeInt 32 1
133 %9 = OpTypePointer Function %8
134 %10 = OpConstant %8 0
135 %11 = OpConstant %8 10
136 %12 = OpTypeBool
137 %13 = OpTypeFloat 32
138 %14 = OpTypeInt 32 0
139 %15 = OpConstant %14 10
140 %16 = OpTypeArray %13 %15
141 %17 = OpTypePointer Function %16
142 %18 = OpTypePointer Function %13
143 %19 = OpConstant %8 1
144 %2 = OpFunction %6 None %7
145 %20 = OpLabel
146 %3 = OpVariable %9 Function
147 %4 = OpVariable %17 Function
148 %5 = OpVariable %17 Function
149 OpBranch %35
150 %35 = OpLabel
151 %36 = OpPhi %8 %10 %20 %47 %46
152 OpLoopMerge %48 %46 None
153 OpBranch %37
154 %37 = OpLabel
155 %38 = OpSLessThan %12 %36 %11
156 OpBranchConditional %38 %39 %48
157 %39 = OpLabel
158 %40 = OpAccessChain %18 %5 %36
159 %41 = OpLoad %13 %40
160 %42 = OpAccessChain %18 %4 %36
161 OpStore %42 %41
162 OpBranch %46
163 %46 = OpLabel
164 %47 = OpIAdd %8 %36 %19
165 OpBranch %35
166 %48 = OpLabel
167 OpBranch %21
168 %21 = OpLabel
169 %22 = OpPhi %8 %10 %48 %23 %24
170 OpLoopMerge %25 %24 None
171 OpBranch %26
172 %26 = OpLabel
173 %27 = OpSLessThan %12 %22 %11
174 OpBranchConditional %27 %28 %25
175 %28 = OpLabel
176 %32 = OpAccessChain %18 %4 %22
177 %33 = OpLoad %13 %32
178 %34 = OpAccessChain %18 %5 %22
179 OpStore %34 %33
180 OpBranch %24
181 %24 = OpLabel
182 %23 = OpIAdd %8 %22 %19
183 OpBranch %21
184 %25 = OpLabel
185 OpReturn
186 OpFunctionEnd
187 )";
188 // clang-format on
189 std::unique_ptr<IRContext> context =
190 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
191 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
192 Module* module = context->module();
193 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
194 << source << std::endl;
195
196 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
197 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
198
199 // Check that the loop will NOT be split when provided with a pass-through
200 // register pressure functor which just returns false.
201 SinglePassRunAndCheck<LoopFissionPass>(
202 source, source, true,
203 [](const RegisterLiveness::RegionRegisterLiveness&) { return false; });
204 }
205
206 /*
207 Generated from the following GLSL
208
209 #version 430
210
211 void main(void) {
212 float A[10];
213 float B[10];
214 for (int i = 0; i < 10; i++) {
215 A[i] = B[i];
216 B[i] = A[i+1];
217 }
218 }
219
220 This loop should not be split, as the i+1 dependence would be broken by
221 splitting the loop.
222 */
223
TEST_F(FissionClassTest,FissionInterdependency)224 TEST_F(FissionClassTest, FissionInterdependency) {
225 // clang-format off
226 // With LocalMultiStoreElimPass
227 const std::string source = R"(OpCapability Shader
228 %1 = OpExtInstImport "GLSL.std.450"
229 OpMemoryModel Logical GLSL450
230 OpEntryPoint Fragment %2 "main"
231 OpExecutionMode %2 OriginUpperLeft
232 OpSource GLSL 430
233 OpName %2 "main"
234 OpName %3 "i"
235 OpName %4 "A"
236 OpName %5 "B"
237 %6 = OpTypeVoid
238 %7 = OpTypeFunction %6
239 %8 = OpTypeInt 32 1
240 %9 = OpTypePointer Function %8
241 %10 = OpConstant %8 0
242 %11 = OpConstant %8 10
243 %12 = OpTypeBool
244 %13 = OpTypeFloat 32
245 %14 = OpTypeInt 32 0
246 %15 = OpConstant %14 10
247 %16 = OpTypeArray %13 %15
248 %17 = OpTypePointer Function %16
249 %18 = OpTypePointer Function %13
250 %19 = OpConstant %8 1
251 %2 = OpFunction %6 None %7
252 %20 = OpLabel
253 %3 = OpVariable %9 Function
254 %4 = OpVariable %17 Function
255 %5 = OpVariable %17 Function
256 OpBranch %21
257 %21 = OpLabel
258 %22 = OpPhi %8 %10 %20 %23 %24
259 OpLoopMerge %25 %24 None
260 OpBranch %26
261 %26 = OpLabel
262 %27 = OpSLessThan %12 %22 %11
263 OpBranchConditional %27 %28 %25
264 %28 = OpLabel
265 %29 = OpAccessChain %18 %5 %22
266 %30 = OpLoad %13 %29
267 %31 = OpAccessChain %18 %4 %22
268 OpStore %31 %30
269 %32 = OpIAdd %8 %22 %19
270 %33 = OpAccessChain %18 %4 %32
271 %34 = OpLoad %13 %33
272 %35 = OpAccessChain %18 %5 %22
273 OpStore %35 %34
274 OpBranch %24
275 %24 = OpLabel
276 %23 = OpIAdd %8 %22 %19
277 OpBranch %21
278 %25 = OpLabel
279 OpReturn
280 OpFunctionEnd
281 )";
282 // clang-format on
283 std::unique_ptr<IRContext> context =
284 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
285 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
286 Module* module = context->module();
287 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
288 << source << std::endl;
289
290 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
291 SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
292 }
293
294 /*
295 Generated from the following GLSL
296
297 #version 430
298
299 void main(void) {
300 float A[10];
301 float B[10];
302 for (int i = 0; i < 10; i++) {
303 A[i] = B[i];
304 B[i+1] = A[i];
305 }
306 }
307
308
309 This should not be split as the load B[i] is dependent on the store B[i+1]
310 */
TEST_F(FissionClassTest,FissionInterdependency2)311 TEST_F(FissionClassTest, FissionInterdependency2) {
312 // clang-format off
313 // With LocalMultiStoreElimPass
314 const std::string source = R"(OpCapability Shader
315 %1 = OpExtInstImport "GLSL.std.450"
316 OpMemoryModel Logical GLSL450
317 OpEntryPoint Fragment %2 "main"
318 OpExecutionMode %2 OriginUpperLeft
319 OpSource GLSL 430
320 OpName %2 "main"
321 OpName %3 "i"
322 OpName %4 "A"
323 OpName %5 "B"
324 %6 = OpTypeVoid
325 %7 = OpTypeFunction %6
326 %8 = OpTypeInt 32 1
327 %9 = OpTypePointer Function %8
328 %10 = OpConstant %8 0
329 %11 = OpConstant %8 10
330 %12 = OpTypeBool
331 %13 = OpTypeFloat 32
332 %14 = OpTypeInt 32 0
333 %15 = OpConstant %14 10
334 %16 = OpTypeArray %13 %15
335 %17 = OpTypePointer Function %16
336 %18 = OpTypePointer Function %13
337 %19 = OpConstant %8 1
338 %2 = OpFunction %6 None %7
339 %20 = OpLabel
340 %3 = OpVariable %9 Function
341 %4 = OpVariable %17 Function
342 %5 = OpVariable %17 Function
343 OpBranch %21
344 %21 = OpLabel
345 %22 = OpPhi %8 %10 %20 %23 %24
346 OpLoopMerge %25 %24 None
347 OpBranch %26
348 %26 = OpLabel
349 %27 = OpSLessThan %12 %22 %11
350 OpBranchConditional %27 %28 %25
351 %28 = OpLabel
352 %29 = OpAccessChain %18 %5 %22
353 %30 = OpLoad %13 %29
354 %31 = OpAccessChain %18 %4 %22
355 OpStore %31 %30
356 %32 = OpIAdd %8 %22 %19
357 %33 = OpAccessChain %18 %4 %22
358 %34 = OpLoad %13 %33
359 %35 = OpAccessChain %18 %5 %32
360 OpStore %35 %34
361 OpBranch %24
362 %24 = OpLabel
363 %23 = OpIAdd %8 %22 %19
364 OpBranch %21
365 %25 = OpLabel
366 OpReturn
367 OpFunctionEnd
368 )";
369 // clang-format on
370 std::unique_ptr<IRContext> context =
371 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
372 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
373 Module* module = context->module();
374 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
375 << source << std::endl;
376
377 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
378 SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
379 }
380
381 /*
382 #version 430
383 void main(void) {
384 float A[10];
385 float B[10];
386 float C[10]
387 float D[10]
388 for (int i = 0; i < 10; i++) {
389 A[i] = B[i];
390 B[i] = A[i];
391 C[i] = D[i];
392 D[i] = C[i];
393 }
394 }
395
396 This should be split into the equivalent of:
397
398 for (int i = 0; i < 10; i++) {
399 A[i] = B[i];
400 B[i] = A[i];
401 }
402 for (int i = 0; i < 10; i++) {
403 C[i] = D[i];
404 D[i] = C[i];
405 }
406
407 We then check that the loop is broken into four for loops like so, if the pass
408 is run twice:
409 for (int i = 0; i < 10; i++)
410 A[i] = B[i];
411 for (int i = 0; i < 10; i++)
412 B[i] = A[i];
413 for (int i = 0; i < 10; i++)
414 C[i] = D[i];
415 for (int i = 0; i < 10; i++)
416 D[i] = C[i];
417
418 */
419
TEST_F(FissionClassTest,FissionMultipleLoadStores)420 TEST_F(FissionClassTest, FissionMultipleLoadStores) {
421 // clang-format off
422 // With LocalMultiStoreElimPass
423 const std::string source = R"(
424 OpCapability Shader
425 %1 = OpExtInstImport "GLSL.std.450"
426 OpMemoryModel Logical GLSL450
427 OpEntryPoint Fragment %2 "main"
428 OpExecutionMode %2 OriginUpperLeft
429 OpSource GLSL 430
430 OpName %2 "main"
431 OpName %3 "i"
432 OpName %4 "A"
433 OpName %5 "B"
434 OpName %6 "C"
435 OpName %7 "D"
436 %8 = OpTypeVoid
437 %9 = OpTypeFunction %8
438 %10 = OpTypeInt 32 1
439 %11 = OpTypePointer Function %10
440 %12 = OpConstant %10 0
441 %13 = OpConstant %10 10
442 %14 = OpTypeBool
443 %15 = OpTypeFloat 32
444 %16 = OpTypeInt 32 0
445 %17 = OpConstant %16 10
446 %18 = OpTypeArray %15 %17
447 %19 = OpTypePointer Function %18
448 %20 = OpTypePointer Function %15
449 %21 = OpConstant %10 1
450 %2 = OpFunction %8 None %9
451 %22 = OpLabel
452 %3 = OpVariable %11 Function
453 %4 = OpVariable %19 Function
454 %5 = OpVariable %19 Function
455 %6 = OpVariable %19 Function
456 %7 = OpVariable %19 Function
457 OpBranch %23
458 %23 = OpLabel
459 %24 = OpPhi %10 %12 %22 %25 %26
460 OpLoopMerge %27 %26 None
461 OpBranch %28
462 %28 = OpLabel
463 %29 = OpSLessThan %14 %24 %13
464 OpBranchConditional %29 %30 %27
465 %30 = OpLabel
466 %31 = OpAccessChain %20 %5 %24
467 %32 = OpLoad %15 %31
468 %33 = OpAccessChain %20 %4 %24
469 OpStore %33 %32
470 %34 = OpAccessChain %20 %4 %24
471 %35 = OpLoad %15 %34
472 %36 = OpAccessChain %20 %5 %24
473 OpStore %36 %35
474 %37 = OpAccessChain %20 %7 %24
475 %38 = OpLoad %15 %37
476 %39 = OpAccessChain %20 %6 %24
477 OpStore %39 %38
478 %40 = OpAccessChain %20 %6 %24
479 %41 = OpLoad %15 %40
480 %42 = OpAccessChain %20 %7 %24
481 OpStore %42 %41
482 OpBranch %26
483 %26 = OpLabel
484 %25 = OpIAdd %10 %24 %21
485 OpBranch %23
486 %27 = OpLabel
487 OpReturn
488 OpFunctionEnd
489 )";
490
491 const std::string expected = R"(OpCapability Shader
492 %1 = OpExtInstImport "GLSL.std.450"
493 OpMemoryModel Logical GLSL450
494 OpEntryPoint Fragment %2 "main"
495 OpExecutionMode %2 OriginUpperLeft
496 OpSource GLSL 430
497 OpName %2 "main"
498 OpName %3 "i"
499 OpName %4 "A"
500 OpName %5 "B"
501 OpName %6 "C"
502 OpName %7 "D"
503 %8 = OpTypeVoid
504 %9 = OpTypeFunction %8
505 %10 = OpTypeInt 32 1
506 %11 = OpTypePointer Function %10
507 %12 = OpConstant %10 0
508 %13 = OpConstant %10 10
509 %14 = OpTypeBool
510 %15 = OpTypeFloat 32
511 %16 = OpTypeInt 32 0
512 %17 = OpConstant %16 10
513 %18 = OpTypeArray %15 %17
514 %19 = OpTypePointer Function %18
515 %20 = OpTypePointer Function %15
516 %21 = OpConstant %10 1
517 %2 = OpFunction %8 None %9
518 %22 = OpLabel
519 %3 = OpVariable %11 Function
520 %4 = OpVariable %19 Function
521 %5 = OpVariable %19 Function
522 %6 = OpVariable %19 Function
523 %7 = OpVariable %19 Function
524 OpBranch %43
525 %43 = OpLabel
526 %44 = OpPhi %10 %12 %22 %61 %60
527 OpLoopMerge %62 %60 None
528 OpBranch %45
529 %45 = OpLabel
530 %46 = OpSLessThan %14 %44 %13
531 OpBranchConditional %46 %47 %62
532 %47 = OpLabel
533 %48 = OpAccessChain %20 %5 %44
534 %49 = OpLoad %15 %48
535 %50 = OpAccessChain %20 %4 %44
536 OpStore %50 %49
537 %51 = OpAccessChain %20 %4 %44
538 %52 = OpLoad %15 %51
539 %53 = OpAccessChain %20 %5 %44
540 OpStore %53 %52
541 OpBranch %60
542 %60 = OpLabel
543 %61 = OpIAdd %10 %44 %21
544 OpBranch %43
545 %62 = OpLabel
546 OpBranch %23
547 %23 = OpLabel
548 %24 = OpPhi %10 %12 %62 %25 %26
549 OpLoopMerge %27 %26 None
550 OpBranch %28
551 %28 = OpLabel
552 %29 = OpSLessThan %14 %24 %13
553 OpBranchConditional %29 %30 %27
554 %30 = OpLabel
555 %37 = OpAccessChain %20 %7 %24
556 %38 = OpLoad %15 %37
557 %39 = OpAccessChain %20 %6 %24
558 OpStore %39 %38
559 %40 = OpAccessChain %20 %6 %24
560 %41 = OpLoad %15 %40
561 %42 = OpAccessChain %20 %7 %24
562 OpStore %42 %41
563 OpBranch %26
564 %26 = OpLabel
565 %25 = OpIAdd %10 %24 %21
566 OpBranch %23
567 %27 = OpLabel
568 OpReturn
569 OpFunctionEnd
570 )";
571
572
573 const std::string expected_multiple_passes = R"(OpCapability Shader
574 %1 = OpExtInstImport "GLSL.std.450"
575 OpMemoryModel Logical GLSL450
576 OpEntryPoint Fragment %2 "main"
577 OpExecutionMode %2 OriginUpperLeft
578 OpSource GLSL 430
579 OpName %2 "main"
580 OpName %3 "i"
581 OpName %4 "A"
582 OpName %5 "B"
583 OpName %6 "C"
584 OpName %7 "D"
585 %8 = OpTypeVoid
586 %9 = OpTypeFunction %8
587 %10 = OpTypeInt 32 1
588 %11 = OpTypePointer Function %10
589 %12 = OpConstant %10 0
590 %13 = OpConstant %10 10
591 %14 = OpTypeBool
592 %15 = OpTypeFloat 32
593 %16 = OpTypeInt 32 0
594 %17 = OpConstant %16 10
595 %18 = OpTypeArray %15 %17
596 %19 = OpTypePointer Function %18
597 %20 = OpTypePointer Function %15
598 %21 = OpConstant %10 1
599 %2 = OpFunction %8 None %9
600 %22 = OpLabel
601 %3 = OpVariable %11 Function
602 %4 = OpVariable %19 Function
603 %5 = OpVariable %19 Function
604 %6 = OpVariable %19 Function
605 %7 = OpVariable %19 Function
606 OpBranch %63
607 %63 = OpLabel
608 %64 = OpPhi %10 %12 %22 %75 %74
609 OpLoopMerge %76 %74 None
610 OpBranch %65
611 %65 = OpLabel
612 %66 = OpSLessThan %14 %64 %13
613 OpBranchConditional %66 %67 %76
614 %67 = OpLabel
615 %68 = OpAccessChain %20 %5 %64
616 %69 = OpLoad %15 %68
617 %70 = OpAccessChain %20 %4 %64
618 OpStore %70 %69
619 OpBranch %74
620 %74 = OpLabel
621 %75 = OpIAdd %10 %64 %21
622 OpBranch %63
623 %76 = OpLabel
624 OpBranch %43
625 %43 = OpLabel
626 %44 = OpPhi %10 %12 %76 %61 %60
627 OpLoopMerge %62 %60 None
628 OpBranch %45
629 %45 = OpLabel
630 %46 = OpSLessThan %14 %44 %13
631 OpBranchConditional %46 %47 %62
632 %47 = OpLabel
633 %51 = OpAccessChain %20 %4 %44
634 %52 = OpLoad %15 %51
635 %53 = OpAccessChain %20 %5 %44
636 OpStore %53 %52
637 OpBranch %60
638 %60 = OpLabel
639 %61 = OpIAdd %10 %44 %21
640 OpBranch %43
641 %62 = OpLabel
642 OpBranch %77
643 %77 = OpLabel
644 %78 = OpPhi %10 %12 %62 %89 %88
645 OpLoopMerge %90 %88 None
646 OpBranch %79
647 %79 = OpLabel
648 %80 = OpSLessThan %14 %78 %13
649 OpBranchConditional %80 %81 %90
650 %81 = OpLabel
651 %82 = OpAccessChain %20 %7 %78
652 %83 = OpLoad %15 %82
653 %84 = OpAccessChain %20 %6 %78
654 OpStore %84 %83
655 OpBranch %88
656 %88 = OpLabel
657 %89 = OpIAdd %10 %78 %21
658 OpBranch %77
659 %90 = OpLabel
660 OpBranch %23
661 %23 = OpLabel
662 %24 = OpPhi %10 %12 %90 %25 %26
663 OpLoopMerge %27 %26 None
664 OpBranch %28
665 %28 = OpLabel
666 %29 = OpSLessThan %14 %24 %13
667 OpBranchConditional %29 %30 %27
668 %30 = OpLabel
669 %40 = OpAccessChain %20 %6 %24
670 %41 = OpLoad %15 %40
671 %42 = OpAccessChain %20 %7 %24
672 OpStore %42 %41
673 OpBranch %26
674 %26 = OpLabel
675 %25 = OpIAdd %10 %24 %21
676 OpBranch %23
677 %27 = OpLabel
678 OpReturn
679 OpFunctionEnd
680 )";
681 // clang-format on
682 std::unique_ptr<IRContext> context =
683 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
684 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
685 Module* module = context->module();
686 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
687 << source << std::endl;
688
689 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
690 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
691
692 // By passing 1 as argument we are using the constructor which makes the
693 // criteria to split the loop be if the registers in the loop exceede 1. By
694 // using this constructor we are also enabling multiple passes (disabled by
695 // default).
696 SinglePassRunAndCheck<LoopFissionPass>(source, expected_multiple_passes, true,
697 1);
698 }
699
700 /*
701 #version 430
702 void main(void) {
703 int accumulator = 0;
704 float X[10];
705 float Y[10];
706
707 for (int i = 0; i < 10; i++) {
708 X[i] = Y[i];
709 Y[i] = X[i];
710 accumulator += i;
711 }
712 }
713
714 This should be split into the equivalent of:
715
716 #version 430
717 void main(void) {
718 int accumulator = 0;
719 float X[10];
720 float Y[10];
721
722 for (int i = 0; i < 10; i++) {
723 X[i] = Y[i];
724 }
725 for (int i = 0; i < 10; i++) {
726 Y[i] = X[i];
727 accumulator += i;
728 }
729 }
730 */
TEST_F(FissionClassTest,FissionWithAccumulator)731 TEST_F(FissionClassTest, FissionWithAccumulator) {
732 // clang-format off
733 // With LocalMultiStoreElimPass
734 const std::string source = R"(OpCapability Shader
735 %1 = OpExtInstImport "GLSL.std.450"
736 OpMemoryModel Logical GLSL450
737 OpEntryPoint Fragment %2 "main"
738 OpExecutionMode %2 OriginUpperLeft
739 OpSource GLSL 430
740 OpName %2 "main"
741 OpName %3 "accumulator"
742 OpName %4 "i"
743 OpName %5 "X"
744 OpName %6 "Y"
745 %7 = OpTypeVoid
746 %8 = OpTypeFunction %7
747 %9 = OpTypeInt 32 1
748 %10 = OpTypePointer Function %9
749 %11 = OpConstant %9 0
750 %12 = OpConstant %9 10
751 %13 = OpTypeBool
752 %14 = OpTypeFloat 32
753 %15 = OpTypeInt 32 0
754 %16 = OpConstant %15 10
755 %17 = OpTypeArray %14 %16
756 %18 = OpTypePointer Function %17
757 %19 = OpTypePointer Function %14
758 %20 = OpConstant %9 1
759 %2 = OpFunction %7 None %8
760 %21 = OpLabel
761 %3 = OpVariable %10 Function
762 %4 = OpVariable %10 Function
763 %5 = OpVariable %18 Function
764 %6 = OpVariable %18 Function
765 OpBranch %22
766 %22 = OpLabel
767 %23 = OpPhi %9 %11 %21 %24 %25
768 %26 = OpPhi %9 %11 %21 %27 %25
769 OpLoopMerge %28 %25 None
770 OpBranch %29
771 %29 = OpLabel
772 %30 = OpSLessThan %13 %26 %12
773 OpBranchConditional %30 %31 %28
774 %31 = OpLabel
775 %32 = OpAccessChain %19 %6 %26
776 %33 = OpLoad %14 %32
777 %34 = OpAccessChain %19 %5 %26
778 OpStore %34 %33
779 %35 = OpAccessChain %19 %5 %26
780 %36 = OpLoad %14 %35
781 %37 = OpAccessChain %19 %6 %26
782 OpStore %37 %36
783 %24 = OpIAdd %9 %23 %26
784 OpBranch %25
785 %25 = OpLabel
786 %27 = OpIAdd %9 %26 %20
787 OpBranch %22
788 %28 = OpLabel
789 OpReturn
790 OpFunctionEnd
791 )";
792
793 const std::string expected = R"(OpCapability Shader
794 %1 = OpExtInstImport "GLSL.std.450"
795 OpMemoryModel Logical GLSL450
796 OpEntryPoint Fragment %2 "main"
797 OpExecutionMode %2 OriginUpperLeft
798 OpSource GLSL 430
799 OpName %2 "main"
800 OpName %3 "accumulator"
801 OpName %4 "i"
802 OpName %5 "X"
803 OpName %6 "Y"
804 %7 = OpTypeVoid
805 %8 = OpTypeFunction %7
806 %9 = OpTypeInt 32 1
807 %10 = OpTypePointer Function %9
808 %11 = OpConstant %9 0
809 %12 = OpConstant %9 10
810 %13 = OpTypeBool
811 %14 = OpTypeFloat 32
812 %15 = OpTypeInt 32 0
813 %16 = OpConstant %15 10
814 %17 = OpTypeArray %14 %16
815 %18 = OpTypePointer Function %17
816 %19 = OpTypePointer Function %14
817 %20 = OpConstant %9 1
818 %2 = OpFunction %7 None %8
819 %21 = OpLabel
820 %3 = OpVariable %10 Function
821 %4 = OpVariable %10 Function
822 %5 = OpVariable %18 Function
823 %6 = OpVariable %18 Function
824 OpBranch %38
825 %38 = OpLabel
826 %40 = OpPhi %9 %11 %21 %52 %51
827 OpLoopMerge %53 %51 None
828 OpBranch %41
829 %41 = OpLabel
830 %42 = OpSLessThan %13 %40 %12
831 OpBranchConditional %42 %43 %53
832 %43 = OpLabel
833 %44 = OpAccessChain %19 %6 %40
834 %45 = OpLoad %14 %44
835 %46 = OpAccessChain %19 %5 %40
836 OpStore %46 %45
837 OpBranch %51
838 %51 = OpLabel
839 %52 = OpIAdd %9 %40 %20
840 OpBranch %38
841 %53 = OpLabel
842 OpBranch %22
843 %22 = OpLabel
844 %23 = OpPhi %9 %11 %53 %24 %25
845 %26 = OpPhi %9 %11 %53 %27 %25
846 OpLoopMerge %28 %25 None
847 OpBranch %29
848 %29 = OpLabel
849 %30 = OpSLessThan %13 %26 %12
850 OpBranchConditional %30 %31 %28
851 %31 = OpLabel
852 %35 = OpAccessChain %19 %5 %26
853 %36 = OpLoad %14 %35
854 %37 = OpAccessChain %19 %6 %26
855 OpStore %37 %36
856 %24 = OpIAdd %9 %23 %26
857 OpBranch %25
858 %25 = OpLabel
859 %27 = OpIAdd %9 %26 %20
860 OpBranch %22
861 %28 = OpLabel
862 OpReturn
863 OpFunctionEnd
864 )";
865 // clang-format on
866 std::unique_ptr<IRContext> context =
867 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
868 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
869 Module* module = context->module();
870 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
871 << source << std::endl;
872
873 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
874 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
875 }
876
877 /*
878 Generated from the following glsl:
879
880 #version 430
881 layout(location=0) out float x;
882 layout(location=1) out float y;
883
884 void main(void) {
885 float accumulator_1 = 0;
886 float accumulator_2 = 0;
887 for (int i = 0; i < 10; i++) {
888 accumulator_1 += i;
889 accumulator_2 += i;
890 }
891
892 x = accumulator_1;
893 y = accumulator_2;
894 }
895
896 Should be split into equivalent of:
897
898 void main(void) {
899 float accumulator_1 = 0;
900 float accumulator_2 = 0;
901 for (int i = 0; i < 10; i++) {
902 accumulator_1 += i;
903 }
904
905 for (int i = 0; i < 10; i++) {
906 accumulator_2 += i;
907 }
908 x = accumulator_1;
909 y = accumulator_2;
910 }
911
912 */
TEST_F(FissionClassTest,FissionWithPhisUsedOutwithLoop)913 TEST_F(FissionClassTest, FissionWithPhisUsedOutwithLoop) {
914 // clang-format off
915 // With LocalMultiStoreElimPass
916 const std::string source = R"(OpCapability Shader
917 %1 = OpExtInstImport "GLSL.std.450"
918 OpMemoryModel Logical GLSL450
919 OpEntryPoint Fragment %2 "main" %3 %4
920 OpExecutionMode %2 OriginUpperLeft
921 OpSource GLSL 430
922 OpName %2 "main"
923 OpName %5 "accumulator_1"
924 OpName %6 "accumulator_2"
925 OpName %7 "i"
926 OpName %3 "x"
927 OpName %4 "y"
928 OpDecorate %3 Location 0
929 OpDecorate %4 Location 1
930 %8 = OpTypeVoid
931 %9 = OpTypeFunction %8
932 %10 = OpTypeFloat 32
933 %11 = OpTypePointer Function %10
934 %12 = OpConstant %10 0
935 %13 = OpTypeInt 32 1
936 %14 = OpTypePointer Function %13
937 %15 = OpConstant %13 0
938 %16 = OpConstant %13 10
939 %17 = OpTypeBool
940 %18 = OpConstant %13 1
941 %19 = OpTypePointer Output %10
942 %3 = OpVariable %19 Output
943 %4 = OpVariable %19 Output
944 %2 = OpFunction %8 None %9
945 %20 = OpLabel
946 %5 = OpVariable %11 Function
947 %6 = OpVariable %11 Function
948 %7 = OpVariable %14 Function
949 OpBranch %21
950 %21 = OpLabel
951 %22 = OpPhi %10 %12 %20 %23 %24
952 %25 = OpPhi %10 %12 %20 %26 %24
953 %27 = OpPhi %13 %15 %20 %28 %24
954 OpLoopMerge %29 %24 None
955 OpBranch %30
956 %30 = OpLabel
957 %31 = OpSLessThan %17 %27 %16
958 OpBranchConditional %31 %32 %29
959 %32 = OpLabel
960 %33 = OpConvertSToF %10 %27
961 %26 = OpFAdd %10 %25 %33
962 %34 = OpConvertSToF %10 %27
963 %23 = OpFAdd %10 %22 %34
964 OpBranch %24
965 %24 = OpLabel
966 %28 = OpIAdd %13 %27 %18
967 OpStore %7 %28
968 OpBranch %21
969 %29 = OpLabel
970 OpStore %3 %25
971 OpStore %4 %22
972 OpReturn
973 OpFunctionEnd
974 )";
975
976 const std::string expected = R"(OpCapability Shader
977 %1 = OpExtInstImport "GLSL.std.450"
978 OpMemoryModel Logical GLSL450
979 OpEntryPoint Fragment %2 "main" %3 %4
980 OpExecutionMode %2 OriginUpperLeft
981 OpSource GLSL 430
982 OpName %2 "main"
983 OpName %5 "accumulator_1"
984 OpName %6 "accumulator_2"
985 OpName %7 "i"
986 OpName %3 "x"
987 OpName %4 "y"
988 OpDecorate %3 Location 0
989 OpDecorate %4 Location 1
990 %8 = OpTypeVoid
991 %9 = OpTypeFunction %8
992 %10 = OpTypeFloat 32
993 %11 = OpTypePointer Function %10
994 %12 = OpConstant %10 0
995 %13 = OpTypeInt 32 1
996 %14 = OpTypePointer Function %13
997 %15 = OpConstant %13 0
998 %16 = OpConstant %13 10
999 %17 = OpTypeBool
1000 %18 = OpConstant %13 1
1001 %19 = OpTypePointer Output %10
1002 %3 = OpVariable %19 Output
1003 %4 = OpVariable %19 Output
1004 %2 = OpFunction %8 None %9
1005 %20 = OpLabel
1006 %5 = OpVariable %11 Function
1007 %6 = OpVariable %11 Function
1008 %7 = OpVariable %14 Function
1009 OpBranch %35
1010 %35 = OpLabel
1011 %37 = OpPhi %10 %12 %20 %43 %46
1012 %38 = OpPhi %13 %15 %20 %47 %46
1013 OpLoopMerge %48 %46 None
1014 OpBranch %39
1015 %39 = OpLabel
1016 %40 = OpSLessThan %17 %38 %16
1017 OpBranchConditional %40 %41 %48
1018 %41 = OpLabel
1019 %42 = OpConvertSToF %10 %38
1020 %43 = OpFAdd %10 %37 %42
1021 OpBranch %46
1022 %46 = OpLabel
1023 %47 = OpIAdd %13 %38 %18
1024 OpStore %7 %47
1025 OpBranch %35
1026 %48 = OpLabel
1027 OpBranch %21
1028 %21 = OpLabel
1029 %22 = OpPhi %10 %12 %48 %23 %24
1030 %27 = OpPhi %13 %15 %48 %28 %24
1031 OpLoopMerge %29 %24 None
1032 OpBranch %30
1033 %30 = OpLabel
1034 %31 = OpSLessThan %17 %27 %16
1035 OpBranchConditional %31 %32 %29
1036 %32 = OpLabel
1037 %34 = OpConvertSToF %10 %27
1038 %23 = OpFAdd %10 %22 %34
1039 OpBranch %24
1040 %24 = OpLabel
1041 %28 = OpIAdd %13 %27 %18
1042 OpStore %7 %28
1043 OpBranch %21
1044 %29 = OpLabel
1045 OpStore %3 %37
1046 OpStore %4 %22
1047 OpReturn
1048 OpFunctionEnd
1049 )";
1050
1051 // clang-format on
1052 std::unique_ptr<IRContext> context =
1053 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
1054 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1055 Module* module = context->module();
1056 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1057 << source << std::endl;
1058
1059 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1060 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
1061 }
1062
1063 /*
1064 #version 430
1065 void main(void) {
1066 float A[10][10];
1067 float B[10][10];
1068 for (int i = 0; i < 10; i++) {
1069 for (int j = 0; j < 10; j++) {
1070 A[i][j] = B[i][j];
1071 B[i][j] = A[i][j];
1072 }
1073 }
1074 }
1075
1076 Should be split into equivalent of:
1077
1078 #version 430
1079 void main(void) {
1080 float A[10][10];
1081 float B[10][10];
1082 for (int i = 0; i < 10; i++) {
1083 for (int j = 0; j < 10; j++) {
1084 A[i][j] = B[i][j];
1085 }
1086 for (int j = 0; j < 10; j++) {
1087 B[i][j] = A[i][j];
1088 }
1089 }
1090 }
1091
1092
1093 */
TEST_F(FissionClassTest,FissionNested)1094 TEST_F(FissionClassTest, FissionNested) {
1095 // clang-format off
1096 // With LocalMultiStoreElimPass
1097 const std::string source = R"(
1098 OpCapability Shader
1099 %1 = OpExtInstImport "GLSL.std.450"
1100 OpMemoryModel Logical GLSL450
1101 OpEntryPoint Fragment %2 "main"
1102 OpExecutionMode %2 OriginUpperLeft
1103 OpSource GLSL 430
1104 OpName %2 "main"
1105 OpName %3 "i"
1106 OpName %4 "j"
1107 OpName %5 "A"
1108 OpName %6 "B"
1109 %7 = OpTypeVoid
1110 %8 = OpTypeFunction %7
1111 %9 = OpTypeInt 32 1
1112 %10 = OpTypePointer Function %9
1113 %11 = OpConstant %9 0
1114 %12 = OpConstant %9 10
1115 %13 = OpTypeBool
1116 %14 = OpTypeFloat 32
1117 %15 = OpTypeInt 32 0
1118 %16 = OpConstant %15 10
1119 %17 = OpTypeArray %14 %16
1120 %18 = OpTypeArray %17 %16
1121 %19 = OpTypePointer Function %18
1122 %20 = OpTypePointer Function %14
1123 %21 = OpConstant %9 1
1124 %2 = OpFunction %7 None %8
1125 %22 = OpLabel
1126 %3 = OpVariable %10 Function
1127 %4 = OpVariable %10 Function
1128 %5 = OpVariable %19 Function
1129 %6 = OpVariable %19 Function
1130 OpStore %3 %11
1131 OpBranch %23
1132 %23 = OpLabel
1133 %24 = OpPhi %9 %11 %22 %25 %26
1134 OpLoopMerge %27 %26 None
1135 OpBranch %28
1136 %28 = OpLabel
1137 %29 = OpSLessThan %13 %24 %12
1138 OpBranchConditional %29 %30 %27
1139 %30 = OpLabel
1140 OpStore %4 %11
1141 OpBranch %31
1142 %31 = OpLabel
1143 %32 = OpPhi %9 %11 %30 %33 %34
1144 OpLoopMerge %35 %34 None
1145 OpBranch %36
1146 %36 = OpLabel
1147 %37 = OpSLessThan %13 %32 %12
1148 OpBranchConditional %37 %38 %35
1149 %38 = OpLabel
1150 %39 = OpAccessChain %20 %6 %24 %32
1151 %40 = OpLoad %14 %39
1152 %41 = OpAccessChain %20 %5 %24 %32
1153 OpStore %41 %40
1154 %42 = OpAccessChain %20 %5 %24 %32
1155 %43 = OpLoad %14 %42
1156 %44 = OpAccessChain %20 %6 %24 %32
1157 OpStore %44 %43
1158 OpBranch %34
1159 %34 = OpLabel
1160 %33 = OpIAdd %9 %32 %21
1161 OpStore %4 %33
1162 OpBranch %31
1163 %35 = OpLabel
1164 OpBranch %26
1165 %26 = OpLabel
1166 %25 = OpIAdd %9 %24 %21
1167 OpStore %3 %25
1168 OpBranch %23
1169 %27 = OpLabel
1170 OpReturn
1171 OpFunctionEnd
1172 )";
1173
1174 const std::string expected = R"(OpCapability Shader
1175 %1 = OpExtInstImport "GLSL.std.450"
1176 OpMemoryModel Logical GLSL450
1177 OpEntryPoint Fragment %2 "main"
1178 OpExecutionMode %2 OriginUpperLeft
1179 OpSource GLSL 430
1180 OpName %2 "main"
1181 OpName %3 "i"
1182 OpName %4 "j"
1183 OpName %5 "A"
1184 OpName %6 "B"
1185 %7 = OpTypeVoid
1186 %8 = OpTypeFunction %7
1187 %9 = OpTypeInt 32 1
1188 %10 = OpTypePointer Function %9
1189 %11 = OpConstant %9 0
1190 %12 = OpConstant %9 10
1191 %13 = OpTypeBool
1192 %14 = OpTypeFloat 32
1193 %15 = OpTypeInt 32 0
1194 %16 = OpConstant %15 10
1195 %17 = OpTypeArray %14 %16
1196 %18 = OpTypeArray %17 %16
1197 %19 = OpTypePointer Function %18
1198 %20 = OpTypePointer Function %14
1199 %21 = OpConstant %9 1
1200 %2 = OpFunction %7 None %8
1201 %22 = OpLabel
1202 %3 = OpVariable %10 Function
1203 %4 = OpVariable %10 Function
1204 %5 = OpVariable %19 Function
1205 %6 = OpVariable %19 Function
1206 OpStore %3 %11
1207 OpBranch %23
1208 %23 = OpLabel
1209 %24 = OpPhi %9 %11 %22 %25 %26
1210 OpLoopMerge %27 %26 None
1211 OpBranch %28
1212 %28 = OpLabel
1213 %29 = OpSLessThan %13 %24 %12
1214 OpBranchConditional %29 %30 %27
1215 %30 = OpLabel
1216 OpStore %4 %11
1217 OpBranch %45
1218 %45 = OpLabel
1219 %46 = OpPhi %9 %11 %30 %57 %56
1220 OpLoopMerge %58 %56 None
1221 OpBranch %47
1222 %47 = OpLabel
1223 %48 = OpSLessThan %13 %46 %12
1224 OpBranchConditional %48 %49 %58
1225 %49 = OpLabel
1226 %50 = OpAccessChain %20 %6 %24 %46
1227 %51 = OpLoad %14 %50
1228 %52 = OpAccessChain %20 %5 %24 %46
1229 OpStore %52 %51
1230 OpBranch %56
1231 %56 = OpLabel
1232 %57 = OpIAdd %9 %46 %21
1233 OpStore %4 %57
1234 OpBranch %45
1235 %58 = OpLabel
1236 OpBranch %31
1237 %31 = OpLabel
1238 %32 = OpPhi %9 %11 %58 %33 %34
1239 OpLoopMerge %35 %34 None
1240 OpBranch %36
1241 %36 = OpLabel
1242 %37 = OpSLessThan %13 %32 %12
1243 OpBranchConditional %37 %38 %35
1244 %38 = OpLabel
1245 %42 = OpAccessChain %20 %5 %24 %32
1246 %43 = OpLoad %14 %42
1247 %44 = OpAccessChain %20 %6 %24 %32
1248 OpStore %44 %43
1249 OpBranch %34
1250 %34 = OpLabel
1251 %33 = OpIAdd %9 %32 %21
1252 OpStore %4 %33
1253 OpBranch %31
1254 %35 = OpLabel
1255 OpBranch %26
1256 %26 = OpLabel
1257 %25 = OpIAdd %9 %24 %21
1258 OpStore %3 %25
1259 OpBranch %23
1260 %27 = OpLabel
1261 OpReturn
1262 OpFunctionEnd
1263 )";
1264
1265 // clang-format on
1266 std::unique_ptr<IRContext> context =
1267 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
1268 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1269 Module* module = context->module();
1270 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1271 << source << std::endl;
1272
1273 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1274 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
1275 }
1276
1277 /*
1278 #version 430
1279 void main(void) {
1280 int accumulator = 0;
1281 float A[10];
1282 float B[10];
1283 float C[10];
1284
1285 for (int i = 0; i < 10; i++) {
1286 int c = C[i];
1287 A[i] = B[i];
1288 B[i] = A[i] + c;
1289 }
1290 }
1291
1292 This loop should not be split as we would have to break the order of the loads
1293 to do so. It would be grouped into two sets:
1294
1295 1
1296 int c = C[i];
1297 B[i] = A[i] + c;
1298
1299 2
1300 A[i] = B[i];
1301
1302 To keep the load C[i] in the same order we would need to put B[i] ahead of that
1303 */
TEST_F(FissionClassTest,FissionLoad)1304 TEST_F(FissionClassTest, FissionLoad) {
1305 // clang-format off
1306 // With LocalMultiStoreElimPass
1307 const std::string source = R"(OpCapability Shader
1308 %1 = OpExtInstImport "GLSL.std.450"
1309 OpMemoryModel Logical GLSL450
1310 OpEntryPoint Fragment %2 "main"
1311 OpExecutionMode %2 OriginUpperLeft
1312 OpSource GLSL 430
1313 OpName %2 "main"
1314 OpName %3 "i"
1315 OpName %4 "c"
1316 OpName %5 "C"
1317 OpName %6 "A"
1318 OpName %7 "B"
1319 %8 = OpTypeVoid
1320 %9 = OpTypeFunction %8
1321 %10 = OpTypeInt 32 1
1322 %11 = OpTypePointer Function %10
1323 %12 = OpConstant %10 0
1324 %13 = OpConstant %10 10
1325 %14 = OpTypeBool
1326 %15 = OpTypeFloat 32
1327 %16 = OpTypePointer Function %15
1328 %17 = OpTypeInt 32 0
1329 %18 = OpConstant %17 10
1330 %19 = OpTypeArray %15 %18
1331 %20 = OpTypePointer Function %19
1332 %21 = OpConstant %10 1
1333 %2 = OpFunction %8 None %9
1334 %22 = OpLabel
1335 %3 = OpVariable %11 Function
1336 %4 = OpVariable %16 Function
1337 %5 = OpVariable %20 Function
1338 %6 = OpVariable %20 Function
1339 %7 = OpVariable %20 Function
1340 OpBranch %23
1341 %23 = OpLabel
1342 %24 = OpPhi %10 %12 %22 %25 %26
1343 OpLoopMerge %27 %26 None
1344 OpBranch %28
1345 %28 = OpLabel
1346 %29 = OpSLessThan %14 %24 %13
1347 OpBranchConditional %29 %30 %27
1348 %30 = OpLabel
1349 %31 = OpAccessChain %16 %5 %24
1350 %32 = OpLoad %15 %31
1351 OpStore %4 %32
1352 %33 = OpAccessChain %16 %7 %24
1353 %34 = OpLoad %15 %33
1354 %35 = OpAccessChain %16 %6 %24
1355 OpStore %35 %34
1356 %36 = OpAccessChain %16 %6 %24
1357 %37 = OpLoad %15 %36
1358 %38 = OpFAdd %15 %37 %32
1359 %39 = OpAccessChain %16 %7 %24
1360 OpStore %39 %38
1361 OpBranch %26
1362 %26 = OpLabel
1363 %25 = OpIAdd %10 %24 %21
1364 OpBranch %23
1365 %27 = OpLabel
1366 OpReturn
1367 OpFunctionEnd
1368 )";
1369 // clang-format on
1370 std::unique_ptr<IRContext> context =
1371 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
1372 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1373 Module* module = context->module();
1374 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1375 << source << std::endl;
1376
1377 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1378 SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
1379 }
1380
1381 /*
1382 #version 430
1383 layout(location=0) flat in int condition;
1384 void main(void) {
1385 float A[10];
1386 float B[10];
1387
1388 for (int i = 0; i < 10; i++) {
1389 if (condition == 1)
1390 A[i] = B[i];
1391 else
1392 B[i] = A[i];
1393 }
1394 }
1395
1396
1397 When this is split we leave the condition check and control flow inplace and
1398 leave its removal for dead code elimination.
1399
1400 #version 430
1401 layout(location=0) flat in int condition;
1402 void main(void) {
1403 float A[10];
1404 float B[10];
1405
1406 for (int i = 0; i < 10; i++) {
1407 if (condition == 1)
1408 A[i] = B[i];
1409 else
1410 ;
1411 }
1412 for (int i = 0; i < 10; i++) {
1413 if (condition == 1)
1414 ;
1415 else
1416 B[i] = A[i];
1417 }
1418 }
1419
1420
1421 */
TEST_F(FissionClassTest,FissionControlFlow)1422 TEST_F(FissionClassTest, FissionControlFlow) {
1423 // clang-format off
1424 // With LocalMultiStoreElimPass
1425 const std::string source = R"(
1426 OpCapability Shader
1427 %1 = OpExtInstImport "GLSL.std.450"
1428 OpMemoryModel Logical GLSL450
1429 OpEntryPoint Fragment %2 "main" %3
1430 OpExecutionMode %2 OriginUpperLeft
1431 OpSource GLSL 430
1432 OpName %2 "main"
1433 OpName %4 "i"
1434 OpName %3 "condition"
1435 OpName %5 "A"
1436 OpName %6 "B"
1437 OpDecorate %3 Flat
1438 OpDecorate %3 Location 0
1439 %7 = OpTypeVoid
1440 %8 = OpTypeFunction %7
1441 %9 = OpTypeInt 32 1
1442 %10 = OpTypePointer Function %9
1443 %11 = OpConstant %9 0
1444 %12 = OpConstant %9 10
1445 %13 = OpTypeBool
1446 %14 = OpTypePointer Input %9
1447 %3 = OpVariable %14 Input
1448 %15 = OpConstant %9 1
1449 %16 = OpTypeFloat 32
1450 %17 = OpTypeInt 32 0
1451 %18 = OpConstant %17 10
1452 %19 = OpTypeArray %16 %18
1453 %20 = OpTypePointer Function %19
1454 %21 = OpTypePointer Function %16
1455 %2 = OpFunction %7 None %8
1456 %22 = OpLabel
1457 %4 = OpVariable %10 Function
1458 %5 = OpVariable %20 Function
1459 %6 = OpVariable %20 Function
1460 %31 = OpLoad %9 %3
1461 OpStore %4 %11
1462 OpBranch %23
1463 %23 = OpLabel
1464 %24 = OpPhi %9 %11 %22 %25 %26
1465 OpLoopMerge %27 %26 None
1466 OpBranch %28
1467 %28 = OpLabel
1468 %29 = OpSLessThan %13 %24 %12
1469 OpBranchConditional %29 %30 %27
1470 %30 = OpLabel
1471 %32 = OpIEqual %13 %31 %15
1472 OpSelectionMerge %33 None
1473 OpBranchConditional %32 %34 %35
1474 %34 = OpLabel
1475 %36 = OpAccessChain %21 %6 %24
1476 %37 = OpLoad %16 %36
1477 %38 = OpAccessChain %21 %5 %24
1478 OpStore %38 %37
1479 OpBranch %33
1480 %35 = OpLabel
1481 %39 = OpAccessChain %21 %5 %24
1482 %40 = OpLoad %16 %39
1483 %41 = OpAccessChain %21 %6 %24
1484 OpStore %41 %40
1485 OpBranch %33
1486 %33 = OpLabel
1487 OpBranch %26
1488 %26 = OpLabel
1489 %25 = OpIAdd %9 %24 %15
1490 OpStore %4 %25
1491 OpBranch %23
1492 %27 = OpLabel
1493 OpReturn
1494 OpFunctionEnd
1495 )";
1496
1497 const std::string expected = R"(OpCapability Shader
1498 %1 = OpExtInstImport "GLSL.std.450"
1499 OpMemoryModel Logical GLSL450
1500 OpEntryPoint Fragment %2 "main" %3
1501 OpExecutionMode %2 OriginUpperLeft
1502 OpSource GLSL 430
1503 OpName %2 "main"
1504 OpName %4 "i"
1505 OpName %3 "condition"
1506 OpName %5 "A"
1507 OpName %6 "B"
1508 OpDecorate %3 Flat
1509 OpDecorate %3 Location 0
1510 %7 = OpTypeVoid
1511 %8 = OpTypeFunction %7
1512 %9 = OpTypeInt 32 1
1513 %10 = OpTypePointer Function %9
1514 %11 = OpConstant %9 0
1515 %12 = OpConstant %9 10
1516 %13 = OpTypeBool
1517 %14 = OpTypePointer Input %9
1518 %3 = OpVariable %14 Input
1519 %15 = OpConstant %9 1
1520 %16 = OpTypeFloat 32
1521 %17 = OpTypeInt 32 0
1522 %18 = OpConstant %17 10
1523 %19 = OpTypeArray %16 %18
1524 %20 = OpTypePointer Function %19
1525 %21 = OpTypePointer Function %16
1526 %2 = OpFunction %7 None %8
1527 %22 = OpLabel
1528 %4 = OpVariable %10 Function
1529 %5 = OpVariable %20 Function
1530 %6 = OpVariable %20 Function
1531 %23 = OpLoad %9 %3
1532 OpStore %4 %11
1533 OpBranch %42
1534 %42 = OpLabel
1535 %43 = OpPhi %9 %11 %22 %58 %57
1536 OpLoopMerge %59 %57 None
1537 OpBranch %44
1538 %44 = OpLabel
1539 %45 = OpSLessThan %13 %43 %12
1540 OpBranchConditional %45 %46 %59
1541 %46 = OpLabel
1542 %47 = OpIEqual %13 %23 %15
1543 OpSelectionMerge %56 None
1544 OpBranchConditional %47 %52 %48
1545 %48 = OpLabel
1546 OpBranch %56
1547 %52 = OpLabel
1548 %53 = OpAccessChain %21 %6 %43
1549 %54 = OpLoad %16 %53
1550 %55 = OpAccessChain %21 %5 %43
1551 OpStore %55 %54
1552 OpBranch %56
1553 %56 = OpLabel
1554 OpBranch %57
1555 %57 = OpLabel
1556 %58 = OpIAdd %9 %43 %15
1557 OpStore %4 %58
1558 OpBranch %42
1559 %59 = OpLabel
1560 OpBranch %24
1561 %24 = OpLabel
1562 %25 = OpPhi %9 %11 %59 %26 %27
1563 OpLoopMerge %28 %27 None
1564 OpBranch %29
1565 %29 = OpLabel
1566 %30 = OpSLessThan %13 %25 %12
1567 OpBranchConditional %30 %31 %28
1568 %31 = OpLabel
1569 %32 = OpIEqual %13 %23 %15
1570 OpSelectionMerge %33 None
1571 OpBranchConditional %32 %34 %35
1572 %34 = OpLabel
1573 OpBranch %33
1574 %35 = OpLabel
1575 %39 = OpAccessChain %21 %5 %25
1576 %40 = OpLoad %16 %39
1577 %41 = OpAccessChain %21 %6 %25
1578 OpStore %41 %40
1579 OpBranch %33
1580 %33 = OpLabel
1581 OpBranch %27
1582 %27 = OpLabel
1583 %26 = OpIAdd %9 %25 %15
1584 OpStore %4 %26
1585 OpBranch %24
1586 %28 = OpLabel
1587 OpReturn
1588 OpFunctionEnd
1589 )";
1590
1591 // clang-format on
1592 std::unique_ptr<IRContext> context =
1593 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
1594 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1595 Module* module = context->module();
1596 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1597 << source << std::endl;
1598
1599 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1600 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
1601 }
1602
1603 /*
1604 #version 430
1605 void main(void) {
1606 float A[10];
1607 float B[10];
1608 for (int i = 0; i < 10; i++) {
1609 if (i == 1)
1610 B[i] = A[i];
1611 else if (i == 2)
1612 A[i] = B[i];
1613 else
1614 A[i] = 0;
1615 }
1616 }
1617
1618 After running the pass with multiple splits enabled (via register threshold of
1619 1) we expect the equivalent of:
1620
1621 #version 430
1622 void main(void) {
1623 float A[10];
1624 float B[10];
1625 for (int i = 0; i < 10; i++) {
1626 if (i == 1)
1627 B[i] = A[i];
1628 else if (i == 2)
1629 else
1630 }
1631 for (int i = 0; i < 10; i++) {
1632 if (i == 1)
1633 else if (i == 2)
1634 A[i] = B[i];
1635 else
1636 }
1637 for (int i = 0; i < 10; i++) {
1638 if (i == 1)
1639 else if (i == 2)
1640 else
1641 A[i] = 0;
1642 }
1643
1644 }
1645
1646 */
TEST_F(FissionClassTest,FissionControlFlow2)1647 TEST_F(FissionClassTest, FissionControlFlow2) {
1648 // clang-format off
1649 // With LocalMultiStoreElimPass
1650 const std::string source = R"(OpCapability Shader
1651 %1 = OpExtInstImport "GLSL.std.450"
1652 OpMemoryModel Logical GLSL450
1653 OpEntryPoint Fragment %2 "main"
1654 OpExecutionMode %2 OriginUpperLeft
1655 OpSource GLSL 430
1656 OpName %2 "main"
1657 OpName %3 "i"
1658 OpName %4 "B"
1659 OpName %5 "A"
1660 %6 = OpTypeVoid
1661 %7 = OpTypeFunction %6
1662 %8 = OpTypeInt 32 1
1663 %9 = OpTypePointer Function %8
1664 %10 = OpConstant %8 0
1665 %11 = OpConstant %8 10
1666 %12 = OpTypeBool
1667 %13 = OpConstant %8 1
1668 %14 = OpTypeFloat 32
1669 %15 = OpTypeInt 32 0
1670 %16 = OpConstant %15 10
1671 %17 = OpTypeArray %14 %16
1672 %18 = OpTypePointer Function %17
1673 %19 = OpTypePointer Function %14
1674 %20 = OpConstant %8 2
1675 %21 = OpConstant %14 0
1676 %2 = OpFunction %6 None %7
1677 %22 = OpLabel
1678 %3 = OpVariable %9 Function
1679 %4 = OpVariable %18 Function
1680 %5 = OpVariable %18 Function
1681 OpStore %3 %10
1682 OpBranch %23
1683 %23 = OpLabel
1684 %24 = OpPhi %8 %10 %22 %25 %26
1685 OpLoopMerge %27 %26 None
1686 OpBranch %28
1687 %28 = OpLabel
1688 %29 = OpSLessThan %12 %24 %11
1689 OpBranchConditional %29 %30 %27
1690 %30 = OpLabel
1691 %31 = OpIEqual %12 %24 %13
1692 OpSelectionMerge %32 None
1693 OpBranchConditional %31 %33 %34
1694 %33 = OpLabel
1695 %35 = OpAccessChain %19 %5 %24
1696 %36 = OpLoad %14 %35
1697 %37 = OpAccessChain %19 %4 %24
1698 OpStore %37 %36
1699 OpBranch %32
1700 %34 = OpLabel
1701 %38 = OpIEqual %12 %24 %20
1702 OpSelectionMerge %39 None
1703 OpBranchConditional %38 %40 %41
1704 %40 = OpLabel
1705 %42 = OpAccessChain %19 %4 %24
1706 %43 = OpLoad %14 %42
1707 %44 = OpAccessChain %19 %5 %24
1708 OpStore %44 %43
1709 OpBranch %39
1710 %41 = OpLabel
1711 %45 = OpAccessChain %19 %5 %24
1712 OpStore %45 %21
1713 OpBranch %39
1714 %39 = OpLabel
1715 OpBranch %32
1716 %32 = OpLabel
1717 OpBranch %26
1718 %26 = OpLabel
1719 %25 = OpIAdd %8 %24 %13
1720 OpStore %3 %25
1721 OpBranch %23
1722 %27 = OpLabel
1723 OpReturn
1724 OpFunctionEnd
1725 )";
1726
1727 const std::string expected = R"(OpCapability Shader
1728 %1 = OpExtInstImport "GLSL.std.450"
1729 OpMemoryModel Logical GLSL450
1730 OpEntryPoint Fragment %2 "main"
1731 OpExecutionMode %2 OriginUpperLeft
1732 OpSource GLSL 430
1733 OpName %2 "main"
1734 OpName %3 "i"
1735 OpName %4 "B"
1736 OpName %5 "A"
1737 %6 = OpTypeVoid
1738 %7 = OpTypeFunction %6
1739 %8 = OpTypeInt 32 1
1740 %9 = OpTypePointer Function %8
1741 %10 = OpConstant %8 0
1742 %11 = OpConstant %8 10
1743 %12 = OpTypeBool
1744 %13 = OpConstant %8 1
1745 %14 = OpTypeFloat 32
1746 %15 = OpTypeInt 32 0
1747 %16 = OpConstant %15 10
1748 %17 = OpTypeArray %14 %16
1749 %18 = OpTypePointer Function %17
1750 %19 = OpTypePointer Function %14
1751 %20 = OpConstant %8 2
1752 %21 = OpConstant %14 0
1753 %2 = OpFunction %6 None %7
1754 %22 = OpLabel
1755 %3 = OpVariable %9 Function
1756 %4 = OpVariable %18 Function
1757 %5 = OpVariable %18 Function
1758 OpStore %3 %10
1759 OpBranch %46
1760 %46 = OpLabel
1761 %47 = OpPhi %8 %10 %22 %67 %66
1762 OpLoopMerge %68 %66 None
1763 OpBranch %48
1764 %48 = OpLabel
1765 %49 = OpSLessThan %12 %47 %11
1766 OpBranchConditional %49 %50 %68
1767 %50 = OpLabel
1768 %51 = OpIEqual %12 %47 %13
1769 OpSelectionMerge %65 None
1770 OpBranchConditional %51 %61 %52
1771 %52 = OpLabel
1772 %53 = OpIEqual %12 %47 %20
1773 OpSelectionMerge %60 None
1774 OpBranchConditional %53 %56 %54
1775 %54 = OpLabel
1776 OpBranch %60
1777 %56 = OpLabel
1778 OpBranch %60
1779 %60 = OpLabel
1780 OpBranch %65
1781 %61 = OpLabel
1782 %62 = OpAccessChain %19 %5 %47
1783 %63 = OpLoad %14 %62
1784 %64 = OpAccessChain %19 %4 %47
1785 OpStore %64 %63
1786 OpBranch %65
1787 %65 = OpLabel
1788 OpBranch %66
1789 %66 = OpLabel
1790 %67 = OpIAdd %8 %47 %13
1791 OpStore %3 %67
1792 OpBranch %46
1793 %68 = OpLabel
1794 OpBranch %69
1795 %69 = OpLabel
1796 %70 = OpPhi %8 %10 %68 %87 %86
1797 OpLoopMerge %88 %86 None
1798 OpBranch %71
1799 %71 = OpLabel
1800 %72 = OpSLessThan %12 %70 %11
1801 OpBranchConditional %72 %73 %88
1802 %73 = OpLabel
1803 %74 = OpIEqual %12 %70 %13
1804 OpSelectionMerge %85 None
1805 OpBranchConditional %74 %84 %75
1806 %75 = OpLabel
1807 %76 = OpIEqual %12 %70 %20
1808 OpSelectionMerge %83 None
1809 OpBranchConditional %76 %79 %77
1810 %77 = OpLabel
1811 OpBranch %83
1812 %79 = OpLabel
1813 %80 = OpAccessChain %19 %4 %70
1814 %81 = OpLoad %14 %80
1815 %82 = OpAccessChain %19 %5 %70
1816 OpStore %82 %81
1817 OpBranch %83
1818 %83 = OpLabel
1819 OpBranch %85
1820 %84 = OpLabel
1821 OpBranch %85
1822 %85 = OpLabel
1823 OpBranch %86
1824 %86 = OpLabel
1825 %87 = OpIAdd %8 %70 %13
1826 OpStore %3 %87
1827 OpBranch %69
1828 %88 = OpLabel
1829 OpBranch %23
1830 %23 = OpLabel
1831 %24 = OpPhi %8 %10 %88 %25 %26
1832 OpLoopMerge %27 %26 None
1833 OpBranch %28
1834 %28 = OpLabel
1835 %29 = OpSLessThan %12 %24 %11
1836 OpBranchConditional %29 %30 %27
1837 %30 = OpLabel
1838 %31 = OpIEqual %12 %24 %13
1839 OpSelectionMerge %32 None
1840 OpBranchConditional %31 %33 %34
1841 %33 = OpLabel
1842 OpBranch %32
1843 %34 = OpLabel
1844 %38 = OpIEqual %12 %24 %20
1845 OpSelectionMerge %39 None
1846 OpBranchConditional %38 %40 %41
1847 %40 = OpLabel
1848 OpBranch %39
1849 %41 = OpLabel
1850 %45 = OpAccessChain %19 %5 %24
1851 OpStore %45 %21
1852 OpBranch %39
1853 %39 = OpLabel
1854 OpBranch %32
1855 %32 = OpLabel
1856 OpBranch %26
1857 %26 = OpLabel
1858 %25 = OpIAdd %8 %24 %13
1859 OpStore %3 %25
1860 OpBranch %23
1861 %27 = OpLabel
1862 OpReturn
1863 OpFunctionEnd
1864 )";
1865
1866 // clang-format on
1867 std::unique_ptr<IRContext> context =
1868 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
1869 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1870 Module* module = context->module();
1871 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1872 << source << std::endl;
1873
1874 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1875 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true, 1);
1876 }
1877
1878 /*
1879 #version 430
1880 layout(location=0) flat in int condition;
1881 void main(void) {
1882 float A[10];
1883 float B[10];
1884 for (int i = 0; i < 10; i++) {
1885 B[i] = A[i];
1886 memoryBarrier();
1887 A[i] = B[i];
1888 }
1889 }
1890
1891 This should not be split due to the memory barrier.
1892 */
TEST_F(FissionClassTest,FissionBarrier)1893 TEST_F(FissionClassTest, FissionBarrier) {
1894 // clang-format off
1895 // With LocalMultiStoreElimPass
1896 const std::string source = R"(OpCapability Shader
1897 %1 = OpExtInstImport "GLSL.std.450"
1898 OpMemoryModel Logical GLSL450
1899 OpEntryPoint Fragment %2 "main" %3
1900 OpExecutionMode %2 OriginUpperLeft
1901 OpSource GLSL 430
1902 OpName %2 "main"
1903 OpName %4 "i"
1904 OpName %5 "B"
1905 OpName %6 "A"
1906 OpName %3 "condition"
1907 OpDecorate %3 Flat
1908 OpDecorate %3 Location 0
1909 %7 = OpTypeVoid
1910 %8 = OpTypeFunction %7
1911 %9 = OpTypeInt 32 1
1912 %10 = OpTypePointer Function %9
1913 %11 = OpConstant %9 0
1914 %12 = OpConstant %9 10
1915 %13 = OpTypeBool
1916 %14 = OpTypeFloat 32
1917 %15 = OpTypeInt 32 0
1918 %16 = OpConstant %15 10
1919 %17 = OpTypeArray %14 %16
1920 %18 = OpTypePointer Function %17
1921 %19 = OpTypePointer Function %14
1922 %20 = OpConstant %15 1
1923 %21 = OpConstant %15 4048
1924 %22 = OpConstant %9 1
1925 %23 = OpTypePointer Input %9
1926 %3 = OpVariable %23 Input
1927 %2 = OpFunction %7 None %8
1928 %24 = OpLabel
1929 %4 = OpVariable %10 Function
1930 %5 = OpVariable %18 Function
1931 %6 = OpVariable %18 Function
1932 OpStore %4 %11
1933 OpBranch %25
1934 %25 = OpLabel
1935 %26 = OpPhi %9 %11 %24 %27 %28
1936 OpLoopMerge %29 %28 None
1937 OpBranch %30
1938 %30 = OpLabel
1939 %31 = OpSLessThan %13 %26 %12
1940 OpBranchConditional %31 %32 %29
1941 %32 = OpLabel
1942 %33 = OpAccessChain %19 %6 %26
1943 %34 = OpLoad %14 %33
1944 %35 = OpAccessChain %19 %5 %26
1945 OpStore %35 %34
1946 OpMemoryBarrier %20 %21
1947 %36 = OpAccessChain %19 %5 %26
1948 %37 = OpLoad %14 %36
1949 %38 = OpAccessChain %19 %6 %26
1950 OpStore %38 %37
1951 OpBranch %28
1952 %28 = OpLabel
1953 %27 = OpIAdd %9 %26 %22
1954 OpStore %4 %27
1955 OpBranch %25
1956 %29 = OpLabel
1957 OpReturn
1958 OpFunctionEnd
1959 )";
1960 // clang-format on
1961 std::unique_ptr<IRContext> context =
1962 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
1963 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1964 Module* module = context->module();
1965 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1966 << source << std::endl;
1967
1968 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1969 SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
1970 }
1971
1972 /*
1973 #version 430
1974 void main(void) {
1975 float A[10];
1976 float B[10];
1977 for (int i = 0; i < 10; i++) {
1978 B[i] = A[i];
1979 if ( i== 1)
1980 break;
1981 A[i] = B[i];
1982 }
1983 }
1984
1985 This should not be split due to the break.
1986 */
TEST_F(FissionClassTest,FissionBreak)1987 TEST_F(FissionClassTest, FissionBreak) {
1988 // clang-format off
1989 // With LocalMultiStoreElimPass
1990 const std::string source = R"(OpCapability Shader
1991 %1 = OpExtInstImport "GLSL.std.450"
1992 OpMemoryModel Logical GLSL450
1993 OpEntryPoint Fragment %2 "main"
1994 OpExecutionMode %2 OriginUpperLeft
1995 OpSource GLSL 430
1996 OpName %2 "main"
1997 OpName %3 "i"
1998 OpName %4 "B"
1999 OpName %5 "A"
2000 %6 = OpTypeVoid
2001 %7 = OpTypeFunction %6
2002 %8 = OpTypeInt 32 1
2003 %9 = OpTypePointer Function %8
2004 %10 = OpConstant %8 0
2005 %11 = OpConstant %8 10
2006 %12 = OpTypeBool
2007 %13 = OpTypeFloat 32
2008 %14 = OpTypeInt 32 0
2009 %15 = OpConstant %14 10
2010 %16 = OpTypeArray %13 %15
2011 %17 = OpTypePointer Function %16
2012 %18 = OpTypePointer Function %13
2013 %19 = OpConstant %8 1
2014 %2 = OpFunction %6 None %7
2015 %20 = OpLabel
2016 %3 = OpVariable %9 Function
2017 %4 = OpVariable %17 Function
2018 %5 = OpVariable %17 Function
2019 OpStore %3 %10
2020 OpBranch %21
2021 %21 = OpLabel
2022 %22 = OpPhi %8 %10 %20 %23 %24
2023 OpLoopMerge %25 %24 None
2024 OpBranch %26
2025 %26 = OpLabel
2026 %27 = OpSLessThan %12 %22 %11
2027 OpBranchConditional %27 %28 %25
2028 %28 = OpLabel
2029 %29 = OpAccessChain %18 %5 %22
2030 %30 = OpLoad %13 %29
2031 %31 = OpAccessChain %18 %4 %22
2032 OpStore %31 %30
2033 %32 = OpIEqual %12 %22 %19
2034 OpSelectionMerge %33 None
2035 OpBranchConditional %32 %34 %33
2036 %34 = OpLabel
2037 OpBranch %25
2038 %33 = OpLabel
2039 %35 = OpAccessChain %18 %4 %22
2040 %36 = OpLoad %13 %35
2041 %37 = OpAccessChain %18 %5 %22
2042 OpStore %37 %36
2043 OpBranch %24
2044 %24 = OpLabel
2045 %23 = OpIAdd %8 %22 %19
2046 OpStore %3 %23
2047 OpBranch %21
2048 %25 = OpLabel
2049 OpReturn
2050 OpFunctionEnd
2051 )";
2052 // clang-format on
2053 std::unique_ptr<IRContext> context =
2054 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
2055 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2056 Module* module = context->module();
2057 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
2058 << source << std::endl;
2059
2060 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2061 SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
2062 }
2063
2064 /*
2065 #version 430
2066 void main(void) {
2067 float A[10];
2068 float B[10];
2069 for (int i = 0; i < 10; i++) {
2070 B[i] = A[i];
2071 if ( i== 1)
2072 continue;
2073 A[i] = B[i];
2074 }
2075 }
2076
2077 This loop should be split into:
2078
2079 for (int i = 0; i < 10; i++) {
2080 B[i] = A[i];
2081 if ( i== 1)
2082 continue;
2083 }
2084 for (int i = 0; i < 10; i++) {
2085 if ( i== 1)
2086 continue;
2087 A[i] = B[i];
2088 }
2089 The continue block in the first loop is left to DCE.
2090 }
2091
2092
2093 */
TEST_F(FissionClassTest,FissionContinue)2094 TEST_F(FissionClassTest, FissionContinue) {
2095 // clang-format off
2096 // With LocalMultiStoreElimPass
2097 const std::string source = R"(OpCapability Shader
2098 %1 = OpExtInstImport "GLSL.std.450"
2099 OpMemoryModel Logical GLSL450
2100 OpEntryPoint Fragment %2 "main"
2101 OpExecutionMode %2 OriginUpperLeft
2102 OpSource GLSL 430
2103 OpName %2 "main"
2104 OpName %3 "i"
2105 OpName %4 "B"
2106 OpName %5 "A"
2107 %6 = OpTypeVoid
2108 %7 = OpTypeFunction %6
2109 %8 = OpTypeInt 32 1
2110 %9 = OpTypePointer Function %8
2111 %10 = OpConstant %8 0
2112 %11 = OpConstant %8 10
2113 %12 = OpTypeBool
2114 %13 = OpTypeFloat 32
2115 %14 = OpTypeInt 32 0
2116 %15 = OpConstant %14 10
2117 %16 = OpTypeArray %13 %15
2118 %17 = OpTypePointer Function %16
2119 %18 = OpTypePointer Function %13
2120 %19 = OpConstant %8 1
2121 %2 = OpFunction %6 None %7
2122 %20 = OpLabel
2123 %3 = OpVariable %9 Function
2124 %4 = OpVariable %17 Function
2125 %5 = OpVariable %17 Function
2126 OpStore %3 %10
2127 OpBranch %21
2128 %21 = OpLabel
2129 %22 = OpPhi %8 %10 %20 %23 %24
2130 OpLoopMerge %25 %24 None
2131 OpBranch %26
2132 %26 = OpLabel
2133 %27 = OpSLessThan %12 %22 %11
2134 OpBranchConditional %27 %28 %25
2135 %28 = OpLabel
2136 %29 = OpAccessChain %18 %5 %22
2137 %30 = OpLoad %13 %29
2138 %31 = OpAccessChain %18 %4 %22
2139 OpStore %31 %30
2140 %32 = OpIEqual %12 %22 %19
2141 OpSelectionMerge %33 None
2142 OpBranchConditional %32 %34 %33
2143 %34 = OpLabel
2144 OpBranch %24
2145 %33 = OpLabel
2146 %35 = OpAccessChain %18 %4 %22
2147 %36 = OpLoad %13 %35
2148 %37 = OpAccessChain %18 %5 %22
2149 OpStore %37 %36
2150 OpBranch %24
2151 %24 = OpLabel
2152 %23 = OpIAdd %8 %22 %19
2153 OpStore %3 %23
2154 OpBranch %21
2155 %25 = OpLabel
2156 OpReturn
2157 OpFunctionEnd
2158 )";
2159
2160 const std::string expected = R"(OpCapability Shader
2161 %1 = OpExtInstImport "GLSL.std.450"
2162 OpMemoryModel Logical GLSL450
2163 OpEntryPoint Fragment %2 "main"
2164 OpExecutionMode %2 OriginUpperLeft
2165 OpSource GLSL 430
2166 OpName %2 "main"
2167 OpName %3 "i"
2168 OpName %4 "B"
2169 OpName %5 "A"
2170 %6 = OpTypeVoid
2171 %7 = OpTypeFunction %6
2172 %8 = OpTypeInt 32 1
2173 %9 = OpTypePointer Function %8
2174 %10 = OpConstant %8 0
2175 %11 = OpConstant %8 10
2176 %12 = OpTypeBool
2177 %13 = OpTypeFloat 32
2178 %14 = OpTypeInt 32 0
2179 %15 = OpConstant %14 10
2180 %16 = OpTypeArray %13 %15
2181 %17 = OpTypePointer Function %16
2182 %18 = OpTypePointer Function %13
2183 %19 = OpConstant %8 1
2184 %2 = OpFunction %6 None %7
2185 %20 = OpLabel
2186 %3 = OpVariable %9 Function
2187 %4 = OpVariable %17 Function
2188 %5 = OpVariable %17 Function
2189 OpStore %3 %10
2190 OpBranch %38
2191 %38 = OpLabel
2192 %39 = OpPhi %8 %10 %20 %53 %52
2193 OpLoopMerge %54 %52 None
2194 OpBranch %40
2195 %40 = OpLabel
2196 %41 = OpSLessThan %12 %39 %11
2197 OpBranchConditional %41 %42 %54
2198 %42 = OpLabel
2199 %43 = OpAccessChain %18 %5 %39
2200 %44 = OpLoad %13 %43
2201 %45 = OpAccessChain %18 %4 %39
2202 OpStore %45 %44
2203 %46 = OpIEqual %12 %39 %19
2204 OpSelectionMerge %48 None
2205 OpBranchConditional %46 %47 %48
2206 %47 = OpLabel
2207 OpBranch %52
2208 %48 = OpLabel
2209 OpBranch %52
2210 %52 = OpLabel
2211 %53 = OpIAdd %8 %39 %19
2212 OpStore %3 %53
2213 OpBranch %38
2214 %54 = OpLabel
2215 OpBranch %21
2216 %21 = OpLabel
2217 %22 = OpPhi %8 %10 %54 %23 %24
2218 OpLoopMerge %25 %24 None
2219 OpBranch %26
2220 %26 = OpLabel
2221 %27 = OpSLessThan %12 %22 %11
2222 OpBranchConditional %27 %28 %25
2223 %28 = OpLabel
2224 %32 = OpIEqual %12 %22 %19
2225 OpSelectionMerge %33 None
2226 OpBranchConditional %32 %34 %33
2227 %34 = OpLabel
2228 OpBranch %24
2229 %33 = OpLabel
2230 %35 = OpAccessChain %18 %4 %22
2231 %36 = OpLoad %13 %35
2232 %37 = OpAccessChain %18 %5 %22
2233 OpStore %37 %36
2234 OpBranch %24
2235 %24 = OpLabel
2236 %23 = OpIAdd %8 %22 %19
2237 OpStore %3 %23
2238 OpBranch %21
2239 %25 = OpLabel
2240 OpReturn
2241 OpFunctionEnd
2242 )";
2243 // clang-format on
2244 std::unique_ptr<IRContext> context =
2245 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
2246 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2247 Module* module = context->module();
2248 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
2249 << source << std::endl;
2250
2251 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2252 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
2253 }
2254
2255 /*
2256 #version 430
2257 void main(void) {
2258 float A[10];
2259 float B[10];
2260 int i = 0;
2261 do {
2262 B[i] = A[i];
2263 A[i] = B[i];
2264 ++i;
2265 } while (i < 10);
2266 }
2267
2268
2269 Check that this is split into:
2270 int i = 0;
2271 do {
2272 B[i] = A[i];
2273 ++i;
2274 } while (i < 10);
2275
2276 i = 0;
2277 do {
2278 A[i] = B[i];
2279 ++i;
2280 } while (i < 10);
2281
2282
2283 */
TEST_F(FissionClassTest,FissionDoWhile)2284 TEST_F(FissionClassTest, FissionDoWhile) {
2285 // clang-format off
2286 // With LocalMultiStoreElimPass
2287 const std::string source = R"(OpCapability Shader
2288 %1 = OpExtInstImport "GLSL.std.450"
2289 OpMemoryModel Logical GLSL450
2290 OpEntryPoint Fragment %2 "main"
2291 OpExecutionMode %2 OriginUpperLeft
2292 OpSource GLSL 430
2293 OpName %2 "main"
2294 OpName %3 "i"
2295 OpName %4 "B"
2296 OpName %5 "A"
2297 %6 = OpTypeVoid
2298 %7 = OpTypeFunction %6
2299 %8 = OpTypeInt 32 1
2300 %9 = OpTypePointer Function %8
2301 %10 = OpConstant %8 0
2302 %11 = OpTypeFloat 32
2303 %12 = OpTypeInt 32 0
2304 %13 = OpConstant %12 10
2305 %14 = OpTypeArray %11 %13
2306 %15 = OpTypePointer Function %14
2307 %16 = OpTypePointer Function %11
2308 %17 = OpConstant %8 1
2309 %18 = OpConstant %8 10
2310 %19 = OpTypeBool
2311 %2 = OpFunction %6 None %7
2312 %20 = OpLabel
2313 %3 = OpVariable %9 Function
2314 %4 = OpVariable %15 Function
2315 %5 = OpVariable %15 Function
2316 OpStore %3 %10
2317 OpBranch %21
2318 %21 = OpLabel
2319 %22 = OpPhi %8 %10 %20 %23 %24
2320 OpLoopMerge %25 %24 None
2321 OpBranch %26
2322 %26 = OpLabel
2323 %27 = OpAccessChain %16 %5 %22
2324 %28 = OpLoad %11 %27
2325 %29 = OpAccessChain %16 %4 %22
2326 OpStore %29 %28
2327 %30 = OpAccessChain %16 %4 %22
2328 %31 = OpLoad %11 %30
2329 %32 = OpAccessChain %16 %5 %22
2330 OpStore %32 %31
2331 %23 = OpIAdd %8 %22 %17
2332 OpStore %3 %23
2333 OpBranch %24
2334 %24 = OpLabel
2335 %33 = OpSLessThan %19 %23 %18
2336 OpBranchConditional %33 %21 %25
2337 %25 = OpLabel
2338 OpReturn
2339 OpFunctionEnd
2340 )";
2341
2342 const std::string expected = R"(OpCapability Shader
2343 %1 = OpExtInstImport "GLSL.std.450"
2344 OpMemoryModel Logical GLSL450
2345 OpEntryPoint Fragment %2 "main"
2346 OpExecutionMode %2 OriginUpperLeft
2347 OpSource GLSL 430
2348 OpName %2 "main"
2349 OpName %3 "i"
2350 OpName %4 "B"
2351 OpName %5 "A"
2352 %6 = OpTypeVoid
2353 %7 = OpTypeFunction %6
2354 %8 = OpTypeInt 32 1
2355 %9 = OpTypePointer Function %8
2356 %10 = OpConstant %8 0
2357 %11 = OpTypeFloat 32
2358 %12 = OpTypeInt 32 0
2359 %13 = OpConstant %12 10
2360 %14 = OpTypeArray %11 %13
2361 %15 = OpTypePointer Function %14
2362 %16 = OpTypePointer Function %11
2363 %17 = OpConstant %8 1
2364 %18 = OpConstant %8 10
2365 %19 = OpTypeBool
2366 %2 = OpFunction %6 None %7
2367 %20 = OpLabel
2368 %3 = OpVariable %9 Function
2369 %4 = OpVariable %15 Function
2370 %5 = OpVariable %15 Function
2371 OpStore %3 %10
2372 OpBranch %34
2373 %34 = OpLabel
2374 %35 = OpPhi %8 %10 %20 %43 %44
2375 OpLoopMerge %46 %44 None
2376 OpBranch %36
2377 %36 = OpLabel
2378 %37 = OpAccessChain %16 %5 %35
2379 %38 = OpLoad %11 %37
2380 %39 = OpAccessChain %16 %4 %35
2381 OpStore %39 %38
2382 %43 = OpIAdd %8 %35 %17
2383 OpStore %3 %43
2384 OpBranch %44
2385 %44 = OpLabel
2386 %45 = OpSLessThan %19 %43 %18
2387 OpBranchConditional %45 %34 %46
2388 %46 = OpLabel
2389 OpBranch %21
2390 %21 = OpLabel
2391 %22 = OpPhi %8 %10 %46 %23 %24
2392 OpLoopMerge %25 %24 None
2393 OpBranch %26
2394 %26 = OpLabel
2395 %30 = OpAccessChain %16 %4 %22
2396 %31 = OpLoad %11 %30
2397 %32 = OpAccessChain %16 %5 %22
2398 OpStore %32 %31
2399 %23 = OpIAdd %8 %22 %17
2400 OpStore %3 %23
2401 OpBranch %24
2402 %24 = OpLabel
2403 %33 = OpSLessThan %19 %23 %18
2404 OpBranchConditional %33 %21 %25
2405 %25 = OpLabel
2406 OpReturn
2407 OpFunctionEnd
2408 )";
2409 // clang-format on
2410 std::unique_ptr<IRContext> context =
2411 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
2412 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2413 Module* module = context->module();
2414 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
2415 << source << std::endl;
2416
2417 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2418 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
2419 }
2420
2421 /*
2422
2423 #version 430
2424 void main(void) {
2425 float A[10][10];
2426 float B[10][10];
2427 for (int j = 0; j < 10; ++j) {
2428 for (int i = 0; i < 10; ++i) {
2429 B[i][j] = A[i][i];
2430 A[i][i] = B[i][j + 1];
2431 }
2432 }
2433 }
2434
2435
2436 This loop can't be split because the load B[i][j + 1] is dependent on the store
2437 B[i][j].
2438
2439 */
TEST_F(FissionClassTest,FissionNestedDependency)2440 TEST_F(FissionClassTest, FissionNestedDependency) {
2441 // clang-format off
2442 // With LocalMultiStoreElimPass
2443 const std::string source = R"(OpCapability Shader
2444 %1 = OpExtInstImport "GLSL.std.450"
2445 OpMemoryModel Logical GLSL450
2446 OpEntryPoint Fragment %2 "main"
2447 OpExecutionMode %2 OriginUpperLeft
2448 OpSource GLSL 430
2449 OpName %2 "main"
2450 OpName %3 "j"
2451 OpName %4 "i"
2452 OpName %5 "B"
2453 OpName %6 "A"
2454 %7 = OpTypeVoid
2455 %8 = OpTypeFunction %7
2456 %9 = OpTypeInt 32 1
2457 %10 = OpTypePointer Function %9
2458 %11 = OpConstant %9 0
2459 %12 = OpConstant %9 10
2460 %13 = OpTypeBool
2461 %14 = OpTypeFloat 32
2462 %15 = OpTypeInt 32 0
2463 %16 = OpConstant %15 10
2464 %17 = OpTypeArray %14 %16
2465 %18 = OpTypeArray %17 %16
2466 %19 = OpTypePointer Function %18
2467 %20 = OpTypePointer Function %14
2468 %21 = OpConstant %9 1
2469 %2 = OpFunction %7 None %8
2470 %22 = OpLabel
2471 %3 = OpVariable %10 Function
2472 %4 = OpVariable %10 Function
2473 %5 = OpVariable %19 Function
2474 %6 = OpVariable %19 Function
2475 OpBranch %23
2476 %23 = OpLabel
2477 %24 = OpPhi %9 %11 %22 %25 %26
2478 OpLoopMerge %27 %26 None
2479 OpBranch %28
2480 %28 = OpLabel
2481 %29 = OpSLessThan %13 %24 %12
2482 OpBranchConditional %29 %30 %27
2483 %30 = OpLabel
2484 OpBranch %31
2485 %31 = OpLabel
2486 %32 = OpPhi %9 %11 %30 %33 %34
2487 OpLoopMerge %35 %34 None
2488 OpBranch %36
2489 %36 = OpLabel
2490 %37 = OpSLessThan %13 %32 %12
2491 OpBranchConditional %37 %38 %35
2492 %38 = OpLabel
2493 %39 = OpAccessChain %20 %6 %32 %32
2494 %40 = OpLoad %14 %39
2495 %41 = OpAccessChain %20 %5 %32 %24
2496 OpStore %41 %40
2497 %42 = OpIAdd %9 %24 %21
2498 %43 = OpAccessChain %20 %5 %32 %42
2499 %44 = OpLoad %14 %43
2500 %45 = OpAccessChain %20 %6 %32 %32
2501 OpStore %45 %44
2502 OpBranch %34
2503 %34 = OpLabel
2504 %33 = OpIAdd %9 %32 %21
2505 OpBranch %31
2506 %35 = OpLabel
2507 OpBranch %26
2508 %26 = OpLabel
2509 %25 = OpIAdd %9 %24 %21
2510 OpBranch %23
2511 %27 = OpLabel
2512 OpReturn
2513 OpFunctionEnd
2514 )";
2515
2516 // clang-format on
2517 std::unique_ptr<IRContext> context =
2518 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
2519 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2520 Module* module = context->module();
2521 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
2522 << source << std::endl;
2523
2524 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2525 SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
2526 }
2527
2528 /*
2529 #version 430
2530 void main(void) {
2531 float A[10][10];
2532 float B[10][10];
2533 for (int j = 0; j < 10; ++j) {
2534 for (int i = 0; i < 10; ++i) {
2535 B[i][i] = A[i][j];
2536 A[i][j+1] = B[i][i];
2537 }
2538 }
2539 }
2540
2541 This loop should not be split as the load A[i][j+1] would be reading a value
2542 written in the store A[i][j] which would be hit before A[i][j+1] if the loops
2543 where split but would not get hit before the read currently.
2544
2545 */
TEST_F(FissionClassTest,FissionNestedDependency2)2546 TEST_F(FissionClassTest, FissionNestedDependency2) {
2547 // clang-format off
2548 // With LocalMultiStoreElimPass
2549 const std::string source = R"(OpCapability Shader
2550 %1 = OpExtInstImport "GLSL.std.450"
2551 OpMemoryModel Logical GLSL450
2552 OpEntryPoint Fragment %2 "main"
2553 OpExecutionMode %2 OriginUpperLeft
2554 OpSource GLSL 430
2555 OpName %2 "main"
2556 OpName %3 "j"
2557 OpName %4 "i"
2558 OpName %5 "B"
2559 OpName %6 "A"
2560 %7 = OpTypeVoid
2561 %8 = OpTypeFunction %7
2562 %9 = OpTypeInt 32 1
2563 %10 = OpTypePointer Function %9
2564 %11 = OpConstant %9 0
2565 %12 = OpConstant %9 10
2566 %13 = OpTypeBool
2567 %14 = OpTypeFloat 32
2568 %15 = OpTypeInt 32 0
2569 %16 = OpConstant %15 10
2570 %17 = OpTypeArray %14 %16
2571 %18 = OpTypeArray %17 %16
2572 %19 = OpTypePointer Function %18
2573 %20 = OpTypePointer Function %14
2574 %21 = OpConstant %9 1
2575 %2 = OpFunction %7 None %8
2576 %22 = OpLabel
2577 %3 = OpVariable %10 Function
2578 %4 = OpVariable %10 Function
2579 %5 = OpVariable %19 Function
2580 %6 = OpVariable %19 Function
2581 OpStore %3 %11
2582 OpBranch %23
2583 %23 = OpLabel
2584 %24 = OpPhi %9 %11 %22 %25 %26
2585 OpLoopMerge %27 %26 None
2586 OpBranch %28
2587 %28 = OpLabel
2588 %29 = OpSLessThan %13 %24 %12
2589 OpBranchConditional %29 %30 %27
2590 %30 = OpLabel
2591 OpStore %4 %11
2592 OpBranch %31
2593 %31 = OpLabel
2594 %32 = OpPhi %9 %11 %30 %33 %34
2595 OpLoopMerge %35 %34 None
2596 OpBranch %36
2597 %36 = OpLabel
2598 %37 = OpSLessThan %13 %32 %12
2599 OpBranchConditional %37 %38 %35
2600 %38 = OpLabel
2601 %39 = OpAccessChain %20 %6 %32 %24
2602 %40 = OpLoad %14 %39
2603 %41 = OpAccessChain %20 %5 %32 %32
2604 OpStore %41 %40
2605 %42 = OpIAdd %9 %24 %21
2606 %43 = OpAccessChain %20 %5 %32 %32
2607 %44 = OpLoad %14 %43
2608 %45 = OpAccessChain %20 %6 %32 %42
2609 OpStore %45 %44
2610 OpBranch %34
2611 %34 = OpLabel
2612 %33 = OpIAdd %9 %32 %21
2613 OpStore %4 %33
2614 OpBranch %31
2615 %35 = OpLabel
2616 OpBranch %26
2617 %26 = OpLabel
2618 %25 = OpIAdd %9 %24 %21
2619 OpStore %3 %25
2620 OpBranch %23
2621 %27 = OpLabel
2622 OpReturn
2623 OpFunctionEnd
2624 )";
2625
2626 // clang-format on
2627 std::unique_ptr<IRContext> context =
2628 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
2629 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2630 Module* module = context->module();
2631 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
2632 << source << std::endl;
2633
2634 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2635 SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
2636 }
2637
2638 /*
2639 #version 430
2640 void main(void) {
2641 float A[10][10];
2642 float B[10][10];
2643 for (int j = 0; j < 10; ++j) {
2644 for (int i = 0; i < 10; ++i) {
2645 B[i][j] = A[i][j];
2646 A[i][j] = B[i][j];
2647 }
2648 for (int i = 0; i < 10; ++i) {
2649 B[i][j] = A[i][j];
2650 A[i][j] = B[i][j];
2651 }
2652 }
2653 }
2654
2655
2656
2657 Should be split into:
2658
2659 for (int j = 0; j < 10; ++j) {
2660 for (int i = 0; i < 10; ++i)
2661 B[i][j] = A[i][j];
2662 for (int i = 0; i < 10; ++i)
2663 A[i][j] = B[i][j];
2664 for (int i = 0; i < 10; ++i)
2665 B[i][j] = A[i][j];
2666 for (int i = 0; i < 10; ++i)
2667 A[i][j] = B[i][j];
2668 */
TEST_F(FissionClassTest,FissionMultipleLoopsNested)2669 TEST_F(FissionClassTest, FissionMultipleLoopsNested) {
2670 // clang-format off
2671 // With LocalMultiStoreElimPass
2672 const std::string source = R"(OpCapability Shader
2673 %1 = OpExtInstImport "GLSL.std.450"
2674 OpMemoryModel Logical GLSL450
2675 OpEntryPoint Fragment %2 "main"
2676 OpExecutionMode %2 OriginUpperLeft
2677 OpSource GLSL 430
2678 OpName %2 "main"
2679 OpName %3 "j"
2680 OpName %4 "i"
2681 OpName %5 "B"
2682 OpName %6 "A"
2683 OpName %7 "i"
2684 %8 = OpTypeVoid
2685 %9 = OpTypeFunction %8
2686 %10 = OpTypeInt 32 1
2687 %11 = OpTypePointer Function %10
2688 %12 = OpConstant %10 0
2689 %13 = OpConstant %10 10
2690 %14 = OpTypeBool
2691 %15 = OpTypeFloat 32
2692 %16 = OpTypeInt 32 0
2693 %17 = OpConstant %16 10
2694 %18 = OpTypeArray %15 %17
2695 %19 = OpTypeArray %18 %17
2696 %20 = OpTypePointer Function %19
2697 %21 = OpTypePointer Function %15
2698 %22 = OpConstant %10 1
2699 %2 = OpFunction %8 None %9
2700 %23 = OpLabel
2701 %3 = OpVariable %11 Function
2702 %4 = OpVariable %11 Function
2703 %5 = OpVariable %20 Function
2704 %6 = OpVariable %20 Function
2705 %7 = OpVariable %11 Function
2706 OpStore %3 %12
2707 OpBranch %24
2708 %24 = OpLabel
2709 %25 = OpPhi %10 %12 %23 %26 %27
2710 OpLoopMerge %28 %27 None
2711 OpBranch %29
2712 %29 = OpLabel
2713 %30 = OpSLessThan %14 %25 %13
2714 OpBranchConditional %30 %31 %28
2715 %31 = OpLabel
2716 OpStore %4 %12
2717 OpBranch %32
2718 %32 = OpLabel
2719 %33 = OpPhi %10 %12 %31 %34 %35
2720 OpLoopMerge %36 %35 None
2721 OpBranch %37
2722 %37 = OpLabel
2723 %38 = OpSLessThan %14 %33 %13
2724 OpBranchConditional %38 %39 %36
2725 %39 = OpLabel
2726 %40 = OpAccessChain %21 %6 %33 %25
2727 %41 = OpLoad %15 %40
2728 %42 = OpAccessChain %21 %5 %33 %25
2729 OpStore %42 %41
2730 %43 = OpAccessChain %21 %5 %33 %25
2731 %44 = OpLoad %15 %43
2732 %45 = OpAccessChain %21 %6 %33 %25
2733 OpStore %45 %44
2734 OpBranch %35
2735 %35 = OpLabel
2736 %34 = OpIAdd %10 %33 %22
2737 OpStore %4 %34
2738 OpBranch %32
2739 %36 = OpLabel
2740 OpStore %7 %12
2741 OpBranch %46
2742 %46 = OpLabel
2743 %47 = OpPhi %10 %12 %36 %48 %49
2744 OpLoopMerge %50 %49 None
2745 OpBranch %51
2746 %51 = OpLabel
2747 %52 = OpSLessThan %14 %47 %13
2748 OpBranchConditional %52 %53 %50
2749 %53 = OpLabel
2750 %54 = OpAccessChain %21 %6 %47 %25
2751 %55 = OpLoad %15 %54
2752 %56 = OpAccessChain %21 %5 %47 %25
2753 OpStore %56 %55
2754 %57 = OpAccessChain %21 %5 %47 %25
2755 %58 = OpLoad %15 %57
2756 %59 = OpAccessChain %21 %6 %47 %25
2757 OpStore %59 %58
2758 OpBranch %49
2759 %49 = OpLabel
2760 %48 = OpIAdd %10 %47 %22
2761 OpStore %7 %48
2762 OpBranch %46
2763 %50 = OpLabel
2764 OpBranch %27
2765 %27 = OpLabel
2766 %26 = OpIAdd %10 %25 %22
2767 OpStore %3 %26
2768 OpBranch %24
2769 %28 = OpLabel
2770 OpReturn
2771 OpFunctionEnd
2772 )";
2773
2774 const std::string expected = R"(OpCapability Shader
2775 %1 = OpExtInstImport "GLSL.std.450"
2776 OpMemoryModel Logical GLSL450
2777 OpEntryPoint Fragment %2 "main"
2778 OpExecutionMode %2 OriginUpperLeft
2779 OpSource GLSL 430
2780 OpName %2 "main"
2781 OpName %3 "j"
2782 OpName %4 "i"
2783 OpName %5 "B"
2784 OpName %6 "A"
2785 OpName %7 "i"
2786 %8 = OpTypeVoid
2787 %9 = OpTypeFunction %8
2788 %10 = OpTypeInt 32 1
2789 %11 = OpTypePointer Function %10
2790 %12 = OpConstant %10 0
2791 %13 = OpConstant %10 10
2792 %14 = OpTypeBool
2793 %15 = OpTypeFloat 32
2794 %16 = OpTypeInt 32 0
2795 %17 = OpConstant %16 10
2796 %18 = OpTypeArray %15 %17
2797 %19 = OpTypeArray %18 %17
2798 %20 = OpTypePointer Function %19
2799 %21 = OpTypePointer Function %15
2800 %22 = OpConstant %10 1
2801 %2 = OpFunction %8 None %9
2802 %23 = OpLabel
2803 %3 = OpVariable %11 Function
2804 %4 = OpVariable %11 Function
2805 %5 = OpVariable %20 Function
2806 %6 = OpVariable %20 Function
2807 %7 = OpVariable %11 Function
2808 OpStore %3 %12
2809 OpBranch %24
2810 %24 = OpLabel
2811 %25 = OpPhi %10 %12 %23 %26 %27
2812 OpLoopMerge %28 %27 None
2813 OpBranch %29
2814 %29 = OpLabel
2815 %30 = OpSLessThan %14 %25 %13
2816 OpBranchConditional %30 %31 %28
2817 %31 = OpLabel
2818 OpStore %4 %12
2819 OpBranch %60
2820 %60 = OpLabel
2821 %61 = OpPhi %10 %12 %31 %72 %71
2822 OpLoopMerge %73 %71 None
2823 OpBranch %62
2824 %62 = OpLabel
2825 %63 = OpSLessThan %14 %61 %13
2826 OpBranchConditional %63 %64 %73
2827 %64 = OpLabel
2828 %65 = OpAccessChain %21 %6 %61 %25
2829 %66 = OpLoad %15 %65
2830 %67 = OpAccessChain %21 %5 %61 %25
2831 OpStore %67 %66
2832 OpBranch %71
2833 %71 = OpLabel
2834 %72 = OpIAdd %10 %61 %22
2835 OpStore %4 %72
2836 OpBranch %60
2837 %73 = OpLabel
2838 OpBranch %32
2839 %32 = OpLabel
2840 %33 = OpPhi %10 %12 %73 %34 %35
2841 OpLoopMerge %36 %35 None
2842 OpBranch %37
2843 %37 = OpLabel
2844 %38 = OpSLessThan %14 %33 %13
2845 OpBranchConditional %38 %39 %36
2846 %39 = OpLabel
2847 %43 = OpAccessChain %21 %5 %33 %25
2848 %44 = OpLoad %15 %43
2849 %45 = OpAccessChain %21 %6 %33 %25
2850 OpStore %45 %44
2851 OpBranch %35
2852 %35 = OpLabel
2853 %34 = OpIAdd %10 %33 %22
2854 OpStore %4 %34
2855 OpBranch %32
2856 %36 = OpLabel
2857 OpStore %7 %12
2858 OpBranch %74
2859 %74 = OpLabel
2860 %75 = OpPhi %10 %12 %36 %86 %85
2861 OpLoopMerge %87 %85 None
2862 OpBranch %76
2863 %76 = OpLabel
2864 %77 = OpSLessThan %14 %75 %13
2865 OpBranchConditional %77 %78 %87
2866 %78 = OpLabel
2867 %79 = OpAccessChain %21 %6 %75 %25
2868 %80 = OpLoad %15 %79
2869 %81 = OpAccessChain %21 %5 %75 %25
2870 OpStore %81 %80
2871 OpBranch %85
2872 %85 = OpLabel
2873 %86 = OpIAdd %10 %75 %22
2874 OpStore %7 %86
2875 OpBranch %74
2876 %87 = OpLabel
2877 OpBranch %46
2878 %46 = OpLabel
2879 %47 = OpPhi %10 %12 %87 %48 %49
2880 OpLoopMerge %50 %49 None
2881 OpBranch %51
2882 %51 = OpLabel
2883 %52 = OpSLessThan %14 %47 %13
2884 OpBranchConditional %52 %53 %50
2885 %53 = OpLabel
2886 %57 = OpAccessChain %21 %5 %47 %25
2887 %58 = OpLoad %15 %57
2888 %59 = OpAccessChain %21 %6 %47 %25
2889 OpStore %59 %58
2890 OpBranch %49
2891 %49 = OpLabel
2892 %48 = OpIAdd %10 %47 %22
2893 OpStore %7 %48
2894 OpBranch %46
2895 %50 = OpLabel
2896 OpBranch %27
2897 %27 = OpLabel
2898 %26 = OpIAdd %10 %25 %22
2899 OpStore %3 %26
2900 OpBranch %24
2901 %28 = OpLabel
2902 OpReturn
2903 OpFunctionEnd
2904 )";
2905 // clang-format on
2906 std::unique_ptr<IRContext> context =
2907 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
2908 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2909 Module* module = context->module();
2910 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
2911 << source << std::endl;
2912 const Function* function = spvtest::GetFunction(module, 2);
2913 LoopDescriptor& pre_pass_descriptor = *context->GetLoopDescriptor(function);
2914 EXPECT_EQ(pre_pass_descriptor.NumLoops(), 3u);
2915 EXPECT_EQ(pre_pass_descriptor.pre_begin()->NumImmediateChildren(), 2u);
2916
2917 // Test that the pass transforms the ir into the expected output.
2918 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2919 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
2920
2921 // Test that the loop descriptor is correctly maintained and updated by the
2922 // pass.
2923 LoopFissionPass loop_fission;
2924 loop_fission.SetContextForTesting(context.get());
2925 loop_fission.Process();
2926
2927 function = spvtest::GetFunction(module, 2);
2928 LoopDescriptor& post_pass_descriptor = *context->GetLoopDescriptor(function);
2929 EXPECT_EQ(post_pass_descriptor.NumLoops(), 5u);
2930 EXPECT_EQ(post_pass_descriptor.pre_begin()->NumImmediateChildren(), 4u);
2931 }
2932
2933 /*
2934 #version 430
2935 void main(void) {
2936 float A[10][10];
2937 float B[10][10];
2938 for (int i = 0; i < 10; ++i) {
2939 B[i][i] = A[i][i];
2940 A[i][i] = B[i][i];
2941 }
2942 for (int i = 0; i < 10; ++i) {
2943 B[i][i] = A[i][i];
2944 A[i][i] = B[i][i]
2945 }
2946 }
2947
2948
2949
2950 Should be split into:
2951
2952 for (int i = 0; i < 10; ++i)
2953 B[i][i] = A[i][i];
2954 for (int i = 0; i < 10; ++i)
2955 A[i][i] = B[i][i];
2956 for (int i = 0; i < 10; ++i)
2957 B[i][i] = A[i][i];
2958 for (int i = 0; i < 10; ++i)
2959 A[i][i] = B[i][i];
2960 */
TEST_F(FissionClassTest,FissionMultipleLoops)2961 TEST_F(FissionClassTest, FissionMultipleLoops) {
2962 // clang-format off
2963 // With LocalMultiStoreElimPass
2964 const std::string source = R"(OpCapability Shader
2965 %1 = OpExtInstImport "GLSL.std.450"
2966 OpMemoryModel Logical GLSL450
2967 OpEntryPoint Fragment %2 "main"
2968 OpExecutionMode %2 OriginUpperLeft
2969 OpSource GLSL 430
2970 OpName %2 "main"
2971 OpName %3 "i"
2972 OpName %4 "B"
2973 OpName %5 "A"
2974 OpName %6 "i"
2975 %7 = OpTypeVoid
2976 %8 = OpTypeFunction %7
2977 %9 = OpTypeInt 32 1
2978 %10 = OpTypePointer Function %9
2979 %11 = OpConstant %9 0
2980 %12 = OpConstant %9 10
2981 %13 = OpTypeBool
2982 %14 = OpTypeFloat 32
2983 %15 = OpTypeInt 32 0
2984 %16 = OpConstant %15 10
2985 %17 = OpTypeArray %14 %16
2986 %18 = OpTypePointer Function %17
2987 %19 = OpTypePointer Function %14
2988 %20 = OpConstant %9 1
2989 %2 = OpFunction %7 None %8
2990 %21 = OpLabel
2991 %3 = OpVariable %10 Function
2992 %4 = OpVariable %18 Function
2993 %5 = OpVariable %18 Function
2994 %6 = OpVariable %10 Function
2995 OpStore %3 %11
2996 OpBranch %22
2997 %22 = OpLabel
2998 %23 = OpPhi %9 %11 %21 %24 %25
2999 OpLoopMerge %26 %25 None
3000 OpBranch %27
3001 %27 = OpLabel
3002 %28 = OpSLessThan %13 %23 %12
3003 OpBranchConditional %28 %29 %26
3004 %29 = OpLabel
3005 %30 = OpAccessChain %19 %5 %23
3006 %31 = OpLoad %14 %30
3007 %32 = OpAccessChain %19 %4 %23
3008 OpStore %32 %31
3009 %33 = OpAccessChain %19 %4 %23
3010 %34 = OpLoad %14 %33
3011 %35 = OpAccessChain %19 %5 %23
3012 OpStore %35 %34
3013 OpBranch %25
3014 %25 = OpLabel
3015 %24 = OpIAdd %9 %23 %20
3016 OpStore %3 %24
3017 OpBranch %22
3018 %26 = OpLabel
3019 OpStore %6 %11
3020 OpBranch %36
3021 %36 = OpLabel
3022 %37 = OpPhi %9 %11 %26 %38 %39
3023 OpLoopMerge %40 %39 None
3024 OpBranch %41
3025 %41 = OpLabel
3026 %42 = OpSLessThan %13 %37 %12
3027 OpBranchConditional %42 %43 %40
3028 %43 = OpLabel
3029 %44 = OpAccessChain %19 %5 %37
3030 %45 = OpLoad %14 %44
3031 %46 = OpAccessChain %19 %4 %37
3032 OpStore %46 %45
3033 %47 = OpAccessChain %19 %4 %37
3034 %48 = OpLoad %14 %47
3035 %49 = OpAccessChain %19 %5 %37
3036 OpStore %49 %48
3037 OpBranch %39
3038 %39 = OpLabel
3039 %38 = OpIAdd %9 %37 %20
3040 OpStore %6 %38
3041 OpBranch %36
3042 %40 = OpLabel
3043 OpReturn
3044 OpFunctionEnd
3045 )";
3046
3047 const std::string expected = R"(OpCapability Shader
3048 %1 = OpExtInstImport "GLSL.std.450"
3049 OpMemoryModel Logical GLSL450
3050 OpEntryPoint Fragment %2 "main"
3051 OpExecutionMode %2 OriginUpperLeft
3052 OpSource GLSL 430
3053 OpName %2 "main"
3054 OpName %3 "i"
3055 OpName %4 "B"
3056 OpName %5 "A"
3057 OpName %6 "i"
3058 %7 = OpTypeVoid
3059 %8 = OpTypeFunction %7
3060 %9 = OpTypeInt 32 1
3061 %10 = OpTypePointer Function %9
3062 %11 = OpConstant %9 0
3063 %12 = OpConstant %9 10
3064 %13 = OpTypeBool
3065 %14 = OpTypeFloat 32
3066 %15 = OpTypeInt 32 0
3067 %16 = OpConstant %15 10
3068 %17 = OpTypeArray %14 %16
3069 %18 = OpTypePointer Function %17
3070 %19 = OpTypePointer Function %14
3071 %20 = OpConstant %9 1
3072 %2 = OpFunction %7 None %8
3073 %21 = OpLabel
3074 %3 = OpVariable %10 Function
3075 %4 = OpVariable %18 Function
3076 %5 = OpVariable %18 Function
3077 %6 = OpVariable %10 Function
3078 OpStore %3 %11
3079 OpBranch %64
3080 %64 = OpLabel
3081 %65 = OpPhi %9 %11 %21 %76 %75
3082 OpLoopMerge %77 %75 None
3083 OpBranch %66
3084 %66 = OpLabel
3085 %67 = OpSLessThan %13 %65 %12
3086 OpBranchConditional %67 %68 %77
3087 %68 = OpLabel
3088 %69 = OpAccessChain %19 %5 %65
3089 %70 = OpLoad %14 %69
3090 %71 = OpAccessChain %19 %4 %65
3091 OpStore %71 %70
3092 OpBranch %75
3093 %75 = OpLabel
3094 %76 = OpIAdd %9 %65 %20
3095 OpStore %3 %76
3096 OpBranch %64
3097 %77 = OpLabel
3098 OpBranch %22
3099 %22 = OpLabel
3100 %23 = OpPhi %9 %11 %77 %24 %25
3101 OpLoopMerge %26 %25 None
3102 OpBranch %27
3103 %27 = OpLabel
3104 %28 = OpSLessThan %13 %23 %12
3105 OpBranchConditional %28 %29 %26
3106 %29 = OpLabel
3107 %33 = OpAccessChain %19 %4 %23
3108 %34 = OpLoad %14 %33
3109 %35 = OpAccessChain %19 %5 %23
3110 OpStore %35 %34
3111 OpBranch %25
3112 %25 = OpLabel
3113 %24 = OpIAdd %9 %23 %20
3114 OpStore %3 %24
3115 OpBranch %22
3116 %26 = OpLabel
3117 OpStore %6 %11
3118 OpBranch %50
3119 %50 = OpLabel
3120 %51 = OpPhi %9 %11 %26 %62 %61
3121 OpLoopMerge %63 %61 None
3122 OpBranch %52
3123 %52 = OpLabel
3124 %53 = OpSLessThan %13 %51 %12
3125 OpBranchConditional %53 %54 %63
3126 %54 = OpLabel
3127 %55 = OpAccessChain %19 %5 %51
3128 %56 = OpLoad %14 %55
3129 %57 = OpAccessChain %19 %4 %51
3130 OpStore %57 %56
3131 OpBranch %61
3132 %61 = OpLabel
3133 %62 = OpIAdd %9 %51 %20
3134 OpStore %6 %62
3135 OpBranch %50
3136 %63 = OpLabel
3137 OpBranch %36
3138 %36 = OpLabel
3139 %37 = OpPhi %9 %11 %63 %38 %39
3140 OpLoopMerge %40 %39 None
3141 OpBranch %41
3142 %41 = OpLabel
3143 %42 = OpSLessThan %13 %37 %12
3144 OpBranchConditional %42 %43 %40
3145 %43 = OpLabel
3146 %47 = OpAccessChain %19 %4 %37
3147 %48 = OpLoad %14 %47
3148 %49 = OpAccessChain %19 %5 %37
3149 OpStore %49 %48
3150 OpBranch %39
3151 %39 = OpLabel
3152 %38 = OpIAdd %9 %37 %20
3153 OpStore %6 %38
3154 OpBranch %36
3155 %40 = OpLabel
3156 OpReturn
3157 OpFunctionEnd
3158 )";
3159 // clang-format on
3160 std::unique_ptr<IRContext> context =
3161 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
3162 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3163 Module* module = context->module();
3164 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
3165 << source << std::endl;
3166
3167 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3168 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
3169
3170 const Function* function = spvtest::GetFunction(module, 2);
3171 LoopDescriptor& pre_pass_descriptor = *context->GetLoopDescriptor(function);
3172 EXPECT_EQ(pre_pass_descriptor.NumLoops(), 2u);
3173 EXPECT_EQ(pre_pass_descriptor.pre_begin()->NumImmediateChildren(), 0u);
3174
3175 // Test that the pass transforms the ir into the expected output.
3176 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3177 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
3178
3179 // Test that the loop descriptor is correctly maintained and updated by the
3180 // pass.
3181 LoopFissionPass loop_fission;
3182 loop_fission.SetContextForTesting(context.get());
3183 loop_fission.Process();
3184
3185 function = spvtest::GetFunction(module, 2);
3186 LoopDescriptor& post_pass_descriptor = *context->GetLoopDescriptor(function);
3187 EXPECT_EQ(post_pass_descriptor.NumLoops(), 4u);
3188 EXPECT_EQ(post_pass_descriptor.pre_begin()->NumImmediateChildren(), 0u);
3189 }
3190
3191 /*
3192 #version 430
3193 int foo() { return 1; }
3194 void main(void) {
3195 float A[10];
3196 float B[10];
3197 for (int i = 0; i < 10; ++i) {
3198 B[i] = A[i];
3199 foo();
3200 A[i] = B[i];
3201 }
3202 }
3203
3204 This should not be split as it has a function call in it so we can't determine
3205 if it has side effects.
3206 */
TEST_F(FissionClassTest,FissionFunctionCall)3207 TEST_F(FissionClassTest, FissionFunctionCall) {
3208 // clang-format off
3209 // With LocalMultiStoreElimPass
3210 const std::string source = R"(OpCapability Shader
3211 %1 = OpExtInstImport "GLSL.std.450"
3212 OpMemoryModel Logical GLSL450
3213 OpEntryPoint Fragment %2 "main"
3214 OpExecutionMode %2 OriginUpperLeft
3215 OpSource GLSL 430
3216 OpName %2 "main"
3217 OpName %3 "foo("
3218 OpName %4 "i"
3219 OpName %5 "B"
3220 OpName %6 "A"
3221 %7 = OpTypeVoid
3222 %8 = OpTypeFunction %7
3223 %9 = OpTypeInt 32 1
3224 %10 = OpTypeFunction %9
3225 %11 = OpConstant %9 1
3226 %12 = OpTypePointer Function %9
3227 %13 = OpConstant %9 0
3228 %14 = OpConstant %9 10
3229 %15 = OpTypeBool
3230 %16 = OpTypeFloat 32
3231 %17 = OpTypeInt 32 0
3232 %18 = OpConstant %17 10
3233 %19 = OpTypeArray %16 %18
3234 %20 = OpTypePointer Function %19
3235 %21 = OpTypePointer Function %16
3236 %2 = OpFunction %7 None %8
3237 %22 = OpLabel
3238 %4 = OpVariable %12 Function
3239 %5 = OpVariable %20 Function
3240 %6 = OpVariable %20 Function
3241 OpStore %4 %13
3242 OpBranch %23
3243 %23 = OpLabel
3244 %24 = OpPhi %9 %13 %22 %25 %26
3245 OpLoopMerge %27 %26 None
3246 OpBranch %28
3247 %28 = OpLabel
3248 %29 = OpSLessThan %15 %24 %14
3249 OpBranchConditional %29 %30 %27
3250 %30 = OpLabel
3251 %31 = OpAccessChain %21 %6 %24
3252 %32 = OpLoad %16 %31
3253 %33 = OpAccessChain %21 %5 %24
3254 OpStore %33 %32
3255 %34 = OpFunctionCall %9 %3
3256 %35 = OpAccessChain %21 %5 %24
3257 %36 = OpLoad %16 %35
3258 %37 = OpAccessChain %21 %6 %24
3259 OpStore %37 %36
3260 OpBranch %26
3261 %26 = OpLabel
3262 %25 = OpIAdd %9 %24 %11
3263 OpStore %4 %25
3264 OpBranch %23
3265 %27 = OpLabel
3266 OpReturn
3267 OpFunctionEnd
3268 %3 = OpFunction %9 None %10
3269 %38 = OpLabel
3270 OpReturnValue %11
3271 OpFunctionEnd
3272 )";
3273
3274 // clang-format on
3275 std::unique_ptr<IRContext> context =
3276 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
3277 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3278 Module* module = context->module();
3279 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
3280 << source << std::endl;
3281
3282 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3283 SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
3284 }
3285
3286 /*
3287 #version 430
3288 void main(void) {
3289 float A[10];
3290 float B[10];
3291 for (int i = 0; i < 10; ++i) {
3292 switch (i) {
3293 case 1:
3294 B[i] = A[i];
3295 break;
3296 default:
3297 A[i] = B[i];
3298 }
3299 }
3300 }
3301
3302 This should be split into:
3303 for (int i = 0; i < 10; ++i) {
3304 switch (i) {
3305 case 1:
3306 break;
3307 default:
3308 A[i] = B[i];
3309 }
3310 }
3311
3312 for (int i = 0; i < 10; ++i) {
3313 switch (i) {
3314 case 1:
3315 B[i] = A[i];
3316 break;
3317 default:
3318 break;
3319 }
3320 }
3321
3322 */
TEST_F(FissionClassTest,FissionSwitchStatement)3323 TEST_F(FissionClassTest, FissionSwitchStatement) {
3324 // clang-format off
3325 // With LocalMultiStoreElimPass
3326 const std::string source = R"(OpCapability Shader
3327 %1 = OpExtInstImport "GLSL.std.450"
3328 OpMemoryModel Logical GLSL450
3329 OpEntryPoint Fragment %2 "main"
3330 OpExecutionMode %2 OriginUpperLeft
3331 OpSource GLSL 430
3332 OpName %2 "main"
3333 OpName %3 "i"
3334 OpName %4 "B"
3335 OpName %5 "A"
3336 %6 = OpTypeVoid
3337 %7 = OpTypeFunction %6
3338 %8 = OpTypeInt 32 1
3339 %9 = OpTypePointer Function %8
3340 %10 = OpConstant %8 0
3341 %11 = OpConstant %8 10
3342 %12 = OpTypeBool
3343 %13 = OpTypeFloat 32
3344 %14 = OpTypeInt 32 0
3345 %15 = OpConstant %14 10
3346 %16 = OpTypeArray %13 %15
3347 %17 = OpTypePointer Function %16
3348 %18 = OpTypePointer Function %13
3349 %19 = OpConstant %8 1
3350 %2 = OpFunction %6 None %7
3351 %20 = OpLabel
3352 %3 = OpVariable %9 Function
3353 %4 = OpVariable %17 Function
3354 %5 = OpVariable %17 Function
3355 OpStore %3 %10
3356 OpBranch %21
3357 %21 = OpLabel
3358 %22 = OpPhi %8 %10 %20 %23 %24
3359 OpLoopMerge %25 %24 None
3360 OpBranch %26
3361 %26 = OpLabel
3362 %27 = OpSLessThan %12 %22 %11
3363 OpBranchConditional %27 %28 %25
3364 %28 = OpLabel
3365 OpSelectionMerge %29 None
3366 OpSwitch %22 %30 1 %31
3367 %30 = OpLabel
3368 %32 = OpAccessChain %18 %4 %22
3369 %33 = OpLoad %13 %32
3370 %34 = OpAccessChain %18 %5 %22
3371 OpStore %34 %33
3372 OpBranch %29
3373 %31 = OpLabel
3374 %35 = OpAccessChain %18 %5 %22
3375 %36 = OpLoad %13 %35
3376 %37 = OpAccessChain %18 %4 %22
3377 OpStore %37 %36
3378 OpBranch %29
3379 %29 = OpLabel
3380 OpBranch %24
3381 %24 = OpLabel
3382 %23 = OpIAdd %8 %22 %19
3383 OpStore %3 %23
3384 OpBranch %21
3385 %25 = OpLabel
3386 OpReturn
3387 OpFunctionEnd
3388 )";
3389
3390 const std::string expected = R"(OpCapability Shader
3391 %1 = OpExtInstImport "GLSL.std.450"
3392 OpMemoryModel Logical GLSL450
3393 OpEntryPoint Fragment %2 "main"
3394 OpExecutionMode %2 OriginUpperLeft
3395 OpSource GLSL 430
3396 OpName %2 "main"
3397 OpName %3 "i"
3398 OpName %4 "B"
3399 OpName %5 "A"
3400 %6 = OpTypeVoid
3401 %7 = OpTypeFunction %6
3402 %8 = OpTypeInt 32 1
3403 %9 = OpTypePointer Function %8
3404 %10 = OpConstant %8 0
3405 %11 = OpConstant %8 10
3406 %12 = OpTypeBool
3407 %13 = OpTypeFloat 32
3408 %14 = OpTypeInt 32 0
3409 %15 = OpConstant %14 10
3410 %16 = OpTypeArray %13 %15
3411 %17 = OpTypePointer Function %16
3412 %18 = OpTypePointer Function %13
3413 %19 = OpConstant %8 1
3414 %2 = OpFunction %6 None %7
3415 %20 = OpLabel
3416 %3 = OpVariable %9 Function
3417 %4 = OpVariable %17 Function
3418 %5 = OpVariable %17 Function
3419 OpStore %3 %10
3420 OpBranch %38
3421 %38 = OpLabel
3422 %39 = OpPhi %8 %10 %20 %53 %52
3423 OpLoopMerge %54 %52 None
3424 OpBranch %40
3425 %40 = OpLabel
3426 %41 = OpSLessThan %12 %39 %11
3427 OpBranchConditional %41 %42 %54
3428 %42 = OpLabel
3429 OpSelectionMerge %51 None
3430 OpSwitch %39 %47 1 %43
3431 %43 = OpLabel
3432 OpBranch %51
3433 %47 = OpLabel
3434 %48 = OpAccessChain %18 %4 %39
3435 %49 = OpLoad %13 %48
3436 %50 = OpAccessChain %18 %5 %39
3437 OpStore %50 %49
3438 OpBranch %51
3439 %51 = OpLabel
3440 OpBranch %52
3441 %52 = OpLabel
3442 %53 = OpIAdd %8 %39 %19
3443 OpStore %3 %53
3444 OpBranch %38
3445 %54 = OpLabel
3446 OpBranch %21
3447 %21 = OpLabel
3448 %22 = OpPhi %8 %10 %54 %23 %24
3449 OpLoopMerge %25 %24 None
3450 OpBranch %26
3451 %26 = OpLabel
3452 %27 = OpSLessThan %12 %22 %11
3453 OpBranchConditional %27 %28 %25
3454 %28 = OpLabel
3455 OpSelectionMerge %29 None
3456 OpSwitch %22 %30 1 %31
3457 %30 = OpLabel
3458 OpBranch %29
3459 %31 = OpLabel
3460 %35 = OpAccessChain %18 %5 %22
3461 %36 = OpLoad %13 %35
3462 %37 = OpAccessChain %18 %4 %22
3463 OpStore %37 %36
3464 OpBranch %29
3465 %29 = OpLabel
3466 OpBranch %24
3467 %24 = OpLabel
3468 %23 = OpIAdd %8 %22 %19
3469 OpStore %3 %23
3470 OpBranch %21
3471 %25 = OpLabel
3472 OpReturn
3473 OpFunctionEnd
3474 )";
3475 // clang-format on
3476 std::unique_ptr<IRContext> context =
3477 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
3478 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3479 Module* module = context->module();
3480 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
3481 << source << std::endl;
3482
3483 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3484 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
3485 }
3486
3487 } // namespace
3488 } // namespace opt
3489 } // namespace spvtools
3490