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