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