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