Home | History | Annotate | Download | only in opt
      1 // Copyright (c) 2017 Google Inc.
      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 <string>
     16 
     17 #include "gmock/gmock.h"
     18 #include "gtest/gtest.h"
     19 #include "source/opt/ccp_pass.h"
     20 #include "test/opt/pass_fixture.h"
     21 #include "test/opt/pass_utils.h"
     22 
     23 namespace spvtools {
     24 namespace opt {
     25 namespace {
     26 
     27 using CCPTest = PassTest<::testing::Test>;
     28 
     29 TEST_F(CCPTest, PropagateThroughPhis) {
     30   const std::string spv_asm = R"(
     31                OpCapability Shader
     32           %1 = OpExtInstImport "GLSL.std.450"
     33                OpMemoryModel Logical GLSL450
     34                OpEntryPoint Fragment %main "main" %x %outparm
     35                OpExecutionMode %main OriginUpperLeft
     36                OpSource GLSL 450
     37                OpName %main "main"
     38                OpName %x "x"
     39                OpName %outparm "outparm"
     40                OpDecorate %x Flat
     41                OpDecorate %x Location 0
     42                OpDecorate %outparm Location 0
     43        %void = OpTypeVoid
     44           %3 = OpTypeFunction %void
     45         %int = OpTypeInt 32 1
     46        %bool = OpTypeBool
     47 %_ptr_Function_int = OpTypePointer Function %int
     48       %int_4 = OpConstant %int 4
     49       %int_3 = OpConstant %int 3
     50       %int_1 = OpConstant %int 1
     51 %_ptr_Input_int = OpTypePointer Input %int
     52           %x = OpVariable %_ptr_Input_int Input
     53 %_ptr_Output_int = OpTypePointer Output %int
     54     %outparm = OpVariable %_ptr_Output_int Output
     55        %main = OpFunction %void None %3
     56           %4 = OpLabel
     57           %5 = OpLoad %int %x
     58           %9 = OpIAdd %int %int_1 %int_3
     59           %6 = OpSGreaterThan %bool %5 %int_3
     60                OpSelectionMerge %25 None
     61                OpBranchConditional %6 %22 %23
     62          %22 = OpLabel
     63 
     64 ; CHECK: OpCopyObject %int %int_4
     65           %7 = OpCopyObject %int %9
     66 
     67                OpBranch %25
     68          %23 = OpLabel
     69           %8 = OpCopyObject %int %int_4
     70                OpBranch %25
     71          %25 = OpLabel
     72 
     73 ; %int_4 should have propagated to both OpPhi operands.
     74 ; CHECK: OpPhi %int %int_4 {{%\d+}} %int_4 {{%\d+}}
     75          %35 = OpPhi %int %7 %22 %8 %23
     76 
     77 ; This function always returns 4. DCE should get rid of everything else.
     78 ; CHECK OpStore %outparm %int_4
     79                OpStore %outparm %35
     80                OpReturn
     81                OpFunctionEnd
     82                )";
     83 
     84   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
     85 }
     86 
     87 TEST_F(CCPTest, SimplifyConditionals) {
     88   const std::string spv_asm = R"(
     89                OpCapability Shader
     90           %1 = OpExtInstImport "GLSL.std.450"
     91                OpMemoryModel Logical GLSL450
     92                OpEntryPoint Fragment %main "main" %outparm
     93                OpExecutionMode %main OriginUpperLeft
     94                OpSource GLSL 450
     95                OpName %main "main"
     96                OpName %outparm "outparm"
     97                OpDecorate %outparm Location 0
     98        %void = OpTypeVoid
     99           %3 = OpTypeFunction %void
    100         %int = OpTypeInt 32 1
    101        %bool = OpTypeBool
    102 %_ptr_Function_int = OpTypePointer Function %int
    103       %int_4 = OpConstant %int 4
    104       %int_3 = OpConstant %int 3
    105       %int_1 = OpConstant %int 1
    106 %_ptr_Output_int = OpTypePointer Output %int
    107     %outparm = OpVariable %_ptr_Output_int Output
    108        %main = OpFunction %void None %3
    109           %4 = OpLabel
    110           %9 = OpIAdd %int %int_4 %int_3
    111           %6 = OpSGreaterThan %bool %9 %int_3
    112                OpSelectionMerge %25 None
    113 ; CHECK: OpBranchConditional %true [[bb_taken:%\d+]] [[bb_not_taken:%\d+]]
    114                OpBranchConditional %6 %22 %23
    115 ; CHECK: [[bb_taken]] = OpLabel
    116          %22 = OpLabel
    117 ; CHECK: OpCopyObject %int %int_7
    118           %7 = OpCopyObject %int %9
    119                OpBranch %25
    120 ; CHECK: [[bb_not_taken]] = OpLabel
    121          %23 = OpLabel
    122 ; CHECK: [[id_not_evaluated:%\d+]] = OpCopyObject %int %int_4
    123           %8 = OpCopyObject %int %int_4
    124                OpBranch %25
    125          %25 = OpLabel
    126 
    127 ; %int_7 should have propagated to the first OpPhi operand. But the else branch
    128 ; is not executable (conditional is always true), so no values should be
    129 ; propagated there and the value of the OpPhi should always be %int_7.
    130 ; CHECK: OpPhi %int %int_7 [[bb_taken]] [[id_not_evaluated]] [[bb_not_taken]]
    131          %35 = OpPhi %int %7 %22 %8 %23
    132 
    133 ; Only the true path of the conditional is ever executed. The output of this
    134 ; function is always %int_7.
    135 ; CHECK: OpStore %outparm %int_7
    136                OpStore %outparm %35
    137                OpReturn
    138                OpFunctionEnd
    139                )";
    140 
    141   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    142 }
    143 
    144 TEST_F(CCPTest, SimplifySwitches) {
    145   const std::string spv_asm = R"(
    146                OpCapability Shader
    147           %1 = OpExtInstImport "GLSL.std.450"
    148                OpMemoryModel Logical GLSL450
    149                OpEntryPoint Fragment %main "main" %outparm
    150                OpExecutionMode %main OriginUpperLeft
    151                OpSource GLSL 450
    152                OpName %main "main"
    153                OpName %outparm "outparm"
    154                OpDecorate %outparm Location 0
    155        %void = OpTypeVoid
    156           %6 = OpTypeFunction %void
    157         %int = OpTypeInt 32 1
    158 %_ptr_Function_int = OpTypePointer Function %int
    159      %int_23 = OpConstant %int 23
    160      %int_42 = OpConstant %int 42
    161      %int_14 = OpConstant %int 14
    162      %int_15 = OpConstant %int 15
    163       %int_4 = OpConstant %int 4
    164 %_ptr_Output_int = OpTypePointer Output %int
    165     %outparm = OpVariable %_ptr_Output_int Output
    166        %main = OpFunction %void None %6
    167          %15 = OpLabel
    168                OpSelectionMerge %17 None
    169                OpSwitch %int_23 %17 10 %18 13 %19 23 %20
    170          %18 = OpLabel
    171                OpBranch %17
    172          %19 = OpLabel
    173                OpBranch %17
    174          %20 = OpLabel
    175                OpBranch %17
    176          %17 = OpLabel
    177          %24 = OpPhi %int %int_23 %15 %int_42 %18 %int_14 %19 %int_15 %20
    178 
    179 ; The switch will always jump to label %20, which carries the value %int_15.
    180 ; CHECK: OpIAdd %int %int_15 %int_4
    181          %22 = OpIAdd %int %24 %int_4
    182 
    183 ; Consequently, the return value will always be %int_19.
    184 ; CHECK: OpStore %outparm %int_19
    185                OpStore %outparm %22
    186                OpReturn
    187                OpFunctionEnd
    188                )";
    189 
    190   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    191 }
    192 
    193 TEST_F(CCPTest, SimplifySwitchesDefaultBranch) {
    194   const std::string spv_asm = R"(
    195                OpCapability Shader
    196           %1 = OpExtInstImport "GLSL.std.450"
    197                OpMemoryModel Logical GLSL450
    198                OpEntryPoint Fragment %main "main" %outparm
    199                OpExecutionMode %main OriginUpperLeft
    200                OpSource GLSL 450
    201                OpName %main "main"
    202                OpName %outparm "outparm"
    203                OpDecorate %outparm Location 0
    204        %void = OpTypeVoid
    205           %6 = OpTypeFunction %void
    206         %int = OpTypeInt 32 1
    207 %_ptr_Function_int = OpTypePointer Function %int
    208      %int_42 = OpConstant %int 42
    209       %int_4 = OpConstant %int 4
    210       %int_1 = OpConstant %int 1
    211 %_ptr_Output_int = OpTypePointer Output %int
    212     %outparm = OpVariable %_ptr_Output_int Output
    213        %main = OpFunction %void None %6
    214          %13 = OpLabel
    215          %15 = OpIAdd %int %int_42 %int_4
    216                OpSelectionMerge %16 None
    217 
    218 ; CHECK: OpSwitch %int_46 {{%\d+}} 10 {{%\d+}}
    219                OpSwitch %15 %17 10 %18
    220          %18 = OpLabel
    221                OpBranch %16
    222          %17 = OpLabel
    223                OpBranch %16
    224          %16 = OpLabel
    225          %22 = OpPhi %int %int_42 %18 %int_1 %17
    226 
    227 ; The switch will always jump to the default label %17.  This carries the value
    228 ; %int_1.
    229 ; CHECK: OpIAdd %int %int_1 %int_4
    230          %20 = OpIAdd %int %22 %int_4
    231 
    232 ; Resulting in a return value of %int_5.
    233 ; CHECK: OpStore %outparm %int_5
    234                OpStore %outparm %20
    235                OpReturn
    236                OpFunctionEnd
    237                )";
    238 
    239   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    240 }
    241 
    242 TEST_F(CCPTest, SimplifyIntVector) {
    243   const std::string spv_asm = R"(
    244                OpCapability Shader
    245           %1 = OpExtInstImport "GLSL.std.450"
    246                OpMemoryModel Logical GLSL450
    247                OpEntryPoint Fragment %main "main" %OutColor
    248                OpExecutionMode %main OriginUpperLeft
    249                OpSource GLSL 450
    250                OpName %main "main"
    251                OpName %v "v"
    252                OpName %OutColor "OutColor"
    253                OpDecorate %OutColor Location 0
    254        %void = OpTypeVoid
    255           %3 = OpTypeFunction %void
    256         %int = OpTypeInt 32 1
    257       %v4int = OpTypeVector %int 4
    258 %_ptr_Function_v4int = OpTypePointer Function %v4int
    259       %int_1 = OpConstant %int 1
    260       %int_2 = OpConstant %int 2
    261       %int_3 = OpConstant %int 3
    262       %int_4 = OpConstant %int 4
    263          %14 = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
    264        %uint = OpTypeInt 32 0
    265      %uint_0 = OpConstant %uint 0
    266 %_ptr_Function_int = OpTypePointer Function %int
    267 %_ptr_Output_v4int = OpTypePointer Output %v4int
    268    %OutColor = OpVariable %_ptr_Output_v4int Output
    269        %main = OpFunction %void None %3
    270           %5 = OpLabel
    271           %v = OpVariable %_ptr_Function_v4int Function
    272                OpStore %v %14
    273          %18 = OpAccessChain %_ptr_Function_int %v %uint_0
    274          %19 = OpLoad %int %18
    275 
    276 ; The constant folder does not see through access chains. To get this, the
    277 ; vector would have to be scalarized.
    278 ; CHECK: [[result_id:%\d+]] = OpIAdd %int {{%\d+}} %int_1
    279          %20 = OpIAdd %int %19 %int_1
    280          %21 = OpAccessChain %_ptr_Function_int %v %uint_0
    281 
    282 ; CHECK: OpStore {{%\d+}} [[result_id]]
    283                OpStore %21 %20
    284          %24 = OpLoad %v4int %v
    285                OpStore %OutColor %24
    286                OpReturn
    287                OpFunctionEnd
    288                )";
    289 
    290   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    291 }
    292 
    293 TEST_F(CCPTest, BadSimplifyFloatVector) {
    294   const std::string spv_asm = R"(
    295                OpCapability Shader
    296           %1 = OpExtInstImport "GLSL.std.450"
    297                OpMemoryModel Logical GLSL450
    298                OpEntryPoint Fragment %main "main" %OutColor
    299                OpExecutionMode %main OriginUpperLeft
    300                OpSource GLSL 450
    301                OpName %main "main"
    302                OpName %v "v"
    303                OpName %OutColor "OutColor"
    304                OpDecorate %OutColor Location 0
    305        %void = OpTypeVoid
    306           %3 = OpTypeFunction %void
    307       %float = OpTypeFloat 32
    308     %v4float = OpTypeVector %float 4
    309 %_ptr_Function_v4float = OpTypePointer Function %v4float
    310     %float_1 = OpConstant %float 1
    311     %float_2 = OpConstant %float 2
    312     %float_3 = OpConstant %float 3
    313     %float_4 = OpConstant %float 4
    314          %14 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
    315        %uint = OpTypeInt 32 0
    316      %uint_0 = OpConstant %uint 0
    317 %_ptr_Function_float = OpTypePointer Function %float
    318 %_ptr_Output_v4float = OpTypePointer Output %v4float
    319    %OutColor = OpVariable %_ptr_Output_v4float Output
    320        %main = OpFunction %void None %3
    321           %5 = OpLabel
    322           %v = OpVariable %_ptr_Function_v4float Function
    323                OpStore %v %14
    324          %18 = OpAccessChain %_ptr_Function_float %v %uint_0
    325          %19 = OpLoad %float %18
    326 
    327 ; NOTE: This test should start failing once floating point folding is
    328 ;       implemented (https://github.com/KhronosGroup/SPIRV-Tools/issues/943).
    329 ;       This should be checking that we are adding %float_1 + %float_1.
    330 ; CHECK: [[result_id:%\d+]] = OpFAdd %float {{%\d+}} %float_1
    331          %20 = OpFAdd %float %19 %float_1
    332          %21 = OpAccessChain %_ptr_Function_float %v %uint_0
    333 
    334 ; This should be checkint that we are storing %float_2 instead of result_it.
    335 ; CHECK: OpStore {{%\d+}} [[result_id]]
    336                OpStore %21 %20
    337          %24 = OpLoad %v4float %v
    338                OpStore %OutColor %24
    339                OpReturn
    340                OpFunctionEnd
    341                )";
    342 
    343   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    344 }
    345 
    346 TEST_F(CCPTest, NoLoadStorePropagation) {
    347   const std::string spv_asm = R"(
    348                OpCapability Shader
    349           %1 = OpExtInstImport "GLSL.std.450"
    350                OpMemoryModel Logical GLSL450
    351                OpEntryPoint Fragment %main "main" %outparm
    352                OpExecutionMode %main OriginUpperLeft
    353                OpSource GLSL 450
    354                OpName %main "main"
    355                OpName %x "x"
    356                OpName %outparm "outparm"
    357                OpDecorate %outparm Location 0
    358        %void = OpTypeVoid
    359           %3 = OpTypeFunction %void
    360         %int = OpTypeInt 32 1
    361 %_ptr_Function_int = OpTypePointer Function %int
    362      %int_23 = OpConstant %int 23
    363 %_ptr_Output_int = OpTypePointer Output %int
    364     %outparm = OpVariable %_ptr_Output_int Output
    365        %main = OpFunction %void None %3
    366           %5 = OpLabel
    367           %x = OpVariable %_ptr_Function_int Function
    368                OpStore %x %int_23
    369 
    370 ; int_23 should not propagate into this load.
    371 ; CHECK: [[load_id:%\d+]] = OpLoad %int %x
    372          %12 = OpLoad %int %x
    373 
    374 ; Nor into this copy operation.
    375 ; CHECK: [[copy_id:%\d+]] = OpCopyObject %int [[load_id]]
    376          %13 = OpCopyObject %int %12
    377 
    378 ; Likewise here.
    379 ; CHECK: OpStore %outparm [[copy_id]]
    380                OpStore %outparm %13
    381                OpReturn
    382                OpFunctionEnd
    383                )";
    384 
    385   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    386 }
    387 
    388 TEST_F(CCPTest, HandleAbortInstructions) {
    389   const std::string spv_asm = R"(
    390                OpCapability Shader
    391           %1 = OpExtInstImport "GLSL.std.450"
    392                OpMemoryModel Logical GLSL450
    393                OpEntryPoint Fragment %main "main"
    394                OpExecutionMode %main OriginUpperLeft
    395                OpSource HLSL 500
    396                OpName %main "main"
    397        %void = OpTypeVoid
    398           %3 = OpTypeFunction %void
    399         %int = OpTypeInt 32 1
    400        %bool = OpTypeBool
    401 ; CHECK: %true = OpConstantTrue %bool
    402       %int_3 = OpConstant %int 3
    403       %int_1 = OpConstant %int 1
    404        %main = OpFunction %void None %3
    405           %4 = OpLabel
    406           %9 = OpIAdd %int %int_3 %int_1
    407           %6 = OpSGreaterThan %bool %9 %int_3
    408                OpSelectionMerge %23 None
    409 ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
    410                OpBranchConditional %6 %22 %23
    411          %22 = OpLabel
    412                OpKill
    413          %23 = OpLabel
    414                OpReturn
    415                OpFunctionEnd
    416   )";
    417 
    418   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    419 }
    420 
    421 TEST_F(CCPTest, SSAWebCycles) {
    422   // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1159
    423   // When there is a cycle in the SSA def-use web, the propagator was getting
    424   // into an infinite loop.  SSA edges for Phi instructions should not be
    425   // added to the edges to simulate.
    426   const std::string spv_asm = R"(
    427                OpCapability Shader
    428           %1 = OpExtInstImport "GLSL.std.450"
    429                OpMemoryModel Logical GLSL450
    430                OpEntryPoint Fragment %main "main"
    431                OpExecutionMode %main OriginUpperLeft
    432                OpSource GLSL 450
    433                OpName %main "main"
    434        %void = OpTypeVoid
    435           %3 = OpTypeFunction %void
    436         %int = OpTypeInt 32 1
    437 %_ptr_Function_int = OpTypePointer Function %int
    438       %int_0 = OpConstant %int 0
    439       %int_4 = OpConstant %int 4
    440        %bool = OpTypeBool
    441       %int_1 = OpConstant %int 1
    442 %_ptr_Output_int = OpTypePointer Output %int
    443        %main = OpFunction %void None %3
    444           %5 = OpLabel
    445                OpBranch %11
    446          %11 = OpLabel
    447          %29 = OpPhi %int %int_0 %5 %22 %14
    448          %30 = OpPhi %int %int_0 %5 %25 %14
    449                OpLoopMerge %13 %14 None
    450                OpBranch %15
    451          %15 = OpLabel
    452          %19 = OpSLessThan %bool %30 %int_4
    453 ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
    454                OpBranchConditional %19 %12 %13
    455          %12 = OpLabel
    456 ; CHECK: OpIAdd %int %int_0 %int_0
    457          %22 = OpIAdd %int %29 %30
    458                OpBranch %14
    459          %14 = OpLabel
    460 ; CHECK: OpPhi %int %int_0 {{%\d+}}
    461          %25 = OpPhi %int %30 %12
    462                OpBranch %11
    463          %13 = OpLabel
    464                OpReturn
    465                OpFunctionEnd
    466   )";
    467 
    468   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    469   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    470 }
    471 
    472 TEST_F(CCPTest, LoopInductionVariables) {
    473   // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1143
    474   // We are failing to properly consider the induction variable for this loop
    475   // as Varying.
    476   const std::string spv_asm = R"(
    477                OpCapability Shader
    478           %1 = OpExtInstImport "GLSL.std.450"
    479                OpMemoryModel Logical GLSL450
    480                OpEntryPoint Fragment %main "main"
    481                OpExecutionMode %main OriginUpperLeft
    482                OpSource GLSL 430
    483                OpName %main "main"
    484        %void = OpTypeVoid
    485           %5 = OpTypeFunction %void
    486         %int = OpTypeInt 32 1
    487 %_ptr_Function_int = OpTypePointer Function %int
    488       %int_0 = OpConstant %int 0
    489      %int_10 = OpConstant %int 10
    490        %bool = OpTypeBool
    491       %int_1 = OpConstant %int 1
    492        %main = OpFunction %void None %5
    493          %12 = OpLabel
    494                OpBranch %13
    495          %13 = OpLabel
    496 
    497 ; This Phi should not have all constant arguments:
    498 ; CHECK: [[phi_id:%\d+]] = OpPhi %int %int_0 {{%\d+}} {{%\d+}} {{%\d+}}
    499          %22 = OpPhi %int %int_0 %12 %21 %15
    500                OpLoopMerge %14 %15 None
    501                OpBranch %16
    502          %16 = OpLabel
    503 
    504 ; The Phi should never be considered to have the value %int_0.
    505 ; CHECK: [[branch_selector:%\d+]] = OpSLessThan %bool [[phi_id]] %int_10
    506          %18 = OpSLessThan %bool %22 %int_10
    507 
    508 ; This conditional was wrongly converted into an always-true jump due to the
    509 ; bad meet evaluation of %22.
    510 ; CHECK: OpBranchConditional [[branch_selector]] {{%\d+}} {{%\d+}}
    511                OpBranchConditional %18 %19 %14
    512          %19 = OpLabel
    513                OpBranch %15
    514          %15 = OpLabel
    515 ; CHECK: OpIAdd %int [[phi_id]] %int_1
    516          %21 = OpIAdd %int %22 %int_1
    517                OpBranch %13
    518          %14 = OpLabel
    519                OpReturn
    520                OpFunctionEnd
    521   )";
    522 
    523   SinglePassRunAndMatch<CCPPass>(spv_asm, true);
    524 }
    525 
    526 TEST_F(CCPTest, HandleCompositeWithUndef) {
    527   // Check to make sure that CCP does not crash when given a "constant" struct
    528   // with an undef.  If at a later time CCP is enhanced to optimize this case,
    529   // it is not wrong.
    530   const std::string spv_asm = R"(
    531                OpCapability Shader
    532           %1 = OpExtInstImport "GLSL.std.450"
    533                OpMemoryModel Logical GLSL450
    534                OpEntryPoint Fragment %main "main"
    535                OpExecutionMode %main OriginUpperLeft
    536                OpSource HLSL 500
    537                OpName %main "main"
    538        %void = OpTypeVoid
    539           %4 = OpTypeFunction %void
    540         %int = OpTypeInt 32 1
    541        %bool = OpTypeBool
    542   %_struct_7 = OpTypeStruct %int %int
    543       %int_1 = OpConstant %int 1
    544           %9 = OpUndef %int
    545          %10 = OpConstantComposite %_struct_7 %int_1 %9
    546        %main = OpFunction %void None %4
    547          %11 = OpLabel
    548          %12 = OpCompositeExtract %int %10 0
    549          %13 = OpCopyObject %int %12
    550                OpReturn
    551                OpFunctionEnd
    552   )";
    553 
    554   auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
    555   EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
    556 }
    557 
    558 TEST_F(CCPTest, SkipSpecConstantInstrucitons) {
    559   const std::string spv_asm = R"(
    560                OpCapability Shader
    561           %1 = OpExtInstImport "GLSL.std.450"
    562                OpMemoryModel Logical GLSL450
    563                OpEntryPoint Fragment %main "main"
    564                OpExecutionMode %main OriginUpperLeft
    565                OpSource HLSL 500
    566                OpName %main "main"
    567        %void = OpTypeVoid
    568           %4 = OpTypeFunction %void
    569        %bool = OpTypeBool
    570          %10 = OpSpecConstantFalse %bool
    571        %main = OpFunction %void None %4
    572          %11 = OpLabel
    573          %12 = OpBranchConditional %10 %l1 %l2
    574          %l1 = OpLabel
    575                OpReturn
    576          %l2 = OpLabel
    577                OpReturn
    578                OpFunctionEnd
    579   )";
    580 
    581   auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
    582   EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
    583 }
    584 
    585 TEST_F(CCPTest, UpdateSubsequentPhisToVarying) {
    586   const std::string text = R"(
    587 OpCapability Shader
    588 OpMemoryModel Logical GLSL450
    589 OpEntryPoint Fragment %func "func" %in
    590 OpExecutionMode %func OriginUpperLeft
    591 %void = OpTypeVoid
    592 %bool = OpTypeBool
    593 %int = OpTypeInt 32 1
    594 %false = OpConstantFalse %bool
    595 %int0 = OpConstant %int 0
    596 %int1 = OpConstant %int 1
    597 %int6 = OpConstant %int 6
    598 %int_ptr_Input = OpTypePointer Input %int
    599 %in = OpVariable %int_ptr_Input Input
    600 %undef = OpUndef %int
    601 %functy = OpTypeFunction %void
    602 %func = OpFunction %void None %functy
    603 %1 = OpLabel
    604 OpBranch %2
    605 %2 = OpLabel
    606 %outer_phi = OpPhi %int %int0 %1 %outer_add %15
    607 %cond1 = OpSLessThanEqual %bool %outer_phi %int6
    608 OpLoopMerge %3 %15 None
    609 OpBranchConditional %cond1 %4 %3
    610 %4 = OpLabel
    611 %ld = OpLoad %int %in
    612 %cond2 = OpSGreaterThanEqual %bool %int1 %ld
    613 OpSelectionMerge %10 None
    614 OpBranchConditional %cond2 %8 %9
    615 %8 = OpLabel
    616 OpBranch %10
    617 %9 = OpLabel
    618 OpBranch %10
    619 %10 = OpLabel
    620 %extra_phi = OpPhi %int %outer_phi %8 %outer_phi %9
    621 OpBranch %11
    622 %11 = OpLabel
    623 %inner_phi = OpPhi %int %int0 %10 %inner_add %13
    624 %cond3 = OpSLessThanEqual %bool %inner_phi %int6
    625 OpLoopMerge %14 %13 None
    626 OpBranchConditional %cond3 %12 %14
    627 %12 = OpLabel
    628 OpBranch %13
    629 %13 = OpLabel
    630 %inner_add = OpIAdd %int %inner_phi %int1
    631 OpBranch %11
    632 %14 = OpLabel
    633 OpBranch %15
    634 %15 = OpLabel
    635 %outer_add = OpIAdd %int %extra_phi %int1
    636 OpBranch %2
    637 %3 = OpLabel
    638 OpReturn
    639 OpFunctionEnd
    640 )";
    641 
    642   auto res = SinglePassRunToBinary<CCPPass>(text, true);
    643   EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
    644 }
    645 
    646 TEST_F(CCPTest, UndefInPhi) {
    647   const std::string text = R"(
    648 ; CHECK: [[uint1:%\w+]] = OpConstant {{%\w+}} 1
    649 ; CHECK: [[phi:%\w+]] = OpPhi
    650 ; CHECK: OpIAdd {{%\w+}} [[phi]] [[uint1]]
    651                OpCapability Kernel
    652                OpCapability Linkage
    653                OpMemoryModel Logical OpenCL
    654                OpDecorate %1 LinkageAttributes "func" Export
    655        %void = OpTypeVoid
    656        %bool = OpTypeBool
    657        %uint = OpTypeInt 32 0
    658      %uint_0 = OpConstant %uint 0
    659      %uint_1 = OpConstant %uint 1
    660           %7 = OpUndef %uint
    661           %8 = OpTypeFunction %void %bool
    662           %1 = OpFunction %void None %8
    663           %9 = OpFunctionParameter %bool
    664          %10 = OpLabel
    665                OpBranchConditional %9 %11 %12
    666          %11 = OpLabel
    667                OpBranch %13
    668          %12 = OpLabel
    669                OpBranch %14
    670          %14 = OpLabel
    671                OpBranchConditional %9 %13 %15
    672          %15 = OpLabel
    673                OpBranch %13
    674          %13 = OpLabel
    675          %16 = OpPhi %uint %uint_0 %11 %7 %14 %uint_1 %15
    676          %17 = OpIAdd %uint %16 %uint_1
    677                OpReturn
    678                OpFunctionEnd
    679 )";
    680 
    681   SinglePassRunAndMatch<CCPPass>(text, true);
    682 }
    683 
    684 // Just test to make sure the constant fold rules are being used.  Will rely on
    685 // the folding test for specific testing of specific rules.
    686 TEST_F(CCPTest, UseConstantFoldingRules) {
    687   const std::string text = R"(
    688 ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
    689 ; CHECK: OpReturnValue [[float1]]
    690                OpCapability Shader
    691                OpCapability Linkage
    692                OpMemoryModel Logical GLSL450
    693                OpDecorate %1 LinkageAttributes "func" Export
    694        %void = OpTypeVoid
    695        %bool = OpTypeBool
    696       %float = OpTypeFloat 32
    697     %float_0 = OpConstant %float 0
    698     %float_1 = OpConstant %float 1
    699           %8 = OpTypeFunction %float
    700           %1 = OpFunction %float None %8
    701          %10 = OpLabel
    702          %17 = OpFAdd %float %float_0 %float_1
    703                OpReturnValue %17
    704                OpFunctionEnd
    705 )";
    706 
    707   SinglePassRunAndMatch<CCPPass>(text, true);
    708 }
    709 
    710 // Test for #1300. Previously value for %5 would not settle during simulation.
    711 TEST_F(CCPTest, SettlePhiLatticeValue) {
    712   const std::string text = R"(
    713 OpCapability Kernel
    714 OpCapability Linkage
    715 OpMemoryModel Logical OpenCL
    716 OpDecorate %func LinkageAttributes "func" Export
    717 %void = OpTypeVoid
    718 %bool = OpTypeBool
    719 %true = OpConstantTrue %bool
    720 %false = OpConstantFalse %bool
    721 %functy = OpTypeFunction %void
    722 %func = OpFunction %void None %functy
    723 %1 = OpLabel
    724 OpBranchConditional %true %2 %3
    725 %3 = OpLabel
    726 OpBranch %2
    727 %2 = OpLabel
    728 %5 = OpPhi %bool %true %1 %false %3
    729 OpReturn
    730 OpFunctionEnd
    731 )";
    732 
    733   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    734   SinglePassRunToBinary<CCPPass>(text, true);
    735 }
    736 
    737 TEST_F(CCPTest, NullBranchCondition) {
    738   const std::string text = R"(
    739 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
    740 ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
    741 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
    742 OpCapability Shader
    743 OpMemoryModel Logical GLSL450
    744 OpEntryPoint Fragment %func "func"
    745 OpExecutionMode %func OriginUpperLeft
    746 %void = OpTypeVoid
    747 %bool = OpTypeBool
    748 %int = OpTypeInt 32 1
    749 %null = OpConstantNull %bool
    750 %int_1 = OpConstant %int 1
    751 %int_2 = OpConstant %int 2
    752 %functy = OpTypeFunction %void
    753 %func = OpFunction %void None %functy
    754 %1 = OpLabel
    755 OpSelectionMerge %2 None
    756 OpBranchConditional %null %2 %3
    757 %3 = OpLabel
    758 OpBranch %2
    759 %2 = OpLabel
    760 %phi = OpPhi %int %int_1 %1 %int_2 %3
    761 %add = OpIAdd %int %int_1 %phi
    762 OpReturn
    763 OpFunctionEnd
    764 )";
    765 
    766   SinglePassRunAndMatch<CCPPass>(text, true);
    767 }
    768 
    769 TEST_F(CCPTest, UndefBranchCondition) {
    770   const std::string text = R"(
    771 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
    772 ; CHECK: [[phi:%\w+]] = OpPhi
    773 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
    774 OpCapability Shader
    775 OpMemoryModel Logical GLSL450
    776 OpEntryPoint Fragment %func "func"
    777 OpExecutionMode %func OriginUpperLeft
    778 %void = OpTypeVoid
    779 %bool = OpTypeBool
    780 %int = OpTypeInt 32 1
    781 %undef = OpUndef %bool
    782 %int_1 = OpConstant %int 1
    783 %int_2 = OpConstant %int 2
    784 %functy = OpTypeFunction %void
    785 %func = OpFunction %void None %functy
    786 %1 = OpLabel
    787 OpSelectionMerge %2 None
    788 OpBranchConditional %undef %2 %3
    789 %3 = OpLabel
    790 OpBranch %2
    791 %2 = OpLabel
    792 %phi = OpPhi %int %int_1 %1 %int_2 %3
    793 %add = OpIAdd %int %int_1 %phi
    794 OpReturn
    795 OpFunctionEnd
    796 )";
    797 
    798   SinglePassRunAndMatch<CCPPass>(text, true);
    799 }
    800 
    801 TEST_F(CCPTest, NullSwitchCondition) {
    802   const std::string text = R"(
    803 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
    804 ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
    805 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
    806 OpCapability Shader
    807 OpMemoryModel Logical GLSL450
    808 OpEntryPoint Fragment %func "func"
    809 OpExecutionMode %func OriginUpperLeft
    810 %void = OpTypeVoid
    811 %int = OpTypeInt 32 1
    812 %null = OpConstantNull %int
    813 %int_1 = OpConstant %int 1
    814 %int_2 = OpConstant %int 2
    815 %functy = OpTypeFunction %void
    816 %func = OpFunction %void None %functy
    817 %1 = OpLabel
    818 OpSelectionMerge %2 None
    819 OpSwitch %null %2 0 %3
    820 %3 = OpLabel
    821 OpBranch %2
    822 %2 = OpLabel
    823 %phi = OpPhi %int %int_1 %1 %int_2 %3
    824 %add = OpIAdd %int %int_1 %phi
    825 OpReturn
    826 OpFunctionEnd
    827 )";
    828 
    829   SinglePassRunAndMatch<CCPPass>(text, true);
    830 }
    831 
    832 TEST_F(CCPTest, UndefSwitchCondition) {
    833   const std::string text = R"(
    834 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
    835 ; CHECK: [[phi:%\w+]] = OpPhi
    836 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
    837 OpCapability Shader
    838 OpMemoryModel Logical GLSL450
    839 OpEntryPoint Fragment %func "func"
    840 OpExecutionMode %func OriginUpperLeft
    841 %void = OpTypeVoid
    842 %int = OpTypeInt 32 1
    843 %undef = OpUndef %int
    844 %int_1 = OpConstant %int 1
    845 %int_2 = OpConstant %int 2
    846 %functy = OpTypeFunction %void
    847 %func = OpFunction %void None %functy
    848 %1 = OpLabel
    849 OpSelectionMerge %2 None
    850 OpSwitch %undef %2 0 %3
    851 %3 = OpLabel
    852 OpBranch %2
    853 %2 = OpLabel
    854 %phi = OpPhi %int %int_1 %1 %int_2 %3
    855 %add = OpIAdd %int %int_1 %phi
    856 OpReturn
    857 OpFunctionEnd
    858 )";
    859 
    860   SinglePassRunAndMatch<CCPPass>(text, true);
    861 }
    862 
    863 // Test for #1361.
    864 TEST_F(CCPTest, CompositeConstructOfGlobalValue) {
    865   const std::string text = R"(
    866 ; CHECK: [[phi:%\w+]] = OpPhi
    867 ; CHECK-NEXT: OpCompositeExtract {{%\w+}} [[phi]] 0
    868 OpCapability Shader
    869 OpMemoryModel Logical GLSL450
    870 OpEntryPoint Fragment %func "func" %in
    871 OpExecutionMode %func OriginUpperLeft
    872 %void = OpTypeVoid
    873 %int = OpTypeInt 32 1
    874 %bool = OpTypeBool
    875 %functy = OpTypeFunction %void
    876 %ptr_int_Input = OpTypePointer Input %int
    877 %in = OpVariable %ptr_int_Input Input
    878 %struct = OpTypeStruct %ptr_int_Input %ptr_int_Input
    879 %struct_null = OpConstantNull %struct
    880 %func = OpFunction %void None %functy
    881 %1 = OpLabel
    882 OpBranch %2
    883 %2 = OpLabel
    884 %phi = OpPhi %struct %struct_null %1 %5 %4
    885 %extract = OpCompositeExtract %ptr_int_Input %phi 0
    886 OpLoopMerge %3 %4 None
    887 OpBranch %4
    888 %4 = OpLabel
    889 %5 = OpCompositeConstruct %struct %in %in
    890 OpBranch %2
    891 %3 = OpLabel
    892 OpReturn
    893 OpFunctionEnd
    894 )";
    895 
    896   SinglePassRunAndMatch<CCPPass>(text, true);
    897 }
    898 
    899 }  // namespace
    900 }  // namespace opt
    901 }  // namespace spvtools
    902