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