Home | History | Annotate | Download | only in opt
      1 // Copyright (c) 2017 Valve Corporation
      2 // Copyright (c) 2017 LunarG Inc.
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //     http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 
     16 #include <memory>
     17 #include <string>
     18 
     19 #include "test/opt/pass_fixture.h"
     20 #include "test/opt/pass_utils.h"
     21 
     22 namespace spvtools {
     23 namespace opt {
     24 namespace {
     25 
     26 using LocalSSAElimTest = PassTest<::testing::Test>;
     27 
     28 TEST_F(LocalSSAElimTest, ForLoop) {
     29   // #version 140
     30   //
     31   // in vec4 BC;
     32   // out float fo;
     33   //
     34   // void main()
     35   // {
     36   //     float f = 0.0;
     37   //     for (int i=0; i<4; i++) {
     38   //       f = f + BC[i];
     39   //     }
     40   //     fo = f;
     41   // }
     42 
     43   const std::string predefs =
     44       R"(OpCapability Shader
     45 %1 = OpExtInstImport "GLSL.std.450"
     46 OpMemoryModel Logical GLSL450
     47 OpEntryPoint Fragment %main "main" %BC %fo
     48 OpExecutionMode %main OriginUpperLeft
     49 OpSource GLSL 140
     50 OpName %main "main"
     51 OpName %f "f"
     52 OpName %i "i"
     53 OpName %BC "BC"
     54 OpName %fo "fo"
     55 %void = OpTypeVoid
     56 %8 = OpTypeFunction %void
     57 %float = OpTypeFloat 32
     58 %_ptr_Function_float = OpTypePointer Function %float
     59 %float_0 = OpConstant %float 0
     60 %int = OpTypeInt 32 1
     61 %_ptr_Function_int = OpTypePointer Function %int
     62 %int_0 = OpConstant %int 0
     63 %int_4 = OpConstant %int 4
     64 %bool = OpTypeBool
     65 %v4float = OpTypeVector %float 4
     66 %_ptr_Input_v4float = OpTypePointer Input %v4float
     67 %BC = OpVariable %_ptr_Input_v4float Input
     68 %_ptr_Input_float = OpTypePointer Input %float
     69 %int_1 = OpConstant %int 1
     70 %_ptr_Output_float = OpTypePointer Output %float
     71 %fo = OpVariable %_ptr_Output_float Output
     72 )";
     73 
     74   const std::string before =
     75       R"(%main = OpFunction %void None %8
     76 %22 = OpLabel
     77 %f = OpVariable %_ptr_Function_float Function
     78 %i = OpVariable %_ptr_Function_int Function
     79 OpStore %f %float_0
     80 OpStore %i %int_0
     81 OpBranch %23
     82 %23 = OpLabel
     83 OpLoopMerge %24 %25 None
     84 OpBranch %26
     85 %26 = OpLabel
     86 %27 = OpLoad %int %i
     87 %28 = OpSLessThan %bool %27 %int_4
     88 OpBranchConditional %28 %29 %24
     89 %29 = OpLabel
     90 %30 = OpLoad %float %f
     91 %31 = OpLoad %int %i
     92 %32 = OpAccessChain %_ptr_Input_float %BC %31
     93 %33 = OpLoad %float %32
     94 %34 = OpFAdd %float %30 %33
     95 OpStore %f %34
     96 OpBranch %25
     97 %25 = OpLabel
     98 %35 = OpLoad %int %i
     99 %36 = OpIAdd %int %35 %int_1
    100 OpStore %i %36
    101 OpBranch %23
    102 %24 = OpLabel
    103 %37 = OpLoad %float %f
    104 OpStore %fo %37
    105 OpReturn
    106 OpFunctionEnd
    107 )";
    108 
    109   const std::string after =
    110       R"(%main = OpFunction %void None %8
    111 %22 = OpLabel
    112 %f = OpVariable %_ptr_Function_float Function
    113 %i = OpVariable %_ptr_Function_int Function
    114 OpStore %f %float_0
    115 OpStore %i %int_0
    116 OpBranch %23
    117 %23 = OpLabel
    118 %39 = OpPhi %float %float_0 %22 %34 %25
    119 %38 = OpPhi %int %int_0 %22 %36 %25
    120 OpLoopMerge %24 %25 None
    121 OpBranch %26
    122 %26 = OpLabel
    123 %28 = OpSLessThan %bool %38 %int_4
    124 OpBranchConditional %28 %29 %24
    125 %29 = OpLabel
    126 %32 = OpAccessChain %_ptr_Input_float %BC %38
    127 %33 = OpLoad %float %32
    128 %34 = OpFAdd %float %39 %33
    129 OpStore %f %34
    130 OpBranch %25
    131 %25 = OpLabel
    132 %36 = OpIAdd %int %38 %int_1
    133 OpStore %i %36
    134 OpBranch %23
    135 %24 = OpLabel
    136 OpStore %fo %39
    137 OpReturn
    138 OpFunctionEnd
    139 )";
    140 
    141   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
    142                                                  predefs + after, true, true);
    143 }
    144 
    145 TEST_F(LocalSSAElimTest, NestedForLoop) {
    146   // #version 450
    147   //
    148   // layout (location=0) in mat4 BC;
    149   // layout (location=0) out float fo;
    150   //
    151   // void main()
    152   // {
    153   //     float f = 0.0;
    154   //     for (int i=0; i<4; i++)
    155   //       for (int j=0; j<4; j++)
    156   //         f = f + BC[i][j];
    157   //     fo = f;
    158   // }
    159 
    160   const std::string predefs =
    161       R"(OpCapability Shader
    162 %1 = OpExtInstImport "GLSL.std.450"
    163 OpMemoryModel Logical GLSL450
    164 OpEntryPoint Fragment %main "main" %BC %fo
    165 OpExecutionMode %main OriginUpperLeft
    166 OpSource GLSL 450
    167 OpName %main "main"
    168 OpName %f "f"
    169 OpName %i "i"
    170 OpName %j "j"
    171 OpName %BC "BC"
    172 OpName %fo "fo"
    173 OpDecorate %BC Location 0
    174 OpDecorate %fo Location 0
    175 %void = OpTypeVoid
    176 %9 = OpTypeFunction %void
    177 %float = OpTypeFloat 32
    178 %_ptr_Function_float = OpTypePointer Function %float
    179 %float_0 = OpConstant %float 0
    180 %int = OpTypeInt 32 1
    181 %_ptr_Function_int = OpTypePointer Function %int
    182 %int_0 = OpConstant %int 0
    183 %int_4 = OpConstant %int 4
    184 %bool = OpTypeBool
    185 %v4float = OpTypeVector %float 4
    186 %mat4v4float = OpTypeMatrix %v4float 4
    187 %_ptr_Input_mat4v4float = OpTypePointer Input %mat4v4float
    188 %BC = OpVariable %_ptr_Input_mat4v4float Input
    189 %_ptr_Input_float = OpTypePointer Input %float
    190 %int_1 = OpConstant %int 1
    191 %_ptr_Output_float = OpTypePointer Output %float
    192 %fo = OpVariable %_ptr_Output_float Output
    193 )";
    194 
    195   const std::string before =
    196       R"(%main = OpFunction %void None %9
    197 %24 = OpLabel
    198 %f = OpVariable %_ptr_Function_float Function
    199 %i = OpVariable %_ptr_Function_int Function
    200 %j = OpVariable %_ptr_Function_int Function
    201 OpStore %f %float_0
    202 OpStore %i %int_0
    203 OpBranch %25
    204 %25 = OpLabel
    205 %26 = OpLoad %int %i
    206 %27 = OpSLessThan %bool %26 %int_4
    207 OpLoopMerge %28 %29 None
    208 OpBranchConditional %27 %30 %28
    209 %30 = OpLabel
    210 OpStore %j %int_0
    211 OpBranch %31
    212 %31 = OpLabel
    213 %32 = OpLoad %int %j
    214 %33 = OpSLessThan %bool %32 %int_4
    215 OpLoopMerge %29 %34 None
    216 OpBranchConditional %33 %34 %29
    217 %34 = OpLabel
    218 %35 = OpLoad %float %f
    219 %36 = OpLoad %int %i
    220 %37 = OpLoad %int %j
    221 %38 = OpAccessChain %_ptr_Input_float %BC %36 %37
    222 %39 = OpLoad %float %38
    223 %40 = OpFAdd %float %35 %39
    224 OpStore %f %40
    225 %41 = OpLoad %int %j
    226 %42 = OpIAdd %int %41 %int_1
    227 OpStore %j %42
    228 OpBranch %31
    229 %29 = OpLabel
    230 %43 = OpLoad %int %i
    231 %44 = OpIAdd %int %43 %int_1
    232 OpStore %i %44
    233 OpBranch %25
    234 %28 = OpLabel
    235 %45 = OpLoad %float %f
    236 OpStore %fo %45
    237 OpReturn
    238 OpFunctionEnd
    239 )";
    240 
    241   const std::string after =
    242       R"(%main = OpFunction %void None %9
    243 %24 = OpLabel
    244 %f = OpVariable %_ptr_Function_float Function
    245 %i = OpVariable %_ptr_Function_int Function
    246 %j = OpVariable %_ptr_Function_int Function
    247 OpStore %f %float_0
    248 OpStore %i %int_0
    249 OpBranch %25
    250 %25 = OpLabel
    251 %47 = OpPhi %float %float_0 %24 %50 %29
    252 %46 = OpPhi %int %int_0 %24 %44 %29
    253 %27 = OpSLessThan %bool %46 %int_4
    254 OpLoopMerge %28 %29 None
    255 OpBranchConditional %27 %30 %28
    256 %30 = OpLabel
    257 OpStore %j %int_0
    258 OpBranch %31
    259 %31 = OpLabel
    260 %50 = OpPhi %float %47 %30 %40 %34
    261 %48 = OpPhi %int %int_0 %30 %42 %34
    262 %33 = OpSLessThan %bool %48 %int_4
    263 OpLoopMerge %29 %34 None
    264 OpBranchConditional %33 %34 %29
    265 %34 = OpLabel
    266 %38 = OpAccessChain %_ptr_Input_float %BC %46 %48
    267 %39 = OpLoad %float %38
    268 %40 = OpFAdd %float %50 %39
    269 OpStore %f %40
    270 %42 = OpIAdd %int %48 %int_1
    271 OpStore %j %42
    272 OpBranch %31
    273 %29 = OpLabel
    274 %44 = OpIAdd %int %46 %int_1
    275 OpStore %i %44
    276 OpBranch %25
    277 %28 = OpLabel
    278 OpStore %fo %47
    279 OpReturn
    280 OpFunctionEnd
    281 )";
    282 
    283   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
    284                                                  predefs + after, true, true);
    285 }
    286 
    287 TEST_F(LocalSSAElimTest, ForLoopWithContinue) {
    288   // #version 140
    289   //
    290   // in vec4 BC;
    291   // out float fo;
    292   //
    293   // void main()
    294   // {
    295   //     float f = 0.0;
    296   //     for (int i=0; i<4; i++) {
    297   //       float t = BC[i];
    298   //       if (t < 0.0)
    299   //         continue;
    300   //       f = f + t;
    301   //     }
    302   //     fo = f;
    303   // }
    304 
    305   const std::string predefs =
    306       R"(OpCapability Shader
    307 %1 = OpExtInstImport "GLSL.std.450"
    308 OpMemoryModel Logical GLSL450
    309 OpEntryPoint Fragment %main "main" %BC %fo
    310 OpExecutionMode %main OriginUpperLeft
    311 OpSource GLSL 140
    312 )";
    313 
    314   const std::string names =
    315       R"(OpName %main "main"
    316 OpName %f "f"
    317 OpName %i "i"
    318 OpName %t "t"
    319 OpName %BC "BC"
    320 OpName %fo "fo"
    321 )";
    322 
    323   const std::string predefs2 =
    324       R"(%void = OpTypeVoid
    325 %9 = OpTypeFunction %void
    326 %float = OpTypeFloat 32
    327 %_ptr_Function_float = OpTypePointer Function %float
    328 %float_0 = OpConstant %float 0
    329 %int = OpTypeInt 32 1
    330 %_ptr_Function_int = OpTypePointer Function %int
    331 %int_0 = OpConstant %int 0
    332 %int_4 = OpConstant %int 4
    333 %bool = OpTypeBool
    334 %v4float = OpTypeVector %float 4
    335 %_ptr_Input_v4float = OpTypePointer Input %v4float
    336 %BC = OpVariable %_ptr_Input_v4float Input
    337 %_ptr_Input_float = OpTypePointer Input %float
    338 %int_1 = OpConstant %int 1
    339 %_ptr_Output_float = OpTypePointer Output %float
    340 %fo = OpVariable %_ptr_Output_float Output
    341 )";
    342 
    343   const std::string before =
    344       R"(%main = OpFunction %void None %9
    345 %23 = OpLabel
    346 %f = OpVariable %_ptr_Function_float Function
    347 %i = OpVariable %_ptr_Function_int Function
    348 %t = OpVariable %_ptr_Function_float Function
    349 OpStore %f %float_0
    350 OpStore %i %int_0
    351 OpBranch %24
    352 %24 = OpLabel
    353 OpLoopMerge %25 %26 None
    354 OpBranch %27
    355 %27 = OpLabel
    356 %28 = OpLoad %int %i
    357 %29 = OpSLessThan %bool %28 %int_4
    358 OpBranchConditional %29 %30 %25
    359 %30 = OpLabel
    360 %31 = OpLoad %int %i
    361 %32 = OpAccessChain %_ptr_Input_float %BC %31
    362 %33 = OpLoad %float %32
    363 OpStore %t %33
    364 %34 = OpLoad %float %t
    365 %35 = OpFOrdLessThan %bool %34 %float_0
    366 OpSelectionMerge %36 None
    367 OpBranchConditional %35 %37 %36
    368 %37 = OpLabel
    369 OpBranch %26
    370 %36 = OpLabel
    371 %38 = OpLoad %float %f
    372 %39 = OpLoad %float %t
    373 %40 = OpFAdd %float %38 %39
    374 OpStore %f %40
    375 OpBranch %26
    376 %26 = OpLabel
    377 %41 = OpLoad %int %i
    378 %42 = OpIAdd %int %41 %int_1
    379 OpStore %i %42
    380 OpBranch %24
    381 %25 = OpLabel
    382 %43 = OpLoad %float %f
    383 OpStore %fo %43
    384 OpReturn
    385 OpFunctionEnd
    386 )";
    387 
    388   const std::string after =
    389       R"(%main = OpFunction %void None %9
    390 %23 = OpLabel
    391 %f = OpVariable %_ptr_Function_float Function
    392 %i = OpVariable %_ptr_Function_int Function
    393 %t = OpVariable %_ptr_Function_float Function
    394 OpStore %f %float_0
    395 OpStore %i %int_0
    396 OpBranch %24
    397 %24 = OpLabel
    398 %45 = OpPhi %float %float_0 %23 %47 %26
    399 %44 = OpPhi %int %int_0 %23 %42 %26
    400 OpLoopMerge %25 %26 None
    401 OpBranch %27
    402 %27 = OpLabel
    403 %29 = OpSLessThan %bool %44 %int_4
    404 OpBranchConditional %29 %30 %25
    405 %30 = OpLabel
    406 %32 = OpAccessChain %_ptr_Input_float %BC %44
    407 %33 = OpLoad %float %32
    408 OpStore %t %33
    409 %35 = OpFOrdLessThan %bool %33 %float_0
    410 OpSelectionMerge %36 None
    411 OpBranchConditional %35 %37 %36
    412 %37 = OpLabel
    413 OpBranch %26
    414 %36 = OpLabel
    415 %40 = OpFAdd %float %45 %33
    416 OpStore %f %40
    417 OpBranch %26
    418 %26 = OpLabel
    419 %47 = OpPhi %float %45 %37 %40 %36
    420 %42 = OpIAdd %int %44 %int_1
    421 OpStore %i %42
    422 OpBranch %24
    423 %25 = OpLabel
    424 OpStore %fo %45
    425 OpReturn
    426 OpFunctionEnd
    427 )";
    428 
    429   SinglePassRunAndCheck<LocalMultiStoreElimPass>(
    430       predefs + names + predefs2 + before, predefs + names + predefs2 + after,
    431       true, true);
    432 }
    433 
    434 TEST_F(LocalSSAElimTest, ForLoopWithBreak) {
    435   // #version 140
    436   //
    437   // in vec4 BC;
    438   // out float fo;
    439   //
    440   // void main()
    441   // {
    442   //     float f = 0.0;
    443   //     for (int i=0; i<4; i++) {
    444   //       float t = f + BC[i];
    445   //       if (t > 1.0)
    446   //         break;
    447   //       f = t;
    448   //     }
    449   //     fo = f;
    450   // }
    451 
    452   const std::string predefs =
    453       R"(OpCapability Shader
    454 %1 = OpExtInstImport "GLSL.std.450"
    455 OpMemoryModel Logical GLSL450
    456 OpEntryPoint Fragment %main "main" %BC %fo
    457 OpExecutionMode %main OriginUpperLeft
    458 OpSource GLSL 140
    459 OpName %main "main"
    460 OpName %f "f"
    461 OpName %i "i"
    462 OpName %t "t"
    463 OpName %BC "BC"
    464 OpName %fo "fo"
    465 %void = OpTypeVoid
    466 %9 = OpTypeFunction %void
    467 %float = OpTypeFloat 32
    468 %_ptr_Function_float = OpTypePointer Function %float
    469 %float_0 = OpConstant %float 0
    470 %int = OpTypeInt 32 1
    471 %_ptr_Function_int = OpTypePointer Function %int
    472 %int_0 = OpConstant %int 0
    473 %int_4 = OpConstant %int 4
    474 %bool = OpTypeBool
    475 %v4float = OpTypeVector %float 4
    476 %_ptr_Input_v4float = OpTypePointer Input %v4float
    477 %BC = OpVariable %_ptr_Input_v4float Input
    478 %_ptr_Input_float = OpTypePointer Input %float
    479 %float_1 = OpConstant %float 1
    480 %int_1 = OpConstant %int 1
    481 %_ptr_Output_float = OpTypePointer Output %float
    482 %fo = OpVariable %_ptr_Output_float Output
    483 )";
    484 
    485   const std::string before =
    486       R"(%main = OpFunction %void None %9
    487 %24 = OpLabel
    488 %f = OpVariable %_ptr_Function_float Function
    489 %i = OpVariable %_ptr_Function_int Function
    490 %t = OpVariable %_ptr_Function_float Function
    491 OpStore %f %float_0
    492 OpStore %i %int_0
    493 OpBranch %25
    494 %25 = OpLabel
    495 OpLoopMerge %26 %27 None
    496 OpBranch %28
    497 %28 = OpLabel
    498 %29 = OpLoad %int %i
    499 %30 = OpSLessThan %bool %29 %int_4
    500 OpBranchConditional %30 %31 %26
    501 %31 = OpLabel
    502 %32 = OpLoad %float %f
    503 %33 = OpLoad %int %i
    504 %34 = OpAccessChain %_ptr_Input_float %BC %33
    505 %35 = OpLoad %float %34
    506 %36 = OpFAdd %float %32 %35
    507 OpStore %t %36
    508 %37 = OpLoad %float %t
    509 %38 = OpFOrdGreaterThan %bool %37 %float_1
    510 OpSelectionMerge %39 None
    511 OpBranchConditional %38 %40 %39
    512 %40 = OpLabel
    513 OpBranch %26
    514 %39 = OpLabel
    515 %41 = OpLoad %float %t
    516 OpStore %f %41
    517 OpBranch %27
    518 %27 = OpLabel
    519 %42 = OpLoad %int %i
    520 %43 = OpIAdd %int %42 %int_1
    521 OpStore %i %43
    522 OpBranch %25
    523 %26 = OpLabel
    524 %44 = OpLoad %float %f
    525 OpStore %fo %44
    526 OpReturn
    527 OpFunctionEnd
    528 )";
    529 
    530   const std::string after =
    531       R"(%main = OpFunction %void None %9
    532 %24 = OpLabel
    533 %f = OpVariable %_ptr_Function_float Function
    534 %i = OpVariable %_ptr_Function_int Function
    535 %t = OpVariable %_ptr_Function_float Function
    536 OpStore %f %float_0
    537 OpStore %i %int_0
    538 OpBranch %25
    539 %25 = OpLabel
    540 %46 = OpPhi %float %float_0 %24 %36 %27
    541 %45 = OpPhi %int %int_0 %24 %43 %27
    542 OpLoopMerge %26 %27 None
    543 OpBranch %28
    544 %28 = OpLabel
    545 %30 = OpSLessThan %bool %45 %int_4
    546 OpBranchConditional %30 %31 %26
    547 %31 = OpLabel
    548 %34 = OpAccessChain %_ptr_Input_float %BC %45
    549 %35 = OpLoad %float %34
    550 %36 = OpFAdd %float %46 %35
    551 OpStore %t %36
    552 %38 = OpFOrdGreaterThan %bool %36 %float_1
    553 OpSelectionMerge %39 None
    554 OpBranchConditional %38 %40 %39
    555 %40 = OpLabel
    556 OpBranch %26
    557 %39 = OpLabel
    558 OpStore %f %36
    559 OpBranch %27
    560 %27 = OpLabel
    561 %43 = OpIAdd %int %45 %int_1
    562 OpStore %i %43
    563 OpBranch %25
    564 %26 = OpLabel
    565 OpStore %fo %46
    566 OpReturn
    567 OpFunctionEnd
    568 )";
    569 
    570   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
    571                                                  predefs + after, true, true);
    572 }
    573 
    574 TEST_F(LocalSSAElimTest, SwapProblem) {
    575   // #version 140
    576   //
    577   // in float fe;
    578   // out float fo;
    579   //
    580   // void main()
    581   // {
    582   //     float f1 = 0.0;
    583   //     float f2 = 1.0;
    584   //     int ie = int(fe);
    585   //     for (int i=0; i<ie; i++) {
    586   //       float t = f1;
    587   //       f1 = f2;
    588   //       f2 = t;
    589   //     }
    590   //     fo = f1;
    591   // }
    592 
    593   const std::string predefs =
    594       R"(OpCapability Shader
    595 %1 = OpExtInstImport "GLSL.std.450"
    596 OpMemoryModel Logical GLSL450
    597 OpEntryPoint Fragment %main "main" %fe %fo
    598 OpExecutionMode %main OriginUpperLeft
    599 OpSource GLSL 140
    600 OpName %main "main"
    601 OpName %f1 "f1"
    602 OpName %f2 "f2"
    603 OpName %ie "ie"
    604 OpName %fe "fe"
    605 OpName %i "i"
    606 OpName %t "t"
    607 OpName %fo "fo"
    608 %void = OpTypeVoid
    609 %11 = OpTypeFunction %void
    610 %float = OpTypeFloat 32
    611 %_ptr_Function_float = OpTypePointer Function %float
    612 %float_0 = OpConstant %float 0
    613 %float_1 = OpConstant %float 1
    614 %int = OpTypeInt 32 1
    615 %_ptr_Function_int = OpTypePointer Function %int
    616 %_ptr_Input_float = OpTypePointer Input %float
    617 %fe = OpVariable %_ptr_Input_float Input
    618 %int_0 = OpConstant %int 0
    619 %bool = OpTypeBool
    620 %int_1 = OpConstant %int 1
    621 %_ptr_Output_float = OpTypePointer Output %float
    622 %fo = OpVariable %_ptr_Output_float Output
    623 )";
    624 
    625   const std::string before =
    626       R"(%main = OpFunction %void None %11
    627 %23 = OpLabel
    628 %f1 = OpVariable %_ptr_Function_float Function
    629 %f2 = OpVariable %_ptr_Function_float Function
    630 %ie = OpVariable %_ptr_Function_int Function
    631 %i = OpVariable %_ptr_Function_int Function
    632 %t = OpVariable %_ptr_Function_float Function
    633 OpStore %f1 %float_0
    634 OpStore %f2 %float_1
    635 %24 = OpLoad %float %fe
    636 %25 = OpConvertFToS %int %24
    637 OpStore %ie %25
    638 OpStore %i %int_0
    639 OpBranch %26
    640 %26 = OpLabel
    641 OpLoopMerge %27 %28 None
    642 OpBranch %29
    643 %29 = OpLabel
    644 %30 = OpLoad %int %i
    645 %31 = OpLoad %int %ie
    646 %32 = OpSLessThan %bool %30 %31
    647 OpBranchConditional %32 %33 %27
    648 %33 = OpLabel
    649 %34 = OpLoad %float %f1
    650 OpStore %t %34
    651 %35 = OpLoad %float %f2
    652 OpStore %f1 %35
    653 %36 = OpLoad %float %t
    654 OpStore %f2 %36
    655 OpBranch %28
    656 %28 = OpLabel
    657 %37 = OpLoad %int %i
    658 %38 = OpIAdd %int %37 %int_1
    659 OpStore %i %38
    660 OpBranch %26
    661 %27 = OpLabel
    662 %39 = OpLoad %float %f1
    663 OpStore %fo %39
    664 OpReturn
    665 OpFunctionEnd
    666 )";
    667 
    668   const std::string after =
    669       R"(%main = OpFunction %void None %11
    670 %23 = OpLabel
    671 %f1 = OpVariable %_ptr_Function_float Function
    672 %f2 = OpVariable %_ptr_Function_float Function
    673 %ie = OpVariable %_ptr_Function_int Function
    674 %i = OpVariable %_ptr_Function_int Function
    675 %t = OpVariable %_ptr_Function_float Function
    676 OpStore %f1 %float_0
    677 OpStore %f2 %float_1
    678 %24 = OpLoad %float %fe
    679 %25 = OpConvertFToS %int %24
    680 OpStore %ie %25
    681 OpStore %i %int_0
    682 OpBranch %26
    683 %26 = OpLabel
    684 %43 = OpPhi %float %float_1 %23 %42 %28
    685 %42 = OpPhi %float %float_0 %23 %43 %28
    686 %40 = OpPhi %int %int_0 %23 %38 %28
    687 OpLoopMerge %27 %28 None
    688 OpBranch %29
    689 %29 = OpLabel
    690 %32 = OpSLessThan %bool %40 %25
    691 OpBranchConditional %32 %33 %27
    692 %33 = OpLabel
    693 OpStore %t %42
    694 OpStore %f1 %43
    695 OpStore %f2 %42
    696 OpBranch %28
    697 %28 = OpLabel
    698 %38 = OpIAdd %int %40 %int_1
    699 OpStore %i %38
    700 OpBranch %26
    701 %27 = OpLabel
    702 OpStore %fo %42
    703 OpReturn
    704 OpFunctionEnd
    705 )";
    706 
    707   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
    708                                                  predefs + after, true, true);
    709 }
    710 
    711 TEST_F(LocalSSAElimTest, LostCopyProblem) {
    712   // #version 140
    713   //
    714   // in vec4 BC;
    715   // out float fo;
    716   //
    717   // void main()
    718   // {
    719   //     float f = 0.0;
    720   //     float t;
    721   //     for (int i=0; i<4; i++) {
    722   //       t = f;
    723   //       f = f + BC[i];
    724   //       if (f > 1.0)
    725   //         break;
    726   //     }
    727   //     fo = t;
    728   // }
    729 
    730   const std::string predefs =
    731       R"(OpCapability Shader
    732 %1 = OpExtInstImport "GLSL.std.450"
    733 OpMemoryModel Logical GLSL450
    734 OpEntryPoint Fragment %main "main" %BC %fo
    735 OpExecutionMode %main OriginUpperLeft
    736 OpSource GLSL 140
    737 OpName %main "main"
    738 OpName %f "f"
    739 OpName %i "i"
    740 OpName %t "t"
    741 OpName %BC "BC"
    742 OpName %fo "fo"
    743 %void = OpTypeVoid
    744 %9 = OpTypeFunction %void
    745 %float = OpTypeFloat 32
    746 %_ptr_Function_float = OpTypePointer Function %float
    747 %float_0 = OpConstant %float 0
    748 %int = OpTypeInt 32 1
    749 %_ptr_Function_int = OpTypePointer Function %int
    750 %int_0 = OpConstant %int 0
    751 %int_4 = OpConstant %int 4
    752 %bool = OpTypeBool
    753 %v4float = OpTypeVector %float 4
    754 %_ptr_Input_v4float = OpTypePointer Input %v4float
    755 %BC = OpVariable %_ptr_Input_v4float Input
    756 %_ptr_Input_float = OpTypePointer Input %float
    757 %float_1 = OpConstant %float 1
    758 %int_1 = OpConstant %int 1
    759 %_ptr_Output_float = OpTypePointer Output %float
    760 %fo = OpVariable %_ptr_Output_float Output
    761 )";
    762 
    763   const std::string before =
    764       R"(%main = OpFunction %void None %9
    765 %24 = OpLabel
    766 %f = OpVariable %_ptr_Function_float Function
    767 %i = OpVariable %_ptr_Function_int Function
    768 %t = OpVariable %_ptr_Function_float Function
    769 OpStore %f %float_0
    770 OpStore %i %int_0
    771 OpBranch %25
    772 %25 = OpLabel
    773 OpLoopMerge %26 %27 None
    774 OpBranch %28
    775 %28 = OpLabel
    776 %29 = OpLoad %int %i
    777 %30 = OpSLessThan %bool %29 %int_4
    778 OpBranchConditional %30 %31 %26
    779 %31 = OpLabel
    780 %32 = OpLoad %float %f
    781 OpStore %t %32
    782 %33 = OpLoad %float %f
    783 %34 = OpLoad %int %i
    784 %35 = OpAccessChain %_ptr_Input_float %BC %34
    785 %36 = OpLoad %float %35
    786 %37 = OpFAdd %float %33 %36
    787 OpStore %f %37
    788 %38 = OpLoad %float %f
    789 %39 = OpFOrdGreaterThan %bool %38 %float_1
    790 OpSelectionMerge %40 None
    791 OpBranchConditional %39 %41 %40
    792 %41 = OpLabel
    793 OpBranch %26
    794 %40 = OpLabel
    795 OpBranch %27
    796 %27 = OpLabel
    797 %42 = OpLoad %int %i
    798 %43 = OpIAdd %int %42 %int_1
    799 OpStore %i %43
    800 OpBranch %25
    801 %26 = OpLabel
    802 %44 = OpLoad %float %t
    803 OpStore %fo %44
    804 OpReturn
    805 OpFunctionEnd
    806 )";
    807 
    808   const std::string after =
    809       R"(%49 = OpUndef %float
    810 %main = OpFunction %void None %9
    811 %24 = OpLabel
    812 %f = OpVariable %_ptr_Function_float Function
    813 %i = OpVariable %_ptr_Function_int Function
    814 %t = OpVariable %_ptr_Function_float Function
    815 OpStore %f %float_0
    816 OpStore %i %int_0
    817 OpBranch %25
    818 %25 = OpLabel
    819 %46 = OpPhi %float %float_0 %24 %37 %27
    820 %45 = OpPhi %int %int_0 %24 %43 %27
    821 %48 = OpPhi %float %49 %24 %46 %27
    822 OpLoopMerge %26 %27 None
    823 OpBranch %28
    824 %28 = OpLabel
    825 %30 = OpSLessThan %bool %45 %int_4
    826 OpBranchConditional %30 %31 %26
    827 %31 = OpLabel
    828 OpStore %t %46
    829 %35 = OpAccessChain %_ptr_Input_float %BC %45
    830 %36 = OpLoad %float %35
    831 %37 = OpFAdd %float %46 %36
    832 OpStore %f %37
    833 %39 = OpFOrdGreaterThan %bool %37 %float_1
    834 OpSelectionMerge %40 None
    835 OpBranchConditional %39 %41 %40
    836 %41 = OpLabel
    837 OpBranch %26
    838 %40 = OpLabel
    839 OpBranch %27
    840 %27 = OpLabel
    841 %43 = OpIAdd %int %45 %int_1
    842 OpStore %i %43
    843 OpBranch %25
    844 %26 = OpLabel
    845 %47 = OpPhi %float %48 %28 %46 %41
    846 OpStore %fo %47
    847 OpReturn
    848 OpFunctionEnd
    849 )";
    850 
    851   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
    852                                                  predefs + after, true, true);
    853 }
    854 
    855 TEST_F(LocalSSAElimTest, IfThenElse) {
    856   // #version 140
    857   //
    858   // in vec4 BaseColor;
    859   // in float f;
    860   //
    861   // void main()
    862   // {
    863   //     vec4 v;
    864   //     if (f >= 0)
    865   //       v = BaseColor * 0.5;
    866   //     else
    867   //       v = BaseColor + vec4(1.0,1.0,1.0,1.0);
    868   //     gl_FragColor = v;
    869   // }
    870 
    871   const std::string predefs =
    872       R"(OpCapability Shader
    873 %1 = OpExtInstImport "GLSL.std.450"
    874 OpMemoryModel Logical GLSL450
    875 OpEntryPoint Fragment %main "main" %f %BaseColor %gl_FragColor
    876 OpExecutionMode %main OriginUpperLeft
    877 OpSource GLSL 140
    878 OpName %main "main"
    879 OpName %f "f"
    880 OpName %v "v"
    881 OpName %BaseColor "BaseColor"
    882 OpName %gl_FragColor "gl_FragColor"
    883 %void = OpTypeVoid
    884 %8 = OpTypeFunction %void
    885 %float = OpTypeFloat 32
    886 %_ptr_Input_float = OpTypePointer Input %float
    887 %f = OpVariable %_ptr_Input_float Input
    888 %float_0 = OpConstant %float 0
    889 %bool = OpTypeBool
    890 %v4float = OpTypeVector %float 4
    891 %_ptr_Function_v4float = OpTypePointer Function %v4float
    892 %_ptr_Input_v4float = OpTypePointer Input %v4float
    893 %BaseColor = OpVariable %_ptr_Input_v4float Input
    894 %float_0_5 = OpConstant %float 0.5
    895 %float_1 = OpConstant %float 1
    896 %18 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
    897 %_ptr_Output_v4float = OpTypePointer Output %v4float
    898 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
    899 )";
    900 
    901   const std::string before =
    902       R"(%main = OpFunction %void None %8
    903 %20 = OpLabel
    904 %v = OpVariable %_ptr_Function_v4float Function
    905 %21 = OpLoad %float %f
    906 %22 = OpFOrdGreaterThanEqual %bool %21 %float_0
    907 OpSelectionMerge %23 None
    908 OpBranchConditional %22 %24 %25
    909 %24 = OpLabel
    910 %26 = OpLoad %v4float %BaseColor
    911 %27 = OpVectorTimesScalar %v4float %26 %float_0_5
    912 OpStore %v %27
    913 OpBranch %23
    914 %25 = OpLabel
    915 %28 = OpLoad %v4float %BaseColor
    916 %29 = OpFAdd %v4float %28 %18
    917 OpStore %v %29
    918 OpBranch %23
    919 %23 = OpLabel
    920 %30 = OpLoad %v4float %v
    921 OpStore %gl_FragColor %30
    922 OpReturn
    923 OpFunctionEnd
    924 )";
    925 
    926   const std::string after =
    927       R"(%main = OpFunction %void None %8
    928 %20 = OpLabel
    929 %v = OpVariable %_ptr_Function_v4float Function
    930 %21 = OpLoad %float %f
    931 %22 = OpFOrdGreaterThanEqual %bool %21 %float_0
    932 OpSelectionMerge %23 None
    933 OpBranchConditional %22 %24 %25
    934 %24 = OpLabel
    935 %26 = OpLoad %v4float %BaseColor
    936 %27 = OpVectorTimesScalar %v4float %26 %float_0_5
    937 OpStore %v %27
    938 OpBranch %23
    939 %25 = OpLabel
    940 %28 = OpLoad %v4float %BaseColor
    941 %29 = OpFAdd %v4float %28 %18
    942 OpStore %v %29
    943 OpBranch %23
    944 %23 = OpLabel
    945 %31 = OpPhi %v4float %27 %24 %29 %25
    946 OpStore %gl_FragColor %31
    947 OpReturn
    948 OpFunctionEnd
    949 )";
    950 
    951   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
    952                                                  predefs + after, true, true);
    953 }
    954 
    955 TEST_F(LocalSSAElimTest, IfThen) {
    956   // #version 140
    957   //
    958   // in vec4 BaseColor;
    959   // in float f;
    960   //
    961   // void main()
    962   // {
    963   //     vec4 v = BaseColor;
    964   //     if (f <= 0)
    965   //       v = v * 0.5;
    966   //     gl_FragColor = v;
    967   // }
    968 
    969   const std::string predefs =
    970       R"(OpCapability Shader
    971 %1 = OpExtInstImport "GLSL.std.450"
    972 OpMemoryModel Logical GLSL450
    973 OpEntryPoint Fragment %main "main" %BaseColor %f %gl_FragColor
    974 OpExecutionMode %main OriginUpperLeft
    975 OpSource GLSL 140
    976 OpName %main "main"
    977 OpName %v "v"
    978 OpName %BaseColor "BaseColor"
    979 OpName %f "f"
    980 OpName %gl_FragColor "gl_FragColor"
    981 %void = OpTypeVoid
    982 %8 = OpTypeFunction %void
    983 %float = OpTypeFloat 32
    984 %v4float = OpTypeVector %float 4
    985 %_ptr_Function_v4float = OpTypePointer Function %v4float
    986 %_ptr_Input_v4float = OpTypePointer Input %v4float
    987 %BaseColor = OpVariable %_ptr_Input_v4float Input
    988 %_ptr_Input_float = OpTypePointer Input %float
    989 %f = OpVariable %_ptr_Input_float Input
    990 %float_0 = OpConstant %float 0
    991 %bool = OpTypeBool
    992 %float_0_5 = OpConstant %float 0.5
    993 %_ptr_Output_v4float = OpTypePointer Output %v4float
    994 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
    995 )";
    996 
    997   const std::string before =
    998       R"(%main = OpFunction %void None %8
    999 %18 = OpLabel
   1000 %v = OpVariable %_ptr_Function_v4float Function
   1001 %19 = OpLoad %v4float %BaseColor
   1002 OpStore %v %19
   1003 %20 = OpLoad %float %f
   1004 %21 = OpFOrdLessThanEqual %bool %20 %float_0
   1005 OpSelectionMerge %22 None
   1006 OpBranchConditional %21 %23 %22
   1007 %23 = OpLabel
   1008 %24 = OpLoad %v4float %v
   1009 %25 = OpVectorTimesScalar %v4float %24 %float_0_5
   1010 OpStore %v %25
   1011 OpBranch %22
   1012 %22 = OpLabel
   1013 %26 = OpLoad %v4float %v
   1014 OpStore %gl_FragColor %26
   1015 OpReturn
   1016 OpFunctionEnd
   1017 )";
   1018 
   1019   const std::string after =
   1020       R"(%main = OpFunction %void None %8
   1021 %18 = OpLabel
   1022 %v = OpVariable %_ptr_Function_v4float Function
   1023 %19 = OpLoad %v4float %BaseColor
   1024 OpStore %v %19
   1025 %20 = OpLoad %float %f
   1026 %21 = OpFOrdLessThanEqual %bool %20 %float_0
   1027 OpSelectionMerge %22 None
   1028 OpBranchConditional %21 %23 %22
   1029 %23 = OpLabel
   1030 %25 = OpVectorTimesScalar %v4float %19 %float_0_5
   1031 OpStore %v %25
   1032 OpBranch %22
   1033 %22 = OpLabel
   1034 %27 = OpPhi %v4float %19 %18 %25 %23
   1035 OpStore %gl_FragColor %27
   1036 OpReturn
   1037 OpFunctionEnd
   1038 )";
   1039 
   1040   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
   1041                                                  predefs + after, true, true);
   1042 }
   1043 
   1044 TEST_F(LocalSSAElimTest, Switch) {
   1045   // #version 140
   1046   //
   1047   // in vec4 BaseColor;
   1048   // in float f;
   1049   //
   1050   // void main()
   1051   // {
   1052   //     vec4 v = BaseColor;
   1053   //     int i = int(f);
   1054   //     switch (i) {
   1055   //       case 0:
   1056   //         v = v * 0.25;
   1057   //         break;
   1058   //       case 1:
   1059   //         v = v * 0.625;
   1060   //         break;
   1061   //       case 2:
   1062   //         v = v * 0.75;
   1063   //         break;
   1064   //       default:
   1065   //         break;
   1066   //     }
   1067   //     gl_FragColor = v;
   1068   // }
   1069 
   1070   const std::string predefs =
   1071       R"(OpCapability Shader
   1072 %1 = OpExtInstImport "GLSL.std.450"
   1073 OpMemoryModel Logical GLSL450
   1074 OpEntryPoint Fragment %main "main" %BaseColor %f %gl_FragColor
   1075 OpExecutionMode %main OriginUpperLeft
   1076 OpSource GLSL 140
   1077 OpName %main "main"
   1078 OpName %v "v"
   1079 OpName %BaseColor "BaseColor"
   1080 OpName %i "i"
   1081 OpName %f "f"
   1082 OpName %gl_FragColor "gl_FragColor"
   1083 %void = OpTypeVoid
   1084 %9 = OpTypeFunction %void
   1085 %float = OpTypeFloat 32
   1086 %v4float = OpTypeVector %float 4
   1087 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1088 %_ptr_Input_v4float = OpTypePointer Input %v4float
   1089 %BaseColor = OpVariable %_ptr_Input_v4float Input
   1090 %int = OpTypeInt 32 1
   1091 %_ptr_Function_int = OpTypePointer Function %int
   1092 %_ptr_Input_float = OpTypePointer Input %float
   1093 %f = OpVariable %_ptr_Input_float Input
   1094 %float_0_25 = OpConstant %float 0.25
   1095 %float_0_625 = OpConstant %float 0.625
   1096 %float_0_75 = OpConstant %float 0.75
   1097 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1098 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
   1099 )";
   1100 
   1101   const std::string before =
   1102       R"(%main = OpFunction %void None %9
   1103 %21 = OpLabel
   1104 %v = OpVariable %_ptr_Function_v4float Function
   1105 %i = OpVariable %_ptr_Function_int Function
   1106 %22 = OpLoad %v4float %BaseColor
   1107 OpStore %v %22
   1108 %23 = OpLoad %float %f
   1109 %24 = OpConvertFToS %int %23
   1110 OpStore %i %24
   1111 %25 = OpLoad %int %i
   1112 OpSelectionMerge %26 None
   1113 OpSwitch %25 %27 0 %28 1 %29 2 %30
   1114 %27 = OpLabel
   1115 OpBranch %26
   1116 %28 = OpLabel
   1117 %31 = OpLoad %v4float %v
   1118 %32 = OpVectorTimesScalar %v4float %31 %float_0_25
   1119 OpStore %v %32
   1120 OpBranch %26
   1121 %29 = OpLabel
   1122 %33 = OpLoad %v4float %v
   1123 %34 = OpVectorTimesScalar %v4float %33 %float_0_625
   1124 OpStore %v %34
   1125 OpBranch %26
   1126 %30 = OpLabel
   1127 %35 = OpLoad %v4float %v
   1128 %36 = OpVectorTimesScalar %v4float %35 %float_0_75
   1129 OpStore %v %36
   1130 OpBranch %26
   1131 %26 = OpLabel
   1132 %37 = OpLoad %v4float %v
   1133 OpStore %gl_FragColor %37
   1134 OpReturn
   1135 OpFunctionEnd
   1136 )";
   1137 
   1138   const std::string after =
   1139       R"(%main = OpFunction %void None %9
   1140 %21 = OpLabel
   1141 %v = OpVariable %_ptr_Function_v4float Function
   1142 %i = OpVariable %_ptr_Function_int Function
   1143 %22 = OpLoad %v4float %BaseColor
   1144 OpStore %v %22
   1145 %23 = OpLoad %float %f
   1146 %24 = OpConvertFToS %int %23
   1147 OpStore %i %24
   1148 OpSelectionMerge %26 None
   1149 OpSwitch %24 %27 0 %28 1 %29 2 %30
   1150 %27 = OpLabel
   1151 OpBranch %26
   1152 %28 = OpLabel
   1153 %32 = OpVectorTimesScalar %v4float %22 %float_0_25
   1154 OpStore %v %32
   1155 OpBranch %26
   1156 %29 = OpLabel
   1157 %34 = OpVectorTimesScalar %v4float %22 %float_0_625
   1158 OpStore %v %34
   1159 OpBranch %26
   1160 %30 = OpLabel
   1161 %36 = OpVectorTimesScalar %v4float %22 %float_0_75
   1162 OpStore %v %36
   1163 OpBranch %26
   1164 %26 = OpLabel
   1165 %38 = OpPhi %v4float %22 %27 %32 %28 %34 %29 %36 %30
   1166 OpStore %gl_FragColor %38
   1167 OpReturn
   1168 OpFunctionEnd
   1169 )";
   1170 
   1171   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
   1172                                                  predefs + after, true, true);
   1173 }
   1174 
   1175 TEST_F(LocalSSAElimTest, SwitchWithFallThrough) {
   1176   // #version 140
   1177   //
   1178   // in vec4 BaseColor;
   1179   // in float f;
   1180   //
   1181   // void main()
   1182   // {
   1183   //     vec4 v = BaseColor;
   1184   //     int i = int(f);
   1185   //     switch (i) {
   1186   //       case 0:
   1187   //         v = v * 0.25;
   1188   //         break;
   1189   //       case 1:
   1190   //         v = v + 0.25;
   1191   //       case 2:
   1192   //         v = v * 0.75;
   1193   //         break;
   1194   //       default:
   1195   //         break;
   1196   //     }
   1197   //     gl_FragColor = v;
   1198   // }
   1199 
   1200   const std::string predefs =
   1201       R"(OpCapability Shader
   1202 %1 = OpExtInstImport "GLSL.std.450"
   1203 OpMemoryModel Logical GLSL450
   1204 OpEntryPoint Fragment %main "main" %BaseColor %f %gl_FragColor
   1205 OpExecutionMode %main OriginUpperLeft
   1206 OpSource GLSL 140
   1207 OpName %main "main"
   1208 OpName %v "v"
   1209 OpName %BaseColor "BaseColor"
   1210 OpName %i "i"
   1211 OpName %f "f"
   1212 OpName %gl_FragColor "gl_FragColor"
   1213 %void = OpTypeVoid
   1214 %9 = OpTypeFunction %void
   1215 %float = OpTypeFloat 32
   1216 %v4float = OpTypeVector %float 4
   1217 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1218 %_ptr_Input_v4float = OpTypePointer Input %v4float
   1219 %BaseColor = OpVariable %_ptr_Input_v4float Input
   1220 %int = OpTypeInt 32 1
   1221 %_ptr_Function_int = OpTypePointer Function %int
   1222 %_ptr_Input_float = OpTypePointer Input %float
   1223 %f = OpVariable %_ptr_Input_float Input
   1224 %float_0_25 = OpConstant %float 0.25
   1225 %float_0_75 = OpConstant %float 0.75
   1226 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1227 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
   1228 )";
   1229 
   1230   const std::string before =
   1231       R"(%main = OpFunction %void None %9
   1232 %20 = OpLabel
   1233 %v = OpVariable %_ptr_Function_v4float Function
   1234 %i = OpVariable %_ptr_Function_int Function
   1235 %21 = OpLoad %v4float %BaseColor
   1236 OpStore %v %21
   1237 %22 = OpLoad %float %f
   1238 %23 = OpConvertFToS %int %22
   1239 OpStore %i %23
   1240 %24 = OpLoad %int %i
   1241 OpSelectionMerge %25 None
   1242 OpSwitch %24 %26 0 %27 1 %28 2 %29
   1243 %26 = OpLabel
   1244 OpBranch %25
   1245 %27 = OpLabel
   1246 %30 = OpLoad %v4float %v
   1247 %31 = OpVectorTimesScalar %v4float %30 %float_0_25
   1248 OpStore %v %31
   1249 OpBranch %25
   1250 %28 = OpLabel
   1251 %32 = OpLoad %v4float %v
   1252 %33 = OpCompositeConstruct %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
   1253 %34 = OpFAdd %v4float %32 %33
   1254 OpStore %v %34
   1255 OpBranch %29
   1256 %29 = OpLabel
   1257 %35 = OpLoad %v4float %v
   1258 %36 = OpVectorTimesScalar %v4float %35 %float_0_75
   1259 OpStore %v %36
   1260 OpBranch %25
   1261 %25 = OpLabel
   1262 %37 = OpLoad %v4float %v
   1263 OpStore %gl_FragColor %37
   1264 OpReturn
   1265 OpFunctionEnd
   1266 )";
   1267 
   1268   const std::string after =
   1269       R"(%main = OpFunction %void None %9
   1270 %20 = OpLabel
   1271 %v = OpVariable %_ptr_Function_v4float Function
   1272 %i = OpVariable %_ptr_Function_int Function
   1273 %21 = OpLoad %v4float %BaseColor
   1274 OpStore %v %21
   1275 %22 = OpLoad %float %f
   1276 %23 = OpConvertFToS %int %22
   1277 OpStore %i %23
   1278 OpSelectionMerge %25 None
   1279 OpSwitch %23 %26 0 %27 1 %28 2 %29
   1280 %26 = OpLabel
   1281 OpBranch %25
   1282 %27 = OpLabel
   1283 %31 = OpVectorTimesScalar %v4float %21 %float_0_25
   1284 OpStore %v %31
   1285 OpBranch %25
   1286 %28 = OpLabel
   1287 %33 = OpCompositeConstruct %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
   1288 %34 = OpFAdd %v4float %21 %33
   1289 OpStore %v %34
   1290 OpBranch %29
   1291 %29 = OpLabel
   1292 %38 = OpPhi %v4float %21 %20 %34 %28
   1293 %36 = OpVectorTimesScalar %v4float %38 %float_0_75
   1294 OpStore %v %36
   1295 OpBranch %25
   1296 %25 = OpLabel
   1297 %39 = OpPhi %v4float %21 %26 %31 %27 %36 %29
   1298 OpStore %gl_FragColor %39
   1299 OpReturn
   1300 OpFunctionEnd
   1301 )";
   1302 
   1303   SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
   1304                                                  predefs + after, true, true);
   1305 }
   1306 
   1307 TEST_F(LocalSSAElimTest, DontPatchPhiInLoopHeaderThatIsNotAVar) {
   1308   // From https://github.com/KhronosGroup/SPIRV-Tools/issues/826
   1309   // Don't try patching the (%16 %7) value/predecessor pair in the OpPhi.
   1310   // That OpPhi is unrelated to this optimization: we did not set that up
   1311   // in the SSA initialization for the loop header block.
   1312   // The pass should be a no-op on this module.
   1313 
   1314   const std::string before = R"(OpCapability Shader
   1315 OpMemoryModel Logical GLSL450
   1316 OpEntryPoint GLCompute %1 "main"
   1317 %void = OpTypeVoid
   1318 %3 = OpTypeFunction %void
   1319 %float = OpTypeFloat 32
   1320 %float_1 = OpConstant %float 1
   1321 %1 = OpFunction %void None %3
   1322 %6 = OpLabel
   1323 OpBranch %7
   1324 %7 = OpLabel
   1325 %8 = OpPhi %float %float_1 %6 %9 %7
   1326 %9 = OpFAdd %float %8 %float_1
   1327 OpLoopMerge %10 %7 None
   1328 OpBranch %7
   1329 %10 = OpLabel
   1330 OpReturn
   1331 OpFunctionEnd
   1332 )";
   1333 
   1334   SinglePassRunAndCheck<LocalMultiStoreElimPass>(before, before, true, true);
   1335 }
   1336 
   1337 TEST_F(LocalSSAElimTest, OptInitializedVariableLikeStore) {
   1338   // Note: SPIR-V edited to change store to v into variable initialization
   1339   //
   1340   // #version 450
   1341   //
   1342   // layout (location=0) in vec4 iColor;
   1343   // layout (location=1) in float fi;
   1344   // layout (location=0) out vec4 oColor;
   1345   //
   1346   // void main()
   1347   // {
   1348   //     vec4 v = vec4(0.0);
   1349   //     if (fi < 0.0)
   1350   //       v.x = iColor.x;
   1351   //     oColor = v;
   1352   // }
   1353 
   1354   const std::string predefs =
   1355       R"(OpCapability Shader
   1356 %1 = OpExtInstImport "GLSL.std.450"
   1357 OpMemoryModel Logical GLSL450
   1358 OpEntryPoint Fragment %main "main" %fi %iColor %oColor
   1359 OpExecutionMode %main OriginUpperLeft
   1360 OpSource GLSL 450
   1361 OpName %main "main"
   1362 OpName %v "v"
   1363 OpName %fi "fi"
   1364 OpName %iColor "iColor"
   1365 OpName %oColor "oColor"
   1366 OpDecorate %fi Location 1
   1367 OpDecorate %iColor Location 0
   1368 OpDecorate %oColor Location 0
   1369 %void = OpTypeVoid
   1370 %8 = OpTypeFunction %void
   1371 %float = OpTypeFloat 32
   1372 %v4float = OpTypeVector %float 4
   1373 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1374 %float_0 = OpConstant %float 0
   1375 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
   1376 %_ptr_Input_float = OpTypePointer Input %float
   1377 %fi = OpVariable %_ptr_Input_float Input
   1378 %bool = OpTypeBool
   1379 %_ptr_Input_v4float = OpTypePointer Input %v4float
   1380 %iColor = OpVariable %_ptr_Input_v4float Input
   1381 %uint = OpTypeInt 32 0
   1382 %uint_0 = OpConstant %uint 0
   1383 %_ptr_Function_float = OpTypePointer Function %float
   1384 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1385 %oColor = OpVariable %_ptr_Output_v4float Output
   1386 )";
   1387 
   1388   const std::string func_before =
   1389       R"(%main = OpFunction %void None %8
   1390 %21 = OpLabel
   1391 %v = OpVariable %_ptr_Function_v4float Function %13
   1392 %22 = OpLoad %float %fi
   1393 %23 = OpFOrdLessThan %bool %22 %float_0
   1394 OpSelectionMerge %24 None
   1395 OpBranchConditional %23 %25 %24
   1396 %25 = OpLabel
   1397 %26 = OpAccessChain %_ptr_Input_float %iColor %uint_0
   1398 %27 = OpLoad %float %26
   1399 %28 = OpLoad %v4float %v
   1400 %29 = OpCompositeInsert %v4float %27 %28 0
   1401 OpStore %v %29
   1402 OpBranch %24
   1403 %24 = OpLabel
   1404 %30 = OpLoad %v4float %v
   1405 OpStore %oColor %30
   1406 OpReturn
   1407 OpFunctionEnd
   1408 )";
   1409 
   1410   const std::string func_after =
   1411       R"(%main = OpFunction %void None %8
   1412 %21 = OpLabel
   1413 %v = OpVariable %_ptr_Function_v4float Function %13
   1414 %22 = OpLoad %float %fi
   1415 %23 = OpFOrdLessThan %bool %22 %float_0
   1416 OpSelectionMerge %24 None
   1417 OpBranchConditional %23 %25 %24
   1418 %25 = OpLabel
   1419 %26 = OpAccessChain %_ptr_Input_float %iColor %uint_0
   1420 %27 = OpLoad %float %26
   1421 %29 = OpCompositeInsert %v4float %27 %13 0
   1422 OpStore %v %29
   1423 OpBranch %24
   1424 %24 = OpLabel
   1425 %31 = OpPhi %v4float %13 %21 %29 %25
   1426 OpStore %oColor %31
   1427 OpReturn
   1428 OpFunctionEnd
   1429 )";
   1430 
   1431   SinglePassRunAndCheck<LocalMultiStoreElimPass>(
   1432       predefs + func_before, predefs + func_after, true, true);
   1433 }
   1434 
   1435 TEST_F(LocalSSAElimTest, PointerVariable) {
   1436   // Test that checks if a pointer variable is removed.
   1437 
   1438   const std::string before =
   1439       R"(OpCapability Shader
   1440 OpMemoryModel Logical GLSL450
   1441 OpEntryPoint Fragment %1 "main" %2
   1442 OpExecutionMode %1 OriginUpperLeft
   1443 OpMemberDecorate %_struct_3 0 Offset 0
   1444 OpDecorate %_runtimearr__struct_3 ArrayStride 16
   1445 OpMemberDecorate %_struct_5 0 Offset 0
   1446 OpDecorate %_struct_5 BufferBlock
   1447 OpMemberDecorate %_struct_6 0 Offset 0
   1448 OpDecorate %_struct_6 BufferBlock
   1449 OpDecorate %2 Location 0
   1450 OpDecorate %7 DescriptorSet 0
   1451 OpDecorate %7 Binding 0
   1452 %void = OpTypeVoid
   1453 %10 = OpTypeFunction %void
   1454 %int = OpTypeInt 32 1
   1455 %uint = OpTypeInt 32 0
   1456 %float = OpTypeFloat 32
   1457 %v4float = OpTypeVector %float 4
   1458 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1459 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
   1460 %_struct_3 = OpTypeStruct %v4float
   1461 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
   1462 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
   1463 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
   1464 %_struct_6 = OpTypeStruct %int
   1465 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
   1466 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5
   1467 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6
   1468 %int_0 = OpConstant %int 0
   1469 %uint_0 = OpConstant %uint 0
   1470 %2 = OpVariable %_ptr_Output_v4float Output
   1471 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform
   1472 %1 = OpFunction %void None %10
   1473 %23 = OpLabel
   1474 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function
   1475 OpStore %24 %7
   1476 %26 = OpLoad %_ptr_Uniform__struct_5 %24
   1477 %27 = OpAccessChain %_ptr_Uniform_v4float %26 %int_0 %uint_0 %int_0
   1478 %28 = OpLoad %v4float %27
   1479 %29 = OpCopyObject %v4float %28
   1480 OpStore %2 %28
   1481 OpReturn
   1482 OpFunctionEnd
   1483 )";
   1484 
   1485   const std::string after =
   1486       R"(OpCapability Shader
   1487 OpMemoryModel Logical GLSL450
   1488 OpEntryPoint Fragment %1 "main" %2
   1489 OpExecutionMode %1 OriginUpperLeft
   1490 OpMemberDecorate %_struct_3 0 Offset 0
   1491 OpDecorate %_runtimearr__struct_3 ArrayStride 16
   1492 OpMemberDecorate %_struct_5 0 Offset 0
   1493 OpDecorate %_struct_5 BufferBlock
   1494 OpMemberDecorate %_struct_6 0 Offset 0
   1495 OpDecorate %_struct_6 BufferBlock
   1496 OpDecorate %2 Location 0
   1497 OpDecorate %7 DescriptorSet 0
   1498 OpDecorate %7 Binding 0
   1499 %void = OpTypeVoid
   1500 %10 = OpTypeFunction %void
   1501 %int = OpTypeInt 32 1
   1502 %uint = OpTypeInt 32 0
   1503 %float = OpTypeFloat 32
   1504 %v4float = OpTypeVector %float 4
   1505 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1506 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
   1507 %_struct_3 = OpTypeStruct %v4float
   1508 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
   1509 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
   1510 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
   1511 %_struct_6 = OpTypeStruct %int
   1512 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
   1513 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5
   1514 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6
   1515 %int_0 = OpConstant %int 0
   1516 %uint_0 = OpConstant %uint 0
   1517 %2 = OpVariable %_ptr_Output_v4float Output
   1518 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform
   1519 %1 = OpFunction %void None %10
   1520 %23 = OpLabel
   1521 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function
   1522 OpStore %24 %7
   1523 %27 = OpAccessChain %_ptr_Uniform_v4float %7 %int_0 %uint_0 %int_0
   1524 %28 = OpLoad %v4float %27
   1525 %29 = OpCopyObject %v4float %28
   1526 OpStore %2 %28
   1527 OpReturn
   1528 OpFunctionEnd
   1529 )";
   1530 
   1531   // Relax logical pointers to allow pointer allocations.
   1532   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1533   ValidatorOptions()->relax_logical_pointer = true;
   1534   SinglePassRunAndCheck<LocalMultiStoreElimPass>(before, after, true, true);
   1535 }
   1536 
   1537 TEST_F(LocalSSAElimTest, VerifyInstToBlockMap) {
   1538   // #version 140
   1539   //
   1540   // in vec4 BC;
   1541   // out float fo;
   1542   //
   1543   // void main()
   1544   // {
   1545   //     float f = 0.0;
   1546   //     for (int i=0; i<4; i++) {
   1547   //       f = f + BC[i];
   1548   //     }
   1549   //     fo = f;
   1550   // }
   1551 
   1552   const std::string text = R"(
   1553 OpCapability Shader
   1554 %1 = OpExtInstImport "GLSL.std.450"
   1555 OpMemoryModel Logical GLSL450
   1556 OpEntryPoint Fragment %main "main" %BC %fo
   1557 OpExecutionMode %main OriginUpperLeft
   1558 OpSource GLSL 140
   1559 OpName %main "main"
   1560 OpName %f "f"
   1561 OpName %i "i"
   1562 OpName %BC "BC"
   1563 OpName %fo "fo"
   1564 %void = OpTypeVoid
   1565 %8 = OpTypeFunction %void
   1566 %float = OpTypeFloat 32
   1567 %_ptr_Function_float = OpTypePointer Function %float
   1568 %float_0 = OpConstant %float 0
   1569 %int = OpTypeInt 32 1
   1570 %_ptr_Function_int = OpTypePointer Function %int
   1571 %int_0 = OpConstant %int 0
   1572 %int_4 = OpConstant %int 4
   1573 %bool = OpTypeBool
   1574 %v4float = OpTypeVector %float 4
   1575 %_ptr_Input_v4float = OpTypePointer Input %v4float
   1576 %BC = OpVariable %_ptr_Input_v4float Input
   1577 %_ptr_Input_float = OpTypePointer Input %float
   1578 %int_1 = OpConstant %int 1
   1579 %_ptr_Output_float = OpTypePointer Output %float
   1580 %fo = OpVariable %_ptr_Output_float Output
   1581 %main = OpFunction %void None %8
   1582 %22 = OpLabel
   1583 %f = OpVariable %_ptr_Function_float Function
   1584 %i = OpVariable %_ptr_Function_int Function
   1585 OpStore %f %float_0
   1586 OpStore %i %int_0
   1587 OpBranch %23
   1588 %23 = OpLabel
   1589 OpLoopMerge %24 %25 None
   1590 OpBranch %26
   1591 %26 = OpLabel
   1592 %27 = OpLoad %int %i
   1593 %28 = OpSLessThan %bool %27 %int_4
   1594 OpBranchConditional %28 %29 %24
   1595 %29 = OpLabel
   1596 %30 = OpLoad %float %f
   1597 %31 = OpLoad %int %i
   1598 %32 = OpAccessChain %_ptr_Input_float %BC %31
   1599 %33 = OpLoad %float %32
   1600 %34 = OpFAdd %float %30 %33
   1601 OpStore %f %34
   1602 OpBranch %25
   1603 %25 = OpLabel
   1604 %35 = OpLoad %int %i
   1605 %36 = OpIAdd %int %35 %int_1
   1606 OpStore %i %36
   1607 OpBranch %23
   1608 %24 = OpLabel
   1609 %37 = OpLoad %float %f
   1610 OpStore %fo %37
   1611 OpReturn
   1612 OpFunctionEnd
   1613 )";
   1614 
   1615   std::unique_ptr<IRContext> context =
   1616       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
   1617                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1618   EXPECT_NE(nullptr, context);
   1619 
   1620   // Force the instruction to block mapping to get built.
   1621   context->get_instr_block(27u);
   1622 
   1623   auto pass = MakeUnique<LocalMultiStoreElimPass>();
   1624   pass->SetMessageConsumer(nullptr);
   1625   const auto status = pass->Run(context.get());
   1626   EXPECT_TRUE(status == Pass::Status::SuccessWithChange);
   1627 }
   1628 
   1629 TEST_F(LocalSSAElimTest, CompositeExtractProblem) {
   1630   const std::string spv_asm = R"(
   1631                OpCapability Tessellation
   1632           %1 = OpExtInstImport "GLSL.std.450"
   1633                OpMemoryModel Logical GLSL450
   1634                OpEntryPoint TessellationControl %2 "main" %16 %17 %18 %20 %22 %26 %27 %30 %31
   1635        %void = OpTypeVoid
   1636           %4 = OpTypeFunction %void
   1637       %float = OpTypeFloat 32
   1638     %v4float = OpTypeVector %float 4
   1639        %uint = OpTypeInt 32 0
   1640      %uint_3 = OpConstant %uint 3
   1641     %v3float = OpTypeVector %float 3
   1642     %v2float = OpTypeVector %float 2
   1643  %_struct_11 = OpTypeStruct %v4float %v4float %v4float %v3float %v3float %v2float %v2float
   1644 %_arr__struct_11_uint_3 = OpTypeArray %_struct_11 %uint_3
   1645 %_ptr_Function__arr__struct_11_uint_3 = OpTypePointer Function %_arr__struct_11_uint_3
   1646 %_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3
   1647 %_ptr_Input__arr_v4float_uint_3 = OpTypePointer Input %_arr_v4float_uint_3
   1648          %16 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input
   1649          %17 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input
   1650          %18 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input
   1651 %_ptr_Input_uint = OpTypePointer Input %uint
   1652          %20 = OpVariable %_ptr_Input_uint Input
   1653 %_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3
   1654          %22 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output
   1655 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1656 %_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3
   1657 %_ptr_Input__arr_v3float_uint_3 = OpTypePointer Input %_arr_v3float_uint_3
   1658          %26 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input
   1659          %27 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input
   1660 %_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3
   1661 %_ptr_Input__arr_v2float_uint_3 = OpTypePointer Input %_arr_v2float_uint_3
   1662          %30 = OpVariable %_ptr_Input__arr_v2float_uint_3 Input
   1663          %31 = OpVariable %_ptr_Input__arr_v2float_uint_3 Input
   1664 %_ptr_Function__struct_11 = OpTypePointer Function %_struct_11
   1665           %2 = OpFunction %void None %4
   1666          %33 = OpLabel
   1667          %66 = OpVariable %_ptr_Function__arr__struct_11_uint_3 Function
   1668          %34 = OpLoad %_arr_v4float_uint_3 %16
   1669          %35 = OpLoad %_arr_v4float_uint_3 %17
   1670          %36 = OpLoad %_arr_v4float_uint_3 %18
   1671          %37 = OpLoad %_arr_v3float_uint_3 %26
   1672          %38 = OpLoad %_arr_v3float_uint_3 %27
   1673          %39 = OpLoad %_arr_v2float_uint_3 %30
   1674          %40 = OpLoad %_arr_v2float_uint_3 %31
   1675          %41 = OpCompositeExtract %v4float %34 0
   1676          %42 = OpCompositeExtract %v4float %35 0
   1677          %43 = OpCompositeExtract %v4float %36 0
   1678          %44 = OpCompositeExtract %v3float %37 0
   1679          %45 = OpCompositeExtract %v3float %38 0
   1680          %46 = OpCompositeExtract %v2float %39 0
   1681          %47 = OpCompositeExtract %v2float %40 0
   1682          %48 = OpCompositeConstruct %_struct_11 %41 %42 %43 %44 %45 %46 %47
   1683          %49 = OpCompositeExtract %v4float %34 1
   1684          %50 = OpCompositeExtract %v4float %35 1
   1685          %51 = OpCompositeExtract %v4float %36 1
   1686          %52 = OpCompositeExtract %v3float %37 1
   1687          %53 = OpCompositeExtract %v3float %38 1
   1688          %54 = OpCompositeExtract %v2float %39 1
   1689          %55 = OpCompositeExtract %v2float %40 1
   1690          %56 = OpCompositeConstruct %_struct_11 %49 %50 %51 %52 %53 %54 %55
   1691          %57 = OpCompositeExtract %v4float %34 2
   1692          %58 = OpCompositeExtract %v4float %35 2
   1693          %59 = OpCompositeExtract %v4float %36 2
   1694          %60 = OpCompositeExtract %v3float %37 2
   1695          %61 = OpCompositeExtract %v3float %38 2
   1696          %62 = OpCompositeExtract %v2float %39 2
   1697          %63 = OpCompositeExtract %v2float %40 2
   1698          %64 = OpCompositeConstruct %_struct_11 %57 %58 %59 %60 %61 %62 %63
   1699          %65 = OpCompositeConstruct %_arr__struct_11_uint_3 %48 %56 %64
   1700          %67 = OpLoad %uint %20
   1701 
   1702 ; CHECK OpStore {{%\d+}} [[store_source:%\d+]]
   1703                OpStore %66 %65
   1704          %68 = OpAccessChain %_ptr_Function__struct_11 %66 %67
   1705 
   1706 ; This load was being removed, because %_ptr_Function__struct_11 was being
   1707 ; wrongfully considered an SSA target.
   1708 ; CHECK OpLoad %_struct_11 %68
   1709          %69 = OpLoad %_struct_11 %68
   1710 
   1711 ; Similarly, %69 cannot be replaced with %65.
   1712 ; CHECK-NOT: OpCompositeExtract %v4float [[store_source]] 0
   1713          %70 = OpCompositeExtract %v4float %69 0
   1714 
   1715          %71 = OpAccessChain %_ptr_Output_v4float %22 %67
   1716                OpStore %71 %70
   1717                OpReturn
   1718                OpFunctionEnd)";
   1719 
   1720   SinglePassRunAndMatch<SSARewritePass>(spv_asm, true);
   1721 }
   1722 
   1723 // Test that the RelaxedPrecision decoration on the variable to added to the
   1724 // result of the OpPhi instruction.
   1725 TEST_F(LocalSSAElimTest, DecoratedVariable) {
   1726   const std::string spv_asm = R"(
   1727 ; CHECK: OpDecorate [[var:%\w+]] RelaxedPrecision
   1728 ; CHECK: OpDecorate [[phi_id:%\w+]] RelaxedPrecision
   1729 ; CHECK: [[phi_id]] = OpPhi
   1730                OpCapability Shader
   1731           %1 = OpExtInstImport "GLSL.std.450"
   1732                OpMemoryModel Logical GLSL450
   1733                OpEntryPoint GLCompute %2 "main"
   1734                OpDecorate %v RelaxedPrecision
   1735        %void = OpTypeVoid
   1736      %func_t = OpTypeFunction %void
   1737        %bool = OpTypeBool
   1738        %true = OpConstantTrue %bool
   1739        %int  = OpTypeInt 32 0
   1740       %int_p = OpTypePointer Function %int
   1741       %int_1 = OpConstant %int 1
   1742       %int_0 = OpConstant %int 0
   1743           %2 = OpFunction %void None %func_t
   1744          %33 = OpLabel
   1745          %v  = OpVariable %int_p Function
   1746                OpSelectionMerge %merge None
   1747                OpBranchConditional %true %l1 %l2
   1748          %l1 = OpLabel
   1749                OpStore %v %int_1
   1750                OpBranch %merge
   1751          %l2 = OpLabel
   1752                OpStore %v %int_0
   1753                OpBranch %merge
   1754       %merge = OpLabel
   1755          %ld = OpLoad %int %v
   1756                OpReturn
   1757                OpFunctionEnd)";
   1758 
   1759   SinglePassRunAndMatch<SSARewritePass>(spv_asm, true);
   1760 }
   1761 
   1762 // Test that the RelaxedPrecision decoration on the variable to added to the
   1763 // result of the OpPhi instruction.
   1764 TEST_F(LocalSSAElimTest, MultipleEdges) {
   1765   const std::string spv_asm = R"(
   1766   ; CHECK: OpSelectionMerge
   1767   ; CHECK: [[header_bb:%\w+]] = OpLabel
   1768   ; CHECK-NOT: OpLabel
   1769   ; CHECK: OpSwitch {{%\w+}} {{%\w+}} 76 [[bb1:%\w+]] 17 [[bb2:%\w+]]
   1770   ; CHECK-SAME: 4 [[bb2]]
   1771   ; CHECK: [[bb2]] = OpLabel
   1772   ; CHECK-NEXT: OpPhi [[type:%\w+]] [[val:%\w+]] [[header_bb]] %int_0 [[bb1]]
   1773           OpCapability Shader
   1774      %1 = OpExtInstImport "GLSL.std.450"
   1775           OpMemoryModel Logical GLSL450
   1776           OpEntryPoint Fragment %4 "main"
   1777           OpExecutionMode %4 OriginUpperLeft
   1778           OpSource ESSL 310
   1779   %void = OpTypeVoid
   1780      %3 = OpTypeFunction %void
   1781    %int = OpTypeInt 32 1
   1782   %_ptr_Function_int = OpTypePointer Function %int
   1783   %int_0 = OpConstant %int 0
   1784   %bool = OpTypeBool
   1785   %true = OpConstantTrue %bool
   1786   %false = OpConstantFalse %bool
   1787   %int_1 = OpConstant %int 1
   1788      %4 = OpFunction %void None %3
   1789      %5 = OpLabel
   1790      %8 = OpVariable %_ptr_Function_int Function
   1791           OpBranch %10
   1792     %10 = OpLabel
   1793           OpLoopMerge %12 %13 None
   1794           OpBranch %14
   1795     %14 = OpLabel
   1796           OpBranchConditional %true %11 %12
   1797     %11 = OpLabel
   1798           OpSelectionMerge %19 None
   1799           OpBranchConditional %false %18 %19
   1800     %18 = OpLabel
   1801           OpSelectionMerge %22 None
   1802           OpSwitch %int_0 %22 76 %20 17 %21 4 %21
   1803     %20 = OpLabel
   1804     %23 = OpLoad %int %8
   1805           OpStore %8 %int_0
   1806           OpBranch %21
   1807     %21 = OpLabel
   1808           OpBranch %22
   1809     %22 = OpLabel
   1810           OpBranch %19
   1811     %19 = OpLabel
   1812           OpBranch %13
   1813     %13 = OpLabel
   1814           OpBranch %10
   1815     %12 = OpLabel
   1816           OpReturn
   1817           OpFunctionEnd
   1818   )";
   1819 
   1820   SinglePassRunAndMatch<SSARewritePass>(spv_asm, true);
   1821 }
   1822 
   1823 // TODO(greg-lunarg): Add tests to verify handling of these cases:
   1824 //
   1825 //    No optimization in the presence of
   1826 //      access chains
   1827 //      function calls
   1828 //      OpCopyMemory?
   1829 //      unsupported extensions
   1830 //    Others?
   1831 
   1832 }  // namespace
   1833 }  // namespace opt
   1834 }  // namespace spvtools
   1835