Home | History | Annotate | Download | only in opt
      1 // Copyright (c) 2018 Google LLC
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include <iostream>
     16 #include <string>
     17 
     18 #include "gmock/gmock.h"
     19 #include "test/opt/assembly_builder.h"
     20 #include "test/opt/pass_fixture.h"
     21 
     22 namespace spvtools {
     23 namespace opt {
     24 namespace {
     25 
     26 using CopyPropArrayPassTest = PassTest<::testing::Test>;
     27 
     28 TEST_F(CopyPropArrayPassTest, BasicPropagateArray) {
     29   const std::string before =
     30       R"(
     31 OpCapability Shader
     32 OpMemoryModel Logical GLSL450
     33 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
     34 OpExecutionMode %main OriginUpperLeft
     35 OpSource HLSL 600
     36 OpName %type_MyCBuffer "type.MyCBuffer"
     37 OpMemberName %type_MyCBuffer 0 "Data"
     38 OpName %MyCBuffer "MyCBuffer"
     39 OpName %main "main"
     40 OpName %in_var_INDEX "in.var.INDEX"
     41 OpName %out_var_SV_Target "out.var.SV_Target"
     42 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
     43 OpMemberDecorate %type_MyCBuffer 0 Offset 0
     44 OpDecorate %type_MyCBuffer Block
     45 OpDecorate %in_var_INDEX Flat
     46 OpDecorate %in_var_INDEX Location 0
     47 OpDecorate %out_var_SV_Target Location 0
     48 OpDecorate %MyCBuffer DescriptorSet 0
     49 OpDecorate %MyCBuffer Binding 0
     50 %float = OpTypeFloat 32
     51 %v4float = OpTypeVector %float 4
     52 %uint = OpTypeInt 32 0
     53 %uint_8 = OpConstant %uint 8
     54 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
     55 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
     56 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
     57 %void = OpTypeVoid
     58 %13 = OpTypeFunction %void
     59 %int = OpTypeInt 32 1
     60 %_ptr_Input_int = OpTypePointer Input %int
     61 %_ptr_Output_v4float = OpTypePointer Output %v4float
     62 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
     63 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
     64 %int_0 = OpConstant %int 0
     65 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
     66 %_ptr_Function_v4float = OpTypePointer Function %v4float
     67 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
     68 %in_var_INDEX = OpVariable %_ptr_Input_int Input
     69 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
     70 ; CHECK: OpFunction
     71 ; CHECK: OpLabel
     72 ; CHECK: OpVariable
     73 ; CHECK: OpAccessChain
     74 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
     75 ; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
     76 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
     77 ; CHECK: OpStore %out_var_SV_Target [[load]]
     78 %main = OpFunction %void None %13
     79 %22 = OpLabel
     80 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
     81 %24 = OpLoad %int %in_var_INDEX
     82 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
     83 %26 = OpLoad %_arr_v4float_uint_8 %25
     84 %27 = OpCompositeExtract %v4float %26 0
     85 %28 = OpCompositeExtract %v4float %26 1
     86 %29 = OpCompositeExtract %v4float %26 2
     87 %30 = OpCompositeExtract %v4float %26 3
     88 %31 = OpCompositeExtract %v4float %26 4
     89 %32 = OpCompositeExtract %v4float %26 5
     90 %33 = OpCompositeExtract %v4float %26 6
     91 %34 = OpCompositeExtract %v4float %26 7
     92 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
     93 OpStore %23 %35
     94 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
     95 %37 = OpLoad %v4float %36
     96 OpStore %out_var_SV_Target %37
     97 OpReturn
     98 OpFunctionEnd
     99 )";
    100 
    101   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    102   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    103                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    104   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
    105 }
    106 
    107 TEST_F(CopyPropArrayPassTest, BasicPropagateArrayWithName) {
    108   const std::string before =
    109       R"(
    110 OpCapability Shader
    111 OpMemoryModel Logical GLSL450
    112 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
    113 OpExecutionMode %main OriginUpperLeft
    114 OpSource HLSL 600
    115 OpName %type_MyCBuffer "type.MyCBuffer"
    116 OpMemberName %type_MyCBuffer 0 "Data"
    117 OpName %MyCBuffer "MyCBuffer"
    118 OpName %main "main"
    119 OpName %local "local"
    120 OpName %in_var_INDEX "in.var.INDEX"
    121 OpName %out_var_SV_Target "out.var.SV_Target"
    122 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
    123 OpMemberDecorate %type_MyCBuffer 0 Offset 0
    124 OpDecorate %type_MyCBuffer Block
    125 OpDecorate %in_var_INDEX Flat
    126 OpDecorate %in_var_INDEX Location 0
    127 OpDecorate %out_var_SV_Target Location 0
    128 OpDecorate %MyCBuffer DescriptorSet 0
    129 OpDecorate %MyCBuffer Binding 0
    130 %float = OpTypeFloat 32
    131 %v4float = OpTypeVector %float 4
    132 %uint = OpTypeInt 32 0
    133 %uint_8 = OpConstant %uint 8
    134 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
    135 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
    136 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
    137 %void = OpTypeVoid
    138 %13 = OpTypeFunction %void
    139 %int = OpTypeInt 32 1
    140 %_ptr_Input_int = OpTypePointer Input %int
    141 %_ptr_Output_v4float = OpTypePointer Output %v4float
    142 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
    143 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
    144 %int_0 = OpConstant %int 0
    145 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
    146 %_ptr_Function_v4float = OpTypePointer Function %v4float
    147 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
    148 %in_var_INDEX = OpVariable %_ptr_Input_int Input
    149 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
    150 ; CHECK: OpFunction
    151 ; CHECK: OpLabel
    152 ; CHECK: OpVariable
    153 ; CHECK: OpAccessChain
    154 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
    155 ; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
    156 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
    157 ; CHECK: OpStore %out_var_SV_Target [[load]]
    158 %main = OpFunction %void None %13
    159 %22 = OpLabel
    160 %local = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
    161 %24 = OpLoad %int %in_var_INDEX
    162 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
    163 %26 = OpLoad %_arr_v4float_uint_8 %25
    164 %27 = OpCompositeExtract %v4float %26 0
    165 %28 = OpCompositeExtract %v4float %26 1
    166 %29 = OpCompositeExtract %v4float %26 2
    167 %30 = OpCompositeExtract %v4float %26 3
    168 %31 = OpCompositeExtract %v4float %26 4
    169 %32 = OpCompositeExtract %v4float %26 5
    170 %33 = OpCompositeExtract %v4float %26 6
    171 %34 = OpCompositeExtract %v4float %26 7
    172 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
    173 OpStore %local %35
    174 %36 = OpAccessChain %_ptr_Function_v4float %local %24
    175 %37 = OpLoad %v4float %36
    176 OpStore %out_var_SV_Target %37
    177 OpReturn
    178 OpFunctionEnd
    179 )";
    180 
    181   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    182   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    183                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    184   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
    185 }
    186 
    187 // Propagate 2d array.  This test identifying a copy through multiple levels.
    188 // Also has to traverse multiple OpAccessChains.
    189 TEST_F(CopyPropArrayPassTest, Propagate2DArray) {
    190   const std::string text =
    191       R"(OpCapability Shader
    192 OpMemoryModel Logical GLSL450
    193 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
    194 OpExecutionMode %main OriginUpperLeft
    195 OpSource HLSL 600
    196 OpName %type_MyCBuffer "type.MyCBuffer"
    197 OpMemberName %type_MyCBuffer 0 "Data"
    198 OpName %MyCBuffer "MyCBuffer"
    199 OpName %main "main"
    200 OpName %in_var_INDEX "in.var.INDEX"
    201 OpName %out_var_SV_Target "out.var.SV_Target"
    202 OpDecorate %_arr_v4float_uint_2 ArrayStride 16
    203 OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
    204 OpMemberDecorate %type_MyCBuffer 0 Offset 0
    205 OpDecorate %type_MyCBuffer Block
    206 OpDecorate %in_var_INDEX Flat
    207 OpDecorate %in_var_INDEX Location 0
    208 OpDecorate %out_var_SV_Target Location 0
    209 OpDecorate %MyCBuffer DescriptorSet 0
    210 OpDecorate %MyCBuffer Binding 0
    211 %float = OpTypeFloat 32
    212 %v4float = OpTypeVector %float 4
    213 %uint = OpTypeInt 32 0
    214 %uint_2 = OpConstant %uint 2
    215 %_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
    216 %_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
    217 %type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
    218 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
    219 %void = OpTypeVoid
    220 %14 = OpTypeFunction %void
    221 %int = OpTypeInt 32 1
    222 %_ptr_Input_int = OpTypePointer Input %int
    223 %_ptr_Output_v4float = OpTypePointer Output %v4float
    224 %_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
    225 %_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
    226 %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
    227 %int_0 = OpConstant %int 0
    228 %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
    229 %_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
    230 %_ptr_Function_v4float = OpTypePointer Function %v4float
    231 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
    232 %in_var_INDEX = OpVariable %_ptr_Input_int Input
    233 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
    234 ; CHECK: OpFunction
    235 ; CHECK: OpLabel
    236 ; CHECK: OpVariable
    237 ; CHECK: OpVariable
    238 ; CHECK: OpAccessChain
    239 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
    240 %main = OpFunction %void None %14
    241 %25 = OpLabel
    242 %26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
    243 %27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
    244 %28 = OpLoad %int %in_var_INDEX
    245 %29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
    246 %30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
    247 %31 = OpCompositeExtract %_arr_v4float_uint_2 %30 0
    248 %32 = OpCompositeExtract %v4float %31 0
    249 %33 = OpCompositeExtract %v4float %31 1
    250 %34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
    251 %35 = OpCompositeExtract %_arr_v4float_uint_2 %30 1
    252 %36 = OpCompositeExtract %v4float %35 0
    253 %37 = OpCompositeExtract %v4float %35 1
    254 %38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
    255 %39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
    256 ; CHECK: OpStore
    257 OpStore %27 %39
    258 %40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
    259 %42 = OpAccessChain %_ptr_Function_v4float %40 %28
    260 %43 = OpLoad %v4float %42
    261 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 [[new_address]] %28
    262 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[ac1]] %28
    263 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[ac2]]
    264 ; CHECK: OpStore %out_var_SV_Target [[load]]
    265 OpStore %out_var_SV_Target %43
    266 OpReturn
    267 OpFunctionEnd
    268 )";
    269 
    270   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    271   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    272                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    273   SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
    274 }
    275 
    276 // Propagate 2d array.  This test identifying a copy through multiple levels.
    277 // Also has to traverse multiple OpAccessChains.
    278 TEST_F(CopyPropArrayPassTest, Propagate2DArrayWithMultiLevelExtract) {
    279   const std::string text =
    280       R"(OpCapability Shader
    281 OpMemoryModel Logical GLSL450
    282 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
    283 OpExecutionMode %main OriginUpperLeft
    284 OpSource HLSL 600
    285 OpName %type_MyCBuffer "type.MyCBuffer"
    286 OpMemberName %type_MyCBuffer 0 "Data"
    287 OpName %MyCBuffer "MyCBuffer"
    288 OpName %main "main"
    289 OpName %in_var_INDEX "in.var.INDEX"
    290 OpName %out_var_SV_Target "out.var.SV_Target"
    291 OpDecorate %_arr_v4float_uint_2 ArrayStride 16
    292 OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
    293 OpMemberDecorate %type_MyCBuffer 0 Offset 0
    294 OpDecorate %type_MyCBuffer Block
    295 OpDecorate %in_var_INDEX Flat
    296 OpDecorate %in_var_INDEX Location 0
    297 OpDecorate %out_var_SV_Target Location 0
    298 OpDecorate %MyCBuffer DescriptorSet 0
    299 OpDecorate %MyCBuffer Binding 0
    300 %float = OpTypeFloat 32
    301 %v4float = OpTypeVector %float 4
    302 %uint = OpTypeInt 32 0
    303 %uint_2 = OpConstant %uint 2
    304 %_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
    305 %_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
    306 %type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
    307 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
    308 %void = OpTypeVoid
    309 %14 = OpTypeFunction %void
    310 %int = OpTypeInt 32 1
    311 %_ptr_Input_int = OpTypePointer Input %int
    312 %_ptr_Output_v4float = OpTypePointer Output %v4float
    313 %_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
    314 %_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
    315 %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
    316 %int_0 = OpConstant %int 0
    317 %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
    318 %_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
    319 %_ptr_Function_v4float = OpTypePointer Function %v4float
    320 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
    321 %in_var_INDEX = OpVariable %_ptr_Input_int Input
    322 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
    323 ; CHECK: OpFunction
    324 ; CHECK: OpLabel
    325 ; CHECK: OpVariable
    326 ; CHECK: OpVariable
    327 ; CHECK: OpAccessChain
    328 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
    329 %main = OpFunction %void None %14
    330 %25 = OpLabel
    331 %26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
    332 %27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
    333 %28 = OpLoad %int %in_var_INDEX
    334 %29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
    335 %30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
    336 %32 = OpCompositeExtract %v4float %30 0 0
    337 %33 = OpCompositeExtract %v4float %30 0 1
    338 %34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
    339 %36 = OpCompositeExtract %v4float %30 1 0
    340 %37 = OpCompositeExtract %v4float %30 1 1
    341 %38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
    342 %39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
    343 ; CHECK: OpStore
    344 OpStore %27 %39
    345 %40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
    346 %42 = OpAccessChain %_ptr_Function_v4float %40 %28
    347 %43 = OpLoad %v4float %42
    348 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 [[new_address]] %28
    349 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[ac1]] %28
    350 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[ac2]]
    351 ; CHECK: OpStore %out_var_SV_Target [[load]]
    352 OpStore %out_var_SV_Target %43
    353 OpReturn
    354 OpFunctionEnd
    355 )";
    356 
    357   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    358   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    359                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    360   SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
    361 }
    362 
    363 // Test decomposing an object when we need to "rewrite" a store.
    364 TEST_F(CopyPropArrayPassTest, DecomposeObjectForArrayStore) {
    365   const std::string text =
    366       R"(               OpCapability Shader
    367                OpMemoryModel Logical GLSL450
    368                OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
    369                OpExecutionMode %main OriginUpperLeft
    370                OpSource HLSL 600
    371                OpName %type_MyCBuffer "type.MyCBuffer"
    372                OpMemberName %type_MyCBuffer 0 "Data"
    373                OpName %MyCBuffer "MyCBuffer"
    374                OpName %main "main"
    375                OpName %in_var_INDEX "in.var.INDEX"
    376                OpName %out_var_SV_Target "out.var.SV_Target"
    377                OpDecorate %_arr_v4float_uint_2 ArrayStride 16
    378                OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
    379                OpMemberDecorate %type_MyCBuffer 0 Offset 0
    380                OpDecorate %type_MyCBuffer Block
    381                OpDecorate %in_var_INDEX Flat
    382                OpDecorate %in_var_INDEX Location 0
    383                OpDecorate %out_var_SV_Target Location 0
    384                OpDecorate %MyCBuffer DescriptorSet 0
    385                OpDecorate %MyCBuffer Binding 0
    386       %float = OpTypeFloat 32
    387     %v4float = OpTypeVector %float 4
    388        %uint = OpTypeInt 32 0
    389      %uint_2 = OpConstant %uint 2
    390 %_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
    391 %_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
    392 %type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
    393 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
    394        %void = OpTypeVoid
    395          %14 = OpTypeFunction %void
    396         %int = OpTypeInt 32 1
    397 %_ptr_Input_int = OpTypePointer Input %int
    398 %_ptr_Output_v4float = OpTypePointer Output %v4float
    399 %_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
    400 %_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
    401 %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
    402       %int_0 = OpConstant %int 0
    403 %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
    404 %_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
    405 %_ptr_Function_v4float = OpTypePointer Function %v4float
    406   %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
    407 %in_var_INDEX = OpVariable %_ptr_Input_int Input
    408 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
    409        %main = OpFunction %void None %14
    410          %25 = OpLabel
    411          %26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
    412          %27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
    413          %28 = OpLoad %int %in_var_INDEX
    414          %29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
    415          %30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
    416          %31 = OpCompositeExtract %_arr_v4float_uint_2 %30 0
    417          %32 = OpCompositeExtract %v4float %31 0
    418          %33 = OpCompositeExtract %v4float %31 1
    419          %34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
    420          %35 = OpCompositeExtract %_arr_v4float_uint_2 %30 1
    421          %36 = OpCompositeExtract %v4float %35 0
    422          %37 = OpCompositeExtract %v4float %35 1
    423          %38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
    424          %39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
    425                OpStore %27 %39
    426 ; CHECK: [[access_chain:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2
    427          %40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
    428 ; CHECK: [[load:%\w+]] = OpLoad %_arr_v4float_uint_2 [[access_chain]]
    429          %41 = OpLoad %_arr_v4float_uint_2_0 %40
    430 ; CHECK: [[extract1:%\w+]] = OpCompositeExtract %v4float [[load]] 0
    431 ; CHECK: [[extract2:%\w+]] = OpCompositeExtract %v4float [[load]] 1
    432 ; CHECK: [[construct:%\w+]] = OpCompositeConstruct %_arr_v4float_uint_2_0 [[extract1]] [[extract2]]
    433 ; CHECK: OpStore %26 [[construct]]
    434                OpStore %26 %41
    435          %42 = OpAccessChain %_ptr_Function_v4float %26 %28
    436          %43 = OpLoad %v4float %42
    437                OpStore %out_var_SV_Target %43
    438                OpReturn
    439                OpFunctionEnd
    440 )";
    441 
    442   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    443   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    444                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    445   SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
    446 }
    447 
    448 // Test decomposing an object when we need to "rewrite" a store.
    449 TEST_F(CopyPropArrayPassTest, DecomposeObjectForStructStore) {
    450   const std::string text =
    451       R"(               OpCapability Shader
    452                OpMemoryModel Logical GLSL450
    453                OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
    454                OpExecutionMode %main OriginUpperLeft
    455                OpSource HLSL 600
    456                OpName %type_MyCBuffer "type.MyCBuffer"
    457                OpMemberName %type_MyCBuffer 0 "Data"
    458                OpName %MyCBuffer "MyCBuffer"
    459                OpName %main "main"
    460                OpName %in_var_INDEX "in.var.INDEX"
    461                OpName %out_var_SV_Target "out.var.SV_Target"
    462                OpMemberDecorate %type_MyCBuffer 0 Offset 0
    463                OpDecorate %type_MyCBuffer Block
    464                OpDecorate %in_var_INDEX Flat
    465                OpDecorate %in_var_INDEX Location 0
    466                OpDecorate %out_var_SV_Target Location 0
    467                OpDecorate %MyCBuffer DescriptorSet 0
    468                OpDecorate %MyCBuffer Binding 0
    469 ; CHECK: OpDecorate [[decorated_type:%\w+]] GLSLPacked
    470                OpDecorate %struct GLSLPacked
    471       %float = OpTypeFloat 32
    472     %v4float = OpTypeVector %float 4
    473        %uint = OpTypeInt 32 0
    474      %uint_2 = OpConstant %uint 2
    475 ; CHECK: [[decorated_type]] = OpTypeStruct
    476 %struct = OpTypeStruct %float %uint
    477 %_arr_struct_uint_2 = OpTypeArray %struct %uint_2
    478 %type_MyCBuffer = OpTypeStruct %_arr_struct_uint_2
    479 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
    480        %void = OpTypeVoid
    481          %14 = OpTypeFunction %void
    482         %int = OpTypeInt 32 1
    483 %_ptr_Input_int = OpTypePointer Input %int
    484 %_ptr_Output_v4float = OpTypePointer Output %v4float
    485 ; CHECK: [[struct:%\w+]] = OpTypeStruct %float %uint
    486 %struct_0 = OpTypeStruct %float %uint
    487 %_arr_struct_0_uint_2 = OpTypeArray %struct_0 %uint_2
    488 %_ptr_Function__arr_struct_0_uint_2 = OpTypePointer Function %_arr_struct_0_uint_2
    489       %int_0 = OpConstant %int 0
    490 %_ptr_Uniform__arr_struct_uint_2 = OpTypePointer Uniform %_arr_struct_uint_2
    491 ; CHECK: [[decorated_ptr:%\w+]] = OpTypePointer Uniform [[decorated_type]]
    492 %_ptr_Function_struct_0 = OpTypePointer Function %struct_0
    493 %_ptr_Function_v4float = OpTypePointer Function %v4float
    494   %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
    495 %in_var_INDEX = OpVariable %_ptr_Input_int Input
    496 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
    497        %main = OpFunction %void None %14
    498          %25 = OpLabel
    499          %26 = OpVariable %_ptr_Function_struct_0 Function
    500          %27 = OpVariable %_ptr_Function__arr_struct_0_uint_2 Function
    501          %28 = OpLoad %int %in_var_INDEX
    502          %29 = OpAccessChain %_ptr_Uniform__arr_struct_uint_2 %MyCBuffer %int_0
    503          %30 = OpLoad %_arr_struct_uint_2 %29
    504          %31 = OpCompositeExtract %struct %30 0
    505          %32 = OpCompositeExtract %v4float %31 0
    506          %33 = OpCompositeExtract %v4float %31 1
    507          %34 = OpCompositeConstruct %struct_0 %32 %33
    508          %35 = OpCompositeExtract %struct %30 1
    509          %36 = OpCompositeExtract %float %35 0
    510          %37 = OpCompositeExtract %uint %35 1
    511          %38 = OpCompositeConstruct %struct_0 %36 %37
    512          %39 = OpCompositeConstruct %_arr_struct_0_uint_2 %34 %38
    513                OpStore %27 %39
    514 ; CHECK: [[access_chain:%\w+]] = OpAccessChain [[decorated_ptr]]
    515          %40 = OpAccessChain %_ptr_Function_struct_0 %27 %28
    516 ; CHECK: [[load:%\w+]] = OpLoad [[decorated_type]] [[access_chain]]
    517          %41 = OpLoad %struct_0 %40
    518 ; CHECK: [[extract1:%\w+]] = OpCompositeExtract %float [[load]] 0
    519 ; CHECK: [[extract2:%\w+]] = OpCompositeExtract %uint [[load]] 1
    520 ; CHECK: [[construct:%\w+]] = OpCompositeConstruct [[struct]] [[extract1]] [[extract2]]
    521 ; CHECK: OpStore %26 [[construct]]
    522                OpStore %26 %41
    523          %42 = OpAccessChain %_ptr_Function_v4float %26 %28
    524          %43 = OpLoad %v4float %42
    525                OpStore %out_var_SV_Target %43
    526                OpReturn
    527                OpFunctionEnd
    528 )";
    529 
    530   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    531   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    532                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    533   SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
    534 }
    535 
    536 TEST_F(CopyPropArrayPassTest, CopyViaInserts) {
    537   const std::string before =
    538       R"(
    539 OpCapability Shader
    540 OpMemoryModel Logical GLSL450
    541 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
    542 OpExecutionMode %main OriginUpperLeft
    543 OpSource HLSL 600
    544 OpName %type_MyCBuffer "type.MyCBuffer"
    545 OpMemberName %type_MyCBuffer 0 "Data"
    546 OpName %MyCBuffer "MyCBuffer"
    547 OpName %main "main"
    548 OpName %in_var_INDEX "in.var.INDEX"
    549 OpName %out_var_SV_Target "out.var.SV_Target"
    550 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
    551 OpMemberDecorate %type_MyCBuffer 0 Offset 0
    552 OpDecorate %type_MyCBuffer Block
    553 OpDecorate %in_var_INDEX Flat
    554 OpDecorate %in_var_INDEX Location 0
    555 OpDecorate %out_var_SV_Target Location 0
    556 OpDecorate %MyCBuffer DescriptorSet 0
    557 OpDecorate %MyCBuffer Binding 0
    558 %float = OpTypeFloat 32
    559 %v4float = OpTypeVector %float 4
    560 %uint = OpTypeInt 32 0
    561 %uint_8 = OpConstant %uint 8
    562 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
    563 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
    564 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
    565 %void = OpTypeVoid
    566 %13 = OpTypeFunction %void
    567 %int = OpTypeInt 32 1
    568 %_ptr_Input_int = OpTypePointer Input %int
    569 %_ptr_Output_v4float = OpTypePointer Output %v4float
    570 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
    571 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
    572 %int_0 = OpConstant %int 0
    573 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
    574 %_ptr_Function_v4float = OpTypePointer Function %v4float
    575 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
    576 %in_var_INDEX = OpVariable %_ptr_Input_int Input
    577 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
    578 ; CHECK: OpFunction
    579 ; CHECK: OpLabel
    580 ; CHECK: OpVariable
    581 ; CHECK: OpAccessChain
    582 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
    583 ; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
    584 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
    585 ; CHECK: OpStore %out_var_SV_Target [[load]]
    586 %main = OpFunction %void None %13
    587 %22 = OpLabel
    588 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
    589 %undef = OpUndef %_arr_v4float_uint_8_0
    590 %24 = OpLoad %int %in_var_INDEX
    591 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
    592 %26 = OpLoad %_arr_v4float_uint_8 %25
    593 %27 = OpCompositeExtract %v4float %26 0
    594 %i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
    595 %28 = OpCompositeExtract %v4float %26 1
    596 %i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
    597 %29 = OpCompositeExtract %v4float %26 2
    598 %i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
    599 %30 = OpCompositeExtract %v4float %26 3
    600 %i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
    601 %31 = OpCompositeExtract %v4float %26 4
    602 %i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
    603 %32 = OpCompositeExtract %v4float %26 5
    604 %i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
    605 %33 = OpCompositeExtract %v4float %26 6
    606 %i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
    607 %34 = OpCompositeExtract %v4float %26 7
    608 %i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
    609 OpStore %23 %i7
    610 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
    611 %37 = OpLoad %v4float %36
    612 OpStore %out_var_SV_Target %37
    613 OpReturn
    614 OpFunctionEnd
    615 )";
    616 
    617   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    618   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    619                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    620   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
    621 }
    622 
    623 TEST_F(CopyPropArrayPassTest, IsomorphicTypes1) {
    624   const std::string before =
    625       R"(
    626 ; CHECK: [[int:%\w+]] = OpTypeInt 32 0
    627 ; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
    628 ; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
    629 ; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
    630 ; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
    631 ; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
    632 ; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
    633 ; CHECK: [[p_a1:%\w+]] = OpTypePointer Uniform [[a1]]
    634 ; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
    635 ; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_a1]] [[global_var]] %uint_0
    636 ; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s2]] [[ac1]] %uint_0
    637 ; CHECK: [[ld:%\w+]] = OpLoad [[s2]] [[ac2]]
    638 ; CHECK: [[ex:%\w+]] = OpCompositeExtract [[s1]] [[ld]]
    639                OpCapability Shader
    640           %1 = OpExtInstImport "GLSL.std.450"
    641                OpMemoryModel Logical GLSL450
    642                OpEntryPoint Fragment %2 "PS_main"
    643                OpExecutionMode %2 OriginUpperLeft
    644                OpSource HLSL 600
    645                OpDecorate %3 DescriptorSet 0
    646                OpDecorate %3 Binding 101
    647        %uint = OpTypeInt 32 0
    648      %uint_1 = OpConstant %uint 1
    649   %s1 = OpTypeStruct %uint
    650   %s2 = OpTypeStruct %s1
    651 %a1 = OpTypeArray %s2 %uint_1
    652   %s3 = OpTypeStruct %a1
    653  %s1_1 = OpTypeStruct %uint
    654 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    655        %void = OpTypeVoid
    656          %13 = OpTypeFunction %void
    657      %uint_0 = OpConstant %uint 0
    658  %s1_0 = OpTypeStruct %uint
    659  %s2_0 = OpTypeStruct %s1_0
    660 %a1_0 = OpTypeArray %s2_0 %uint_1
    661  %s3_0 = OpTypeStruct %a1_0
    662 %p_s3 = OpTypePointer Uniform %s3
    663 %p_s3_0 = OpTypePointer Function %s3_0
    664           %3 = OpVariable %p_s3 Uniform
    665 %p_a1_0 = OpTypePointer Function %a1_0
    666 %p_s2_0 = OpTypePointer Function %s2_0
    667           %2 = OpFunction %void None %13
    668          %20 = OpLabel
    669          %21 = OpVariable %p_a1_0 Function
    670          %22 = OpLoad %s3 %3
    671          %23 = OpCompositeExtract %a1 %22 0
    672          %24 = OpCompositeExtract %s2 %23 0
    673          %25 = OpCompositeExtract %s1 %24 0
    674          %26 = OpCompositeExtract %uint %25 0
    675          %27 = OpCompositeConstruct %s1_0 %26
    676          %32 = OpCompositeConstruct %s2_0 %27
    677          %28 = OpCompositeConstruct %a1_0 %32
    678                OpStore %21 %28
    679          %29 = OpAccessChain %p_s2_0 %21 %uint_0
    680          %30 = OpLoad %s2 %29
    681          %31 = OpCompositeExtract %s1 %30 0
    682                OpReturn
    683                OpFunctionEnd
    684 )";
    685 
    686   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    687   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    688                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    689   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
    690 }
    691 
    692 TEST_F(CopyPropArrayPassTest, IsomorphicTypes2) {
    693   const std::string before =
    694       R"(
    695 ; CHECK: [[int:%\w+]] = OpTypeInt 32 0
    696 ; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
    697 ; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
    698 ; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
    699 ; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
    700 ; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
    701 ; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
    702 ; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
    703 ; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]]
    704 ; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0
    705 ; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0
    706 ; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]]
    707 ; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]]
    708                OpCapability Shader
    709           %1 = OpExtInstImport "GLSL.std.450"
    710                OpMemoryModel Logical GLSL450
    711                OpEntryPoint Fragment %2 "PS_main"
    712                OpExecutionMode %2 OriginUpperLeft
    713                OpSource HLSL 600
    714                OpDecorate %3 DescriptorSet 0
    715                OpDecorate %3 Binding 101
    716        %uint = OpTypeInt 32 0
    717      %uint_1 = OpConstant %uint 1
    718   %_struct_6 = OpTypeStruct %uint
    719   %_struct_7 = OpTypeStruct %_struct_6
    720 %_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1
    721   %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1
    722  %_struct_10 = OpTypeStruct %uint
    723 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    724        %void = OpTypeVoid
    725          %13 = OpTypeFunction %void
    726      %uint_0 = OpConstant %uint 0
    727  %_struct_15 = OpTypeStruct %uint
    728 %_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1
    729 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
    730 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
    731           %3 = OpVariable %_ptr_Uniform__struct_9 Uniform
    732 %_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1
    733           %2 = OpFunction %void None %13
    734          %20 = OpLabel
    735          %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function
    736          %22 = OpLoad %_struct_9 %3
    737          %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0
    738          %24 = OpCompositeExtract %_struct_7 %23 0
    739          %25 = OpCompositeExtract %_struct_6 %24 0
    740          %26 = OpCompositeExtract %uint %25 0
    741          %27 = OpCompositeConstruct %_struct_15 %26
    742          %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27
    743                OpStore %21 %28
    744          %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0
    745          %30 = OpLoad %_struct_15 %29
    746          %31 = OpCompositeExtract %uint %30 0
    747                OpReturn
    748                OpFunctionEnd
    749 )";
    750 
    751   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    752   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    753                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    754   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
    755 }
    756 
    757 TEST_F(CopyPropArrayPassTest, IsomorphicTypes3) {
    758   const std::string before =
    759       R"(
    760 ; CHECK: [[int:%\w+]] = OpTypeInt 32 0
    761 ; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
    762 ; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
    763 ; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
    764 ; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
    765 ; CHECK: [[s1_1:%\w+]] = OpTypeStruct [[int]]
    766 ; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
    767 ; CHECK: [[p_s1_1:%\w+]] = OpTypePointer Function [[s1_1]]
    768 ; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
    769 ; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
    770 ; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]]
    771 ; CHECK: [[var:%\w+]] = OpVariable [[p_s1_1]] Function
    772 ; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0
    773 ; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0
    774 ; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]]
    775 ; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]]
    776 ; CHECK: [[copy:%\w+]] = OpCompositeConstruct [[s1_1]] [[ex]]
    777 ; CHECK: OpStore [[var]] [[copy]]
    778                OpCapability Shader
    779           %1 = OpExtInstImport "GLSL.std.450"
    780                OpMemoryModel Logical GLSL450
    781                OpEntryPoint Fragment %2 "PS_main"
    782                OpExecutionMode %2 OriginUpperLeft
    783                OpSource HLSL 600
    784                OpDecorate %3 DescriptorSet 0
    785                OpDecorate %3 Binding 101
    786        %uint = OpTypeInt 32 0
    787      %uint_1 = OpConstant %uint 1
    788   %_struct_6 = OpTypeStruct %uint
    789   %_struct_7 = OpTypeStruct %_struct_6
    790 %_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1
    791   %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1
    792 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    793        %void = OpTypeVoid
    794          %13 = OpTypeFunction %void
    795      %uint_0 = OpConstant %uint 0
    796  %_struct_15 = OpTypeStruct %uint
    797  %_struct_10 = OpTypeStruct %uint
    798 %_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1
    799 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
    800 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
    801           %3 = OpVariable %_ptr_Uniform__struct_9 Uniform
    802 %_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1
    803           %2 = OpFunction %void None %13
    804          %20 = OpLabel
    805          %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function
    806         %var = OpVariable %_ptr_Function__struct_15 Function
    807          %22 = OpLoad %_struct_9 %3
    808          %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0
    809          %24 = OpCompositeExtract %_struct_7 %23 0
    810          %25 = OpCompositeExtract %_struct_6 %24 0
    811          %26 = OpCompositeExtract %uint %25 0
    812          %27 = OpCompositeConstruct %_struct_15 %26
    813          %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27
    814                OpStore %21 %28
    815          %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0
    816          %30 = OpLoad %_struct_15 %29
    817                OpStore %var %30
    818                OpReturn
    819                OpFunctionEnd
    820 )";
    821 
    822   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    823   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
    824                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
    825   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
    826 }
    827 
    828 TEST_F(CopyPropArrayPassTest, BadMergingTwoObjects) {
    829   // The second element in the |OpCompositeConstruct| is from a different
    830   // object.
    831   const std::string text =
    832       R"(OpCapability Shader
    833 OpMemoryModel Logical GLSL450
    834 OpEntryPoint Fragment %main "main"
    835 OpExecutionMode %main OriginUpperLeft
    836 OpName %type_ConstBuf "type.ConstBuf"
    837 OpMemberName %type_ConstBuf 0 "TexSizeU"
    838 OpMemberName %type_ConstBuf 1 "TexSizeV"
    839 OpName %ConstBuf "ConstBuf"
    840 OpName %main "main"
    841 OpMemberDecorate %type_ConstBuf 0 Offset 0
    842 OpMemberDecorate %type_ConstBuf 1 Offset 8
    843 OpDecorate %type_ConstBuf Block
    844 OpDecorate %ConstBuf DescriptorSet 0
    845 OpDecorate %ConstBuf Binding 2
    846 %float = OpTypeFloat 32
    847 %v2float = OpTypeVector %float 2
    848 %type_ConstBuf = OpTypeStruct %v2float %v2float
    849 %_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf
    850 %void = OpTypeVoid
    851 %9 = OpTypeFunction %void
    852 %uint = OpTypeInt 32 0
    853 %int_0 = OpConstant %uint 0
    854 %uint_2 = OpConstant %uint 2
    855 %_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2
    856 %_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2
    857 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
    858 %ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
    859 %main = OpFunction %void None %9
    860 %24 = OpLabel
    861 %25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function
    862 %27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
    863 %28 = OpLoad %v2float %27
    864 %29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
    865 %30 = OpLoad %v2float %29
    866 %31 = OpFNegate %v2float %30
    867 %37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %31
    868 OpStore %25 %37
    869 OpReturn
    870 OpFunctionEnd
    871 )";
    872 
    873   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
    874       text, /* skip_nop = */ true, /* do_validation = */ false);
    875   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    876 }
    877 
    878 TEST_F(CopyPropArrayPassTest, SecondElementNotContained) {
    879   // The second element in the |OpCompositeConstruct| is not a memory object.
    880   // Make sure no change happends.
    881   const std::string text =
    882       R"(OpCapability Shader
    883 OpMemoryModel Logical GLSL450
    884 OpEntryPoint Fragment %main "main"
    885 OpExecutionMode %main OriginUpperLeft
    886 OpName %type_ConstBuf "type.ConstBuf"
    887 OpMemberName %type_ConstBuf 0 "TexSizeU"
    888 OpMemberName %type_ConstBuf 1 "TexSizeV"
    889 OpName %ConstBuf "ConstBuf"
    890 OpName %main "main"
    891 OpMemberDecorate %type_ConstBuf 0 Offset 0
    892 OpMemberDecorate %type_ConstBuf 1 Offset 8
    893 OpDecorate %type_ConstBuf Block
    894 OpDecorate %ConstBuf DescriptorSet 0
    895 OpDecorate %ConstBuf Binding 2
    896 OpDecorate %ConstBuf2 DescriptorSet 1
    897 OpDecorate %ConstBuf2 Binding 2
    898 %float = OpTypeFloat 32
    899 %v2float = OpTypeVector %float 2
    900 %type_ConstBuf = OpTypeStruct %v2float %v2float
    901 %_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf
    902 %void = OpTypeVoid
    903 %9 = OpTypeFunction %void
    904 %uint = OpTypeInt 32 0
    905 %int_0 = OpConstant %uint 0
    906 %int_1 = OpConstant %uint 1
    907 %uint_2 = OpConstant %uint 2
    908 %_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2
    909 %_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2
    910 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
    911 %ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
    912 %ConstBuf2 = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
    913 %main = OpFunction %void None %9
    914 %24 = OpLabel
    915 %25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function
    916 %27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
    917 %28 = OpLoad %v2float %27
    918 %29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf2 %int_1
    919 %30 = OpLoad %v2float %29
    920 %37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %30
    921 OpStore %25 %37
    922 OpReturn
    923 OpFunctionEnd
    924 )";
    925 
    926   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
    927       text, /* skip_nop = */ true, /* do_validation = */ false);
    928   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    929 }
    930 // This test will place a load before the store.  We cannot propagate in this
    931 // case.
    932 TEST_F(CopyPropArrayPassTest, LoadBeforeStore) {
    933   const std::string text =
    934       R"(
    935 OpCapability Shader
    936 OpMemoryModel Logical GLSL450
    937 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
    938 OpExecutionMode %main OriginUpperLeft
    939 OpSource HLSL 600
    940 OpName %type_MyCBuffer "type.MyCBuffer"
    941 OpMemberName %type_MyCBuffer 0 "Data"
    942 OpName %MyCBuffer "MyCBuffer"
    943 OpName %main "main"
    944 OpName %in_var_INDEX "in.var.INDEX"
    945 OpName %out_var_SV_Target "out.var.SV_Target"
    946 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
    947 OpMemberDecorate %type_MyCBuffer 0 Offset 0
    948 OpDecorate %type_MyCBuffer Block
    949 OpDecorate %in_var_INDEX Flat
    950 OpDecorate %in_var_INDEX Location 0
    951 OpDecorate %out_var_SV_Target Location 0
    952 OpDecorate %MyCBuffer DescriptorSet 0
    953 OpDecorate %MyCBuffer Binding 0
    954 %float = OpTypeFloat 32
    955 %v4float = OpTypeVector %float 4
    956 %uint = OpTypeInt 32 0
    957 %uint_8 = OpConstant %uint 8
    958 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
    959 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
    960 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
    961 %void = OpTypeVoid
    962 %13 = OpTypeFunction %void
    963 %int = OpTypeInt 32 1
    964 %_ptr_Input_int = OpTypePointer Input %int
    965 %_ptr_Output_v4float = OpTypePointer Output %v4float
    966 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
    967 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
    968 %int_0 = OpConstant %int 0
    969 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
    970 %_ptr_Function_v4float = OpTypePointer Function %v4float
    971 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
    972 %in_var_INDEX = OpVariable %_ptr_Input_int Input
    973 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
    974 %main = OpFunction %void None %13
    975 %22 = OpLabel
    976 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
    977 %38 = OpAccessChain %_ptr_Function_v4float %23 %24
    978 %39 = OpLoad %v4float %36
    979 %24 = OpLoad %int %in_var_INDEX
    980 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
    981 %26 = OpLoad %_arr_v4float_uint_8 %25
    982 %27 = OpCompositeExtract %v4float %26 0
    983 %28 = OpCompositeExtract %v4float %26 1
    984 %29 = OpCompositeExtract %v4float %26 2
    985 %30 = OpCompositeExtract %v4float %26 3
    986 %31 = OpCompositeExtract %v4float %26 4
    987 %32 = OpCompositeExtract %v4float %26 5
    988 %33 = OpCompositeExtract %v4float %26 6
    989 %34 = OpCompositeExtract %v4float %26 7
    990 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
    991 OpStore %23 %35
    992 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
    993 %37 = OpLoad %v4float %36
    994 OpStore %out_var_SV_Target %37
    995 OpReturn
    996 OpFunctionEnd
    997 )";
    998 
    999   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1000   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
   1001                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
   1002   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
   1003       text, /* skip_nop = */ true, /* do_validation = */ false);
   1004 
   1005   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
   1006 }
   1007 
   1008 // This test will place a load where it is not dominated by the store.  We
   1009 // cannot propagate in this case.
   1010 TEST_F(CopyPropArrayPassTest, LoadNotDominated) {
   1011   const std::string text =
   1012       R"(
   1013 OpCapability Shader
   1014 OpMemoryModel Logical GLSL450
   1015 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
   1016 OpExecutionMode %main OriginUpperLeft
   1017 OpSource HLSL 600
   1018 OpName %type_MyCBuffer "type.MyCBuffer"
   1019 OpMemberName %type_MyCBuffer 0 "Data"
   1020 OpName %MyCBuffer "MyCBuffer"
   1021 OpName %main "main"
   1022 OpName %in_var_INDEX "in.var.INDEX"
   1023 OpName %out_var_SV_Target "out.var.SV_Target"
   1024 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
   1025 OpMemberDecorate %type_MyCBuffer 0 Offset 0
   1026 OpDecorate %type_MyCBuffer Block
   1027 OpDecorate %in_var_INDEX Flat
   1028 OpDecorate %in_var_INDEX Location 0
   1029 OpDecorate %out_var_SV_Target Location 0
   1030 OpDecorate %MyCBuffer DescriptorSet 0
   1031 OpDecorate %MyCBuffer Binding 0
   1032 %bool = OpTypeBool
   1033 %true = OpConstantTrue %bool
   1034 %float = OpTypeFloat 32
   1035 %v4float = OpTypeVector %float 4
   1036 %uint = OpTypeInt 32 0
   1037 %uint_8 = OpConstant %uint 8
   1038 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
   1039 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
   1040 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
   1041 %void = OpTypeVoid
   1042 %13 = OpTypeFunction %void
   1043 %int = OpTypeInt 32 1
   1044 %_ptr_Input_int = OpTypePointer Input %int
   1045 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1046 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
   1047 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
   1048 %int_0 = OpConstant %int 0
   1049 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
   1050 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1051 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
   1052 %in_var_INDEX = OpVariable %_ptr_Input_int Input
   1053 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
   1054 %main = OpFunction %void None %13
   1055 %22 = OpLabel
   1056 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
   1057 OpSelectionMerge %merge None
   1058 OpBranchConditional %true %if %else
   1059 %if = OpLabel
   1060 %24 = OpLoad %int %in_var_INDEX
   1061 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
   1062 %26 = OpLoad %_arr_v4float_uint_8 %25
   1063 %27 = OpCompositeExtract %v4float %26 0
   1064 %28 = OpCompositeExtract %v4float %26 1
   1065 %29 = OpCompositeExtract %v4float %26 2
   1066 %30 = OpCompositeExtract %v4float %26 3
   1067 %31 = OpCompositeExtract %v4float %26 4
   1068 %32 = OpCompositeExtract %v4float %26 5
   1069 %33 = OpCompositeExtract %v4float %26 6
   1070 %34 = OpCompositeExtract %v4float %26 7
   1071 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
   1072 OpStore %23 %35
   1073 %38 = OpAccessChain %_ptr_Function_v4float %23 %24
   1074 %39 = OpLoad %v4float %36
   1075 OpBranch %merge
   1076 %else = OpLabel
   1077 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
   1078 %37 = OpLoad %v4float %36
   1079 OpBranch %merge
   1080 %merge = OpLabel
   1081 %phi = OpPhi %out_var_SV_Target %39 %if %37 %else
   1082 OpStore %out_var_SV_Target %phi
   1083 OpReturn
   1084 OpFunctionEnd
   1085 )";
   1086 
   1087   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1088   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
   1089                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
   1090   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
   1091       text, /* skip_nop = */ true, /* do_validation = */ false);
   1092 
   1093   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
   1094 }
   1095 
   1096 // This test has a partial store to the variable.  We cannot propagate in this
   1097 // case.
   1098 TEST_F(CopyPropArrayPassTest, PartialStore) {
   1099   const std::string text =
   1100       R"(
   1101 OpCapability Shader
   1102 OpMemoryModel Logical GLSL450
   1103 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
   1104 OpExecutionMode %main OriginUpperLeft
   1105 OpSource HLSL 600
   1106 OpName %type_MyCBuffer "type.MyCBuffer"
   1107 OpMemberName %type_MyCBuffer 0 "Data"
   1108 OpName %MyCBuffer "MyCBuffer"
   1109 OpName %main "main"
   1110 OpName %in_var_INDEX "in.var.INDEX"
   1111 OpName %out_var_SV_Target "out.var.SV_Target"
   1112 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
   1113 OpMemberDecorate %type_MyCBuffer 0 Offset 0
   1114 OpDecorate %type_MyCBuffer Block
   1115 OpDecorate %in_var_INDEX Flat
   1116 OpDecorate %in_var_INDEX Location 0
   1117 OpDecorate %out_var_SV_Target Location 0
   1118 OpDecorate %MyCBuffer DescriptorSet 0
   1119 OpDecorate %MyCBuffer Binding 0
   1120 %float = OpTypeFloat 32
   1121 %v4float = OpTypeVector %float 4
   1122 %uint = OpTypeInt 32 0
   1123 %uint_8 = OpConstant %uint 8
   1124 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
   1125 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
   1126 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
   1127 %void = OpTypeVoid
   1128 %13 = OpTypeFunction %void
   1129 %int = OpTypeInt 32 1
   1130 %_ptr_Input_int = OpTypePointer Input %int
   1131 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1132 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
   1133 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
   1134 %int_0 = OpConstant %int 0
   1135 %f0 = OpConstant %float 0
   1136 %v4const = OpConstantComposite %v4float %f0 %f0 %f0 %f0
   1137 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
   1138 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1139 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
   1140 %in_var_INDEX = OpVariable %_ptr_Input_int Input
   1141 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
   1142 %main = OpFunction %void None %13
   1143 %22 = OpLabel
   1144 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
   1145 %24 = OpLoad %int %in_var_INDEX
   1146 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
   1147 %26 = OpLoad %_arr_v4float_uint_8 %25
   1148 %27 = OpCompositeExtract %v4float %26 0
   1149 %28 = OpCompositeExtract %v4float %26 1
   1150 %29 = OpCompositeExtract %v4float %26 2
   1151 %30 = OpCompositeExtract %v4float %26 3
   1152 %31 = OpCompositeExtract %v4float %26 4
   1153 %32 = OpCompositeExtract %v4float %26 5
   1154 %33 = OpCompositeExtract %v4float %26 6
   1155 %34 = OpCompositeExtract %v4float %26 7
   1156 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
   1157 OpStore %23 %35
   1158 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
   1159 %37 = OpLoad %v4float %36
   1160 %39 = OpStore %36 %v4const
   1161 OpStore %out_var_SV_Target %37
   1162 OpReturn
   1163 OpFunctionEnd
   1164 )";
   1165 
   1166   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1167   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
   1168                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
   1169   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
   1170       text, /* skip_nop = */ true, /* do_validation = */ false);
   1171 
   1172   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
   1173 }
   1174 
   1175 // This test does not have a proper copy of an object.  We cannot propagate in
   1176 // this case.
   1177 TEST_F(CopyPropArrayPassTest, NotACopy) {
   1178   const std::string text =
   1179       R"(
   1180 OpCapability Shader
   1181 OpMemoryModel Logical GLSL450
   1182 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
   1183 OpExecutionMode %main OriginUpperLeft
   1184 OpSource HLSL 600
   1185 OpName %type_MyCBuffer "type.MyCBuffer"
   1186 OpMemberName %type_MyCBuffer 0 "Data"
   1187 OpName %MyCBuffer "MyCBuffer"
   1188 OpName %main "main"
   1189 OpName %in_var_INDEX "in.var.INDEX"
   1190 OpName %out_var_SV_Target "out.var.SV_Target"
   1191 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
   1192 OpMemberDecorate %type_MyCBuffer 0 Offset 0
   1193 OpDecorate %type_MyCBuffer Block
   1194 OpDecorate %in_var_INDEX Flat
   1195 OpDecorate %in_var_INDEX Location 0
   1196 OpDecorate %out_var_SV_Target Location 0
   1197 OpDecorate %MyCBuffer DescriptorSet 0
   1198 OpDecorate %MyCBuffer Binding 0
   1199 %float = OpTypeFloat 32
   1200 %v4float = OpTypeVector %float 4
   1201 %uint = OpTypeInt 32 0
   1202 %uint_8 = OpConstant %uint 8
   1203 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
   1204 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
   1205 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
   1206 %void = OpTypeVoid
   1207 %13 = OpTypeFunction %void
   1208 %int = OpTypeInt 32 1
   1209 %_ptr_Input_int = OpTypePointer Input %int
   1210 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1211 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
   1212 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
   1213 %int_0 = OpConstant %int 0
   1214 %f0 = OpConstant %float 0
   1215 %v4const = OpConstantComposite %v4float %f0 %f0 %f0 %f0
   1216 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
   1217 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1218 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
   1219 %in_var_INDEX = OpVariable %_ptr_Input_int Input
   1220 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
   1221 %main = OpFunction %void None %13
   1222 %22 = OpLabel
   1223 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
   1224 %24 = OpLoad %int %in_var_INDEX
   1225 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
   1226 %26 = OpLoad %_arr_v4float_uint_8 %25
   1227 %27 = OpCompositeExtract %v4float %26 0
   1228 %28 = OpCompositeExtract %v4float %26 0
   1229 %29 = OpCompositeExtract %v4float %26 2
   1230 %30 = OpCompositeExtract %v4float %26 3
   1231 %31 = OpCompositeExtract %v4float %26 4
   1232 %32 = OpCompositeExtract %v4float %26 5
   1233 %33 = OpCompositeExtract %v4float %26 6
   1234 %34 = OpCompositeExtract %v4float %26 7
   1235 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
   1236 OpStore %23 %35
   1237 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
   1238 %37 = OpLoad %v4float %36
   1239 OpStore %out_var_SV_Target %37
   1240 OpReturn
   1241 OpFunctionEnd
   1242 )";
   1243 
   1244   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1245   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
   1246                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
   1247   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
   1248       text, /* skip_nop = */ true, /* do_validation = */ false);
   1249 
   1250   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
   1251 }
   1252 
   1253 TEST_F(CopyPropArrayPassTest, BadCopyViaInserts1) {
   1254   const std::string text =
   1255       R"(
   1256 OpCapability Shader
   1257 OpMemoryModel Logical GLSL450
   1258 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
   1259 OpExecutionMode %main OriginUpperLeft
   1260 OpSource HLSL 600
   1261 OpName %type_MyCBuffer "type.MyCBuffer"
   1262 OpMemberName %type_MyCBuffer 0 "Data"
   1263 OpName %MyCBuffer "MyCBuffer"
   1264 OpName %main "main"
   1265 OpName %in_var_INDEX "in.var.INDEX"
   1266 OpName %out_var_SV_Target "out.var.SV_Target"
   1267 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
   1268 OpMemberDecorate %type_MyCBuffer 0 Offset 0
   1269 OpDecorate %type_MyCBuffer Block
   1270 OpDecorate %in_var_INDEX Flat
   1271 OpDecorate %in_var_INDEX Location 0
   1272 OpDecorate %out_var_SV_Target Location 0
   1273 OpDecorate %MyCBuffer DescriptorSet 0
   1274 OpDecorate %MyCBuffer Binding 0
   1275 %float = OpTypeFloat 32
   1276 %v4float = OpTypeVector %float 4
   1277 %uint = OpTypeInt 32 0
   1278 %uint_8 = OpConstant %uint 8
   1279 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
   1280 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
   1281 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
   1282 %void = OpTypeVoid
   1283 %13 = OpTypeFunction %void
   1284 %int = OpTypeInt 32 1
   1285 %_ptr_Input_int = OpTypePointer Input %int
   1286 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1287 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
   1288 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
   1289 %int_0 = OpConstant %int 0
   1290 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
   1291 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1292 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
   1293 %in_var_INDEX = OpVariable %_ptr_Input_int Input
   1294 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
   1295 %main = OpFunction %void None %13
   1296 %22 = OpLabel
   1297 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
   1298 %undef = OpUndef %_arr_v4float_uint_8_0
   1299 %24 = OpLoad %int %in_var_INDEX
   1300 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
   1301 %26 = OpLoad %_arr_v4float_uint_8 %25
   1302 %27 = OpCompositeExtract %v4float %26 0
   1303 %i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
   1304 %28 = OpCompositeExtract %v4float %26 1
   1305 %i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
   1306 %29 = OpCompositeExtract %v4float %26 2
   1307 %i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 3
   1308 %30 = OpCompositeExtract %v4float %26 3
   1309 %i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
   1310 %31 = OpCompositeExtract %v4float %26 4
   1311 %i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
   1312 %32 = OpCompositeExtract %v4float %26 5
   1313 %i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
   1314 %33 = OpCompositeExtract %v4float %26 6
   1315 %i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
   1316 %34 = OpCompositeExtract %v4float %26 7
   1317 %i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
   1318 OpStore %23 %i7
   1319 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
   1320 %37 = OpLoad %v4float %36
   1321 OpStore %out_var_SV_Target %37
   1322 OpReturn
   1323 OpFunctionEnd
   1324 )";
   1325 
   1326   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1327   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
   1328                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
   1329   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
   1330       text, /* skip_nop = */ true, /* do_validation = */ false);
   1331 
   1332   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
   1333 }
   1334 
   1335 TEST_F(CopyPropArrayPassTest, BadCopyViaInserts2) {
   1336   const std::string text =
   1337       R"(
   1338 OpCapability Shader
   1339 OpMemoryModel Logical GLSL450
   1340 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
   1341 OpExecutionMode %main OriginUpperLeft
   1342 OpSource HLSL 600
   1343 OpName %type_MyCBuffer "type.MyCBuffer"
   1344 OpMemberName %type_MyCBuffer 0 "Data"
   1345 OpName %MyCBuffer "MyCBuffer"
   1346 OpName %main "main"
   1347 OpName %in_var_INDEX "in.var.INDEX"
   1348 OpName %out_var_SV_Target "out.var.SV_Target"
   1349 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
   1350 OpMemberDecorate %type_MyCBuffer 0 Offset 0
   1351 OpDecorate %type_MyCBuffer Block
   1352 OpDecorate %in_var_INDEX Flat
   1353 OpDecorate %in_var_INDEX Location 0
   1354 OpDecorate %out_var_SV_Target Location 0
   1355 OpDecorate %MyCBuffer DescriptorSet 0
   1356 OpDecorate %MyCBuffer Binding 0
   1357 %float = OpTypeFloat 32
   1358 %v4float = OpTypeVector %float 4
   1359 %uint = OpTypeInt 32 0
   1360 %uint_8 = OpConstant %uint 8
   1361 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
   1362 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
   1363 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
   1364 %void = OpTypeVoid
   1365 %13 = OpTypeFunction %void
   1366 %int = OpTypeInt 32 1
   1367 %_ptr_Input_int = OpTypePointer Input %int
   1368 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1369 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
   1370 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
   1371 %int_0 = OpConstant %int 0
   1372 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
   1373 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1374 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
   1375 %in_var_INDEX = OpVariable %_ptr_Input_int Input
   1376 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
   1377 %main = OpFunction %void None %13
   1378 %22 = OpLabel
   1379 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
   1380 %undef = OpUndef %_arr_v4float_uint_8_0
   1381 %24 = OpLoad %int %in_var_INDEX
   1382 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
   1383 %26 = OpLoad %_arr_v4float_uint_8 %25
   1384 %27 = OpCompositeExtract %v4float %26 0
   1385 %i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
   1386 %28 = OpCompositeExtract %v4float %26 1
   1387 %i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
   1388 %29 = OpCompositeExtract %v4float %26 3
   1389 %i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
   1390 %30 = OpCompositeExtract %v4float %26 3
   1391 %i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
   1392 %31 = OpCompositeExtract %v4float %26 4
   1393 %i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
   1394 %32 = OpCompositeExtract %v4float %26 5
   1395 %i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
   1396 %33 = OpCompositeExtract %v4float %26 6
   1397 %i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
   1398 %34 = OpCompositeExtract %v4float %26 7
   1399 %i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
   1400 OpStore %23 %i7
   1401 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
   1402 %37 = OpLoad %v4float %36
   1403 OpStore %out_var_SV_Target %37
   1404 OpReturn
   1405 OpFunctionEnd
   1406 )";
   1407 
   1408   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1409   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
   1410                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
   1411   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
   1412       text, /* skip_nop = */ true, /* do_validation = */ false);
   1413 
   1414   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
   1415 }
   1416 
   1417 TEST_F(CopyPropArrayPassTest, BadCopyViaInserts3) {
   1418   const std::string text =
   1419       R"(
   1420 OpCapability Shader
   1421 OpMemoryModel Logical GLSL450
   1422 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
   1423 OpExecutionMode %main OriginUpperLeft
   1424 OpSource HLSL 600
   1425 OpName %type_MyCBuffer "type.MyCBuffer"
   1426 OpMemberName %type_MyCBuffer 0 "Data"
   1427 OpName %MyCBuffer "MyCBuffer"
   1428 OpName %main "main"
   1429 OpName %in_var_INDEX "in.var.INDEX"
   1430 OpName %out_var_SV_Target "out.var.SV_Target"
   1431 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
   1432 OpMemberDecorate %type_MyCBuffer 0 Offset 0
   1433 OpDecorate %type_MyCBuffer Block
   1434 OpDecorate %in_var_INDEX Flat
   1435 OpDecorate %in_var_INDEX Location 0
   1436 OpDecorate %out_var_SV_Target Location 0
   1437 OpDecorate %MyCBuffer DescriptorSet 0
   1438 OpDecorate %MyCBuffer Binding 0
   1439 %float = OpTypeFloat 32
   1440 %v4float = OpTypeVector %float 4
   1441 %uint = OpTypeInt 32 0
   1442 %uint_8 = OpConstant %uint 8
   1443 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
   1444 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
   1445 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
   1446 %void = OpTypeVoid
   1447 %13 = OpTypeFunction %void
   1448 %int = OpTypeInt 32 1
   1449 %_ptr_Input_int = OpTypePointer Input %int
   1450 %_ptr_Output_v4float = OpTypePointer Output %v4float
   1451 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
   1452 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
   1453 %int_0 = OpConstant %int 0
   1454 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
   1455 %_ptr_Function_v4float = OpTypePointer Function %v4float
   1456 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
   1457 %in_var_INDEX = OpVariable %_ptr_Input_int Input
   1458 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
   1459 %main = OpFunction %void None %13
   1460 %22 = OpLabel
   1461 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
   1462 %undef = OpUndef %_arr_v4float_uint_8_0
   1463 %24 = OpLoad %int %in_var_INDEX
   1464 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
   1465 %26 = OpLoad %_arr_v4float_uint_8 %25
   1466 %28 = OpCompositeExtract %v4float %26 1
   1467 %i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %undef 1
   1468 %29 = OpCompositeExtract %v4float %26 2
   1469 %i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
   1470 %30 = OpCompositeExtract %v4float %26 3
   1471 %i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
   1472 %31 = OpCompositeExtract %v4float %26 4
   1473 %i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
   1474 %32 = OpCompositeExtract %v4float %26 5
   1475 %i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
   1476 %33 = OpCompositeExtract %v4float %26 6
   1477 %i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
   1478 %34 = OpCompositeExtract %v4float %26 7
   1479 %i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
   1480 OpStore %23 %i7
   1481 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
   1482 %37 = OpLoad %v4float %36
   1483 OpStore %out_var_SV_Target %37
   1484 OpReturn
   1485 OpFunctionEnd
   1486 )";
   1487 
   1488   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1489   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
   1490                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
   1491   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
   1492       text, /* skip_nop = */ true, /* do_validation = */ false);
   1493 
   1494   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
   1495 }
   1496 
   1497 TEST_F(CopyPropArrayPassTest, AtomicAdd) {
   1498   const std::string before = R"(OpCapability SampledBuffer
   1499 OpCapability StorageImageExtendedFormats
   1500 OpCapability ImageBuffer
   1501 OpCapability Shader
   1502 %1 = OpExtInstImport "GLSL.std.450"
   1503 OpMemoryModel Logical GLSL450
   1504 OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
   1505 OpExecutionMode %2 LocalSize 64 1 1
   1506 OpSource HLSL 600
   1507 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
   1508 OpDecorate %4 DescriptorSet 4
   1509 OpDecorate %4 Binding 70
   1510 %uint = OpTypeInt 32 0
   1511 %6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
   1512 %_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
   1513 %_ptr_Function_6 = OpTypePointer Function %6
   1514 %void = OpTypeVoid
   1515 %10 = OpTypeFunction %void
   1516 %uint_0 = OpConstant %uint 0
   1517 %uint_1 = OpConstant %uint 1
   1518 %v3uint = OpTypeVector %uint 3
   1519 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
   1520 %_ptr_Image_uint = OpTypePointer Image %uint
   1521 %4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
   1522 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
   1523 %2 = OpFunction %void None %10
   1524 %17 = OpLabel
   1525 %16 = OpVariable %_ptr_Function_6 Function
   1526 %18 = OpLoad %6 %4
   1527 OpStore %16 %18
   1528 %19 = OpImageTexelPointer %_ptr_Image_uint %16 %uint_0 %uint_0
   1529 %20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
   1530 OpReturn
   1531 OpFunctionEnd
   1532 )";
   1533 
   1534   const std::string after = R"(OpCapability SampledBuffer
   1535 OpCapability StorageImageExtendedFormats
   1536 OpCapability ImageBuffer
   1537 OpCapability Shader
   1538 %1 = OpExtInstImport "GLSL.std.450"
   1539 OpMemoryModel Logical GLSL450
   1540 OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
   1541 OpExecutionMode %2 LocalSize 64 1 1
   1542 OpSource HLSL 600
   1543 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
   1544 OpDecorate %4 DescriptorSet 4
   1545 OpDecorate %4 Binding 70
   1546 %uint = OpTypeInt 32 0
   1547 %6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
   1548 %_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
   1549 %_ptr_Function_6 = OpTypePointer Function %6
   1550 %void = OpTypeVoid
   1551 %10 = OpTypeFunction %void
   1552 %uint_0 = OpConstant %uint 0
   1553 %uint_1 = OpConstant %uint 1
   1554 %v3uint = OpTypeVector %uint 3
   1555 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
   1556 %_ptr_Image_uint = OpTypePointer Image %uint
   1557 %4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
   1558 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
   1559 %2 = OpFunction %void None %10
   1560 %17 = OpLabel
   1561 %16 = OpVariable %_ptr_Function_6 Function
   1562 %18 = OpLoad %6 %4
   1563 OpStore %16 %18
   1564 %19 = OpImageTexelPointer %_ptr_Image_uint %4 %uint_0 %uint_0
   1565 %20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
   1566 OpReturn
   1567 OpFunctionEnd
   1568 )";
   1569 
   1570   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   1571   SinglePassRunAndCheck<CopyPropagateArrays>(before, after, true, true);
   1572 }
   1573 
   1574 }  // namespace
   1575 }  // namespace opt
   1576 }  // namespace spvtools
   1577