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 <string> 16 17#include "gmock/gmock.h" 18#include "test/opt/assembly_builder.h" 19#include "test/opt/pass_fixture.h" 20 21namespace spvtools { 22namespace opt { 23namespace { 24 25using CopyPropArrayPassTest = PassTest<::testing::Test>; 26 27TEST_F(CopyPropArrayPassTest, BasicPropagateArray) { 28 const std::string before = 29 R"( 30OpCapability Shader 31OpMemoryModel Logical GLSL450 32OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 33OpExecutionMode %main OriginUpperLeft 34OpSource HLSL 600 35OpName %type_MyCBuffer "type.MyCBuffer" 36OpMemberName %type_MyCBuffer 0 "Data" 37OpName %MyCBuffer "MyCBuffer" 38OpName %main "main" 39OpName %in_var_INDEX "in.var.INDEX" 40OpName %out_var_SV_Target "out.var.SV_Target" 41OpDecorate %_arr_v4float_uint_8 ArrayStride 16 42OpMemberDecorate %type_MyCBuffer 0 Offset 0 43OpDecorate %type_MyCBuffer Block 44OpDecorate %in_var_INDEX Flat 45OpDecorate %in_var_INDEX Location 0 46OpDecorate %out_var_SV_Target Location 0 47OpDecorate %MyCBuffer DescriptorSet 0 48OpDecorate %MyCBuffer Binding 0 49%float = OpTypeFloat 32 50%v4float = OpTypeVector %float 4 51%uint = OpTypeInt 32 0 52%uint_8 = OpConstant %uint 8 53%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 54%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 55%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 56%void = OpTypeVoid 57%13 = OpTypeFunction %void 58%int = OpTypeInt 32 1 59%_ptr_Input_int = OpTypePointer Input %int 60%_ptr_Output_v4float = OpTypePointer Output %v4float 61%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 62%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 63%int_0 = OpConstant %int 0 64%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 65%_ptr_Function_v4float = OpTypePointer Function %v4float 66%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 67%in_var_INDEX = OpVariable %_ptr_Input_int Input 68%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 69; CHECK: OpFunction 70; CHECK: OpLabel 71; CHECK: OpVariable 72; CHECK: OpAccessChain 73; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 74; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24 75; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]] 76; CHECK: OpStore %out_var_SV_Target [[load]] 77%main = OpFunction %void None %13 78%22 = OpLabel 79%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 80%24 = OpLoad %int %in_var_INDEX 81%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 82%26 = OpLoad %_arr_v4float_uint_8 %25 83%27 = OpCompositeExtract %v4float %26 0 84%28 = OpCompositeExtract %v4float %26 1 85%29 = OpCompositeExtract %v4float %26 2 86%30 = OpCompositeExtract %v4float %26 3 87%31 = OpCompositeExtract %v4float %26 4 88%32 = OpCompositeExtract %v4float %26 5 89%33 = OpCompositeExtract %v4float %26 6 90%34 = OpCompositeExtract %v4float %26 7 91%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34 92OpStore %23 %35 93%36 = OpAccessChain %_ptr_Function_v4float %23 %24 94%37 = OpLoad %v4float %36 95OpStore %out_var_SV_Target %37 96OpReturn 97OpFunctionEnd 98)"; 99 100 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 101 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 102 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 103 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 104} 105 106TEST_F(CopyPropArrayPassTest, BasicPropagateArrayWithName) { 107 const std::string before = 108 R"( 109OpCapability Shader 110OpMemoryModel Logical GLSL450 111OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 112OpExecutionMode %main OriginUpperLeft 113OpSource HLSL 600 114OpName %type_MyCBuffer "type.MyCBuffer" 115OpMemberName %type_MyCBuffer 0 "Data" 116OpName %MyCBuffer "MyCBuffer" 117OpName %main "main" 118OpName %local "local" 119OpName %in_var_INDEX "in.var.INDEX" 120OpName %out_var_SV_Target "out.var.SV_Target" 121OpDecorate %_arr_v4float_uint_8 ArrayStride 16 122OpMemberDecorate %type_MyCBuffer 0 Offset 0 123OpDecorate %type_MyCBuffer Block 124OpDecorate %in_var_INDEX Flat 125OpDecorate %in_var_INDEX Location 0 126OpDecorate %out_var_SV_Target Location 0 127OpDecorate %MyCBuffer DescriptorSet 0 128OpDecorate %MyCBuffer Binding 0 129%float = OpTypeFloat 32 130%v4float = OpTypeVector %float 4 131%uint = OpTypeInt 32 0 132%uint_8 = OpConstant %uint 8 133%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 134%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 135%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 136%void = OpTypeVoid 137%13 = OpTypeFunction %void 138%int = OpTypeInt 32 1 139%_ptr_Input_int = OpTypePointer Input %int 140%_ptr_Output_v4float = OpTypePointer Output %v4float 141%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 142%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 143%int_0 = OpConstant %int 0 144%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 145%_ptr_Function_v4float = OpTypePointer Function %v4float 146%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 147%in_var_INDEX = OpVariable %_ptr_Input_int Input 148%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 149; CHECK: OpFunction 150; CHECK: OpLabel 151; CHECK: OpVariable 152; CHECK: OpAccessChain 153; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 154; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24 155; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]] 156; CHECK: OpStore %out_var_SV_Target [[load]] 157%main = OpFunction %void None %13 158%22 = OpLabel 159%local = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 160%24 = OpLoad %int %in_var_INDEX 161%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 162%26 = OpLoad %_arr_v4float_uint_8 %25 163%27 = OpCompositeExtract %v4float %26 0 164%28 = OpCompositeExtract %v4float %26 1 165%29 = OpCompositeExtract %v4float %26 2 166%30 = OpCompositeExtract %v4float %26 3 167%31 = OpCompositeExtract %v4float %26 4 168%32 = OpCompositeExtract %v4float %26 5 169%33 = OpCompositeExtract %v4float %26 6 170%34 = OpCompositeExtract %v4float %26 7 171%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34 172OpStore %local %35 173%36 = OpAccessChain %_ptr_Function_v4float %local %24 174%37 = OpLoad %v4float %36 175OpStore %out_var_SV_Target %37 176OpReturn 177OpFunctionEnd 178)"; 179 180 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 181 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 182 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 183 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 184} 185 186// Propagate 2d array. This test identifying a copy through multiple levels. 187// Also has to traverse multiple OpAccessChains. 188TEST_F(CopyPropArrayPassTest, Propagate2DArray) { 189 const std::string text = 190 R"(OpCapability Shader 191OpMemoryModel Logical GLSL450 192OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 193OpExecutionMode %main OriginUpperLeft 194OpSource HLSL 600 195OpName %type_MyCBuffer "type.MyCBuffer" 196OpMemberName %type_MyCBuffer 0 "Data" 197OpName %MyCBuffer "MyCBuffer" 198OpName %main "main" 199OpName %in_var_INDEX "in.var.INDEX" 200OpName %out_var_SV_Target "out.var.SV_Target" 201OpDecorate %_arr_v4float_uint_2 ArrayStride 16 202OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32 203OpMemberDecorate %type_MyCBuffer 0 Offset 0 204OpDecorate %type_MyCBuffer Block 205OpDecorate %in_var_INDEX Flat 206OpDecorate %in_var_INDEX Location 0 207OpDecorate %out_var_SV_Target Location 0 208OpDecorate %MyCBuffer DescriptorSet 0 209OpDecorate %MyCBuffer Binding 0 210%float = OpTypeFloat 32 211%v4float = OpTypeVector %float 4 212%uint = OpTypeInt 32 0 213%uint_2 = OpConstant %uint 2 214%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 215%_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2 216%type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2 217%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 218%void = OpTypeVoid 219%14 = OpTypeFunction %void 220%int = OpTypeInt 32 1 221%_ptr_Input_int = OpTypePointer Input %int 222%_ptr_Output_v4float = OpTypePointer Output %v4float 223%_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2 224%_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2 225%_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2 226%int_0 = OpConstant %int 0 227%_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2 228%_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0 229%_ptr_Function_v4float = OpTypePointer Function %v4float 230%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 231%in_var_INDEX = OpVariable %_ptr_Input_int Input 232%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 233; CHECK: OpFunction 234; CHECK: OpLabel 235; CHECK: OpVariable 236; CHECK: OpVariable 237; CHECK: OpAccessChain 238; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0 239%main = OpFunction %void None %14 240%25 = OpLabel 241%26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function 242%27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function 243%28 = OpLoad %int %in_var_INDEX 244%29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0 245%30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29 246%31 = OpCompositeExtract %_arr_v4float_uint_2 %30 0 247%32 = OpCompositeExtract %v4float %31 0 248%33 = OpCompositeExtract %v4float %31 1 249%34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33 250%35 = OpCompositeExtract %_arr_v4float_uint_2 %30 1 251%36 = OpCompositeExtract %v4float %35 0 252%37 = OpCompositeExtract %v4float %35 1 253%38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37 254%39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38 255; CHECK: OpStore 256OpStore %27 %39 257%40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28 258%42 = OpAccessChain %_ptr_Function_v4float %40 %28 259%43 = OpLoad %v4float %42 260; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 [[new_address]] %28 261; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[ac1]] %28 262; CHECK: [[load:%\w+]] = OpLoad %v4float [[ac2]] 263; CHECK: OpStore %out_var_SV_Target [[load]] 264OpStore %out_var_SV_Target %43 265OpReturn 266OpFunctionEnd 267)"; 268 269 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 270 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 271 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 272 SinglePassRunAndMatch<CopyPropagateArrays>(text, false); 273} 274 275// Propagate 2d array. This test identifying a copy through multiple levels. 276// Also has to traverse multiple OpAccessChains. 277TEST_F(CopyPropArrayPassTest, Propagate2DArrayWithMultiLevelExtract) { 278 const std::string text = 279 R"(OpCapability Shader 280OpMemoryModel Logical GLSL450 281OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 282OpExecutionMode %main OriginUpperLeft 283OpSource HLSL 600 284OpName %type_MyCBuffer "type.MyCBuffer" 285OpMemberName %type_MyCBuffer 0 "Data" 286OpName %MyCBuffer "MyCBuffer" 287OpName %main "main" 288OpName %in_var_INDEX "in.var.INDEX" 289OpName %out_var_SV_Target "out.var.SV_Target" 290OpDecorate %_arr_v4float_uint_2 ArrayStride 16 291OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32 292OpMemberDecorate %type_MyCBuffer 0 Offset 0 293OpDecorate %type_MyCBuffer Block 294OpDecorate %in_var_INDEX Flat 295OpDecorate %in_var_INDEX Location 0 296OpDecorate %out_var_SV_Target Location 0 297OpDecorate %MyCBuffer DescriptorSet 0 298OpDecorate %MyCBuffer Binding 0 299%float = OpTypeFloat 32 300%v4float = OpTypeVector %float 4 301%uint = OpTypeInt 32 0 302%uint_2 = OpConstant %uint 2 303%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 304%_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2 305%type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2 306%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 307%void = OpTypeVoid 308%14 = OpTypeFunction %void 309%int = OpTypeInt 32 1 310%_ptr_Input_int = OpTypePointer Input %int 311%_ptr_Output_v4float = OpTypePointer Output %v4float 312%_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2 313%_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2 314%_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2 315%int_0 = OpConstant %int 0 316%_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2 317%_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0 318%_ptr_Function_v4float = OpTypePointer Function %v4float 319%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 320%in_var_INDEX = OpVariable %_ptr_Input_int Input 321%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 322; CHECK: OpFunction 323; CHECK: OpLabel 324; CHECK: OpVariable 325; CHECK: OpVariable 326; CHECK: OpAccessChain 327; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0 328%main = OpFunction %void None %14 329%25 = OpLabel 330%26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function 331%27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function 332%28 = OpLoad %int %in_var_INDEX 333%29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0 334%30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29 335%32 = OpCompositeExtract %v4float %30 0 0 336%33 = OpCompositeExtract %v4float %30 0 1 337%34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33 338%36 = OpCompositeExtract %v4float %30 1 0 339%37 = OpCompositeExtract %v4float %30 1 1 340%38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37 341%39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38 342; CHECK: OpStore 343OpStore %27 %39 344%40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28 345%42 = OpAccessChain %_ptr_Function_v4float %40 %28 346%43 = OpLoad %v4float %42 347; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 [[new_address]] %28 348; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[ac1]] %28 349; CHECK: [[load:%\w+]] = OpLoad %v4float [[ac2]] 350; CHECK: OpStore %out_var_SV_Target [[load]] 351OpStore %out_var_SV_Target %43 352OpReturn 353OpFunctionEnd 354)"; 355 356 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 357 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 358 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 359 SinglePassRunAndMatch<CopyPropagateArrays>(text, false); 360} 361 362// Test decomposing an object when we need to "rewrite" a store. 363TEST_F(CopyPropArrayPassTest, DecomposeObjectForArrayStore) { 364 const std::string text = 365 R"( OpCapability Shader 366 OpMemoryModel Logical GLSL450 367 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 368 OpExecutionMode %main OriginUpperLeft 369 OpSource HLSL 600 370 OpName %type_MyCBuffer "type.MyCBuffer" 371 OpMemberName %type_MyCBuffer 0 "Data" 372 OpName %MyCBuffer "MyCBuffer" 373 OpName %main "main" 374 OpName %in_var_INDEX "in.var.INDEX" 375 OpName %out_var_SV_Target "out.var.SV_Target" 376 OpDecorate %_arr_v4float_uint_2 ArrayStride 16 377 OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32 378 OpMemberDecorate %type_MyCBuffer 0 Offset 0 379 OpDecorate %type_MyCBuffer Block 380 OpDecorate %in_var_INDEX Flat 381 OpDecorate %in_var_INDEX Location 0 382 OpDecorate %out_var_SV_Target Location 0 383 OpDecorate %MyCBuffer DescriptorSet 0 384 OpDecorate %MyCBuffer Binding 0 385 %float = OpTypeFloat 32 386 %v4float = OpTypeVector %float 4 387 %uint = OpTypeInt 32 0 388 %uint_2 = OpConstant %uint 2 389%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 390%_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2 391%type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2 392%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 393 %void = OpTypeVoid 394 %14 = OpTypeFunction %void 395 %int = OpTypeInt 32 1 396%_ptr_Input_int = OpTypePointer Input %int 397%_ptr_Output_v4float = OpTypePointer Output %v4float 398%_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2 399%_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2 400%_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2 401 %int_0 = OpConstant %int 0 402%_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2 403%_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0 404%_ptr_Function_v4float = OpTypePointer Function %v4float 405 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 406%in_var_INDEX = OpVariable %_ptr_Input_int Input 407%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 408 %main = OpFunction %void None %14 409 %25 = OpLabel 410 %26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function 411 %27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function 412 %28 = OpLoad %int %in_var_INDEX 413 %29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0 414 %30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29 415 %31 = OpCompositeExtract %_arr_v4float_uint_2 %30 0 416 %32 = OpCompositeExtract %v4float %31 0 417 %33 = OpCompositeExtract %v4float %31 1 418 %34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33 419 %35 = OpCompositeExtract %_arr_v4float_uint_2 %30 1 420 %36 = OpCompositeExtract %v4float %35 0 421 %37 = OpCompositeExtract %v4float %35 1 422 %38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37 423 %39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38 424 OpStore %27 %39 425; CHECK: [[access_chain:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 426 %40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28 427; CHECK: [[load:%\w+]] = OpLoad %_arr_v4float_uint_2 [[access_chain]] 428 %41 = OpLoad %_arr_v4float_uint_2_0 %40 429; CHECK: [[extract1:%\w+]] = OpCompositeExtract %v4float [[load]] 0 430; CHECK: [[extract2:%\w+]] = OpCompositeExtract %v4float [[load]] 1 431; CHECK: [[construct:%\w+]] = OpCompositeConstruct %_arr_v4float_uint_2_0 [[extract1]] [[extract2]] 432; CHECK: OpStore %26 [[construct]] 433 OpStore %26 %41 434 %42 = OpAccessChain %_ptr_Function_v4float %26 %28 435 %43 = OpLoad %v4float %42 436 OpStore %out_var_SV_Target %43 437 OpReturn 438 OpFunctionEnd 439)"; 440 441 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 442 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 443 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 444 SinglePassRunAndMatch<CopyPropagateArrays>(text, false); 445} 446 447// Test decomposing an object when we need to "rewrite" a store. 448TEST_F(CopyPropArrayPassTest, DecomposeObjectForStructStore) { 449 const std::string text = 450 R"( OpCapability Shader 451 OpMemoryModel Logical GLSL450 452 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 453 OpExecutionMode %main OriginUpperLeft 454 OpSource HLSL 600 455 OpName %type_MyCBuffer "type.MyCBuffer" 456 OpMemberName %type_MyCBuffer 0 "Data" 457 OpName %MyCBuffer "MyCBuffer" 458 OpName %main "main" 459 OpName %in_var_INDEX "in.var.INDEX" 460 OpName %out_var_SV_Target "out.var.SV_Target" 461 OpMemberDecorate %type_MyCBuffer 0 Offset 0 462 OpDecorate %type_MyCBuffer Block 463 OpDecorate %in_var_INDEX Flat 464 OpDecorate %in_var_INDEX Location 0 465 OpDecorate %out_var_SV_Target Location 0 466 OpDecorate %MyCBuffer DescriptorSet 0 467 OpDecorate %MyCBuffer Binding 0 468; CHECK: OpDecorate [[decorated_type:%\w+]] GLSLPacked 469 OpDecorate %struct GLSLPacked 470 %float = OpTypeFloat 32 471 %v4float = OpTypeVector %float 4 472 %uint = OpTypeInt 32 0 473 %uint_2 = OpConstant %uint 2 474; CHECK: [[decorated_type]] = OpTypeStruct 475%struct = OpTypeStruct %float %uint 476%_arr_struct_uint_2 = OpTypeArray %struct %uint_2 477%type_MyCBuffer = OpTypeStruct %_arr_struct_uint_2 478%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 479 %void = OpTypeVoid 480 %14 = OpTypeFunction %void 481 %int = OpTypeInt 32 1 482%_ptr_Input_int = OpTypePointer Input %int 483%_ptr_Output_v4float = OpTypePointer Output %v4float 484; CHECK: [[struct:%\w+]] = OpTypeStruct %float %uint 485%struct_0 = OpTypeStruct %float %uint 486%_arr_struct_0_uint_2 = OpTypeArray %struct_0 %uint_2 487%_ptr_Function__arr_struct_0_uint_2 = OpTypePointer Function %_arr_struct_0_uint_2 488 %int_0 = OpConstant %int 0 489%_ptr_Uniform__arr_struct_uint_2 = OpTypePointer Uniform %_arr_struct_uint_2 490; CHECK: [[decorated_ptr:%\w+]] = OpTypePointer Uniform [[decorated_type]] 491%_ptr_Function_struct_0 = OpTypePointer Function %struct_0 492%_ptr_Function_v4float = OpTypePointer Function %v4float 493 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 494%in_var_INDEX = OpVariable %_ptr_Input_int Input 495%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 496 %main = OpFunction %void None %14 497 %25 = OpLabel 498 %26 = OpVariable %_ptr_Function_struct_0 Function 499 %27 = OpVariable %_ptr_Function__arr_struct_0_uint_2 Function 500 %28 = OpLoad %int %in_var_INDEX 501 %29 = OpAccessChain %_ptr_Uniform__arr_struct_uint_2 %MyCBuffer %int_0 502 %30 = OpLoad %_arr_struct_uint_2 %29 503 %31 = OpCompositeExtract %struct %30 0 504 %32 = OpCompositeExtract %v4float %31 0 505 %33 = OpCompositeExtract %v4float %31 1 506 %34 = OpCompositeConstruct %struct_0 %32 %33 507 %35 = OpCompositeExtract %struct %30 1 508 %36 = OpCompositeExtract %float %35 0 509 %37 = OpCompositeExtract %uint %35 1 510 %38 = OpCompositeConstruct %struct_0 %36 %37 511 %39 = OpCompositeConstruct %_arr_struct_0_uint_2 %34 %38 512 OpStore %27 %39 513; CHECK: [[access_chain:%\w+]] = OpAccessChain [[decorated_ptr]] 514 %40 = OpAccessChain %_ptr_Function_struct_0 %27 %28 515; CHECK: [[load:%\w+]] = OpLoad [[decorated_type]] [[access_chain]] 516 %41 = OpLoad %struct_0 %40 517; CHECK: [[extract1:%\w+]] = OpCompositeExtract %float [[load]] 0 518; CHECK: [[extract2:%\w+]] = OpCompositeExtract %uint [[load]] 1 519; CHECK: [[construct:%\w+]] = OpCompositeConstruct [[struct]] [[extract1]] [[extract2]] 520; CHECK: OpStore %26 [[construct]] 521 OpStore %26 %41 522 %42 = OpAccessChain %_ptr_Function_v4float %26 %28 523 %43 = OpLoad %v4float %42 524 OpStore %out_var_SV_Target %43 525 OpReturn 526 OpFunctionEnd 527)"; 528 529 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 530 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 531 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 532 SinglePassRunAndMatch<CopyPropagateArrays>(text, false); 533} 534 535TEST_F(CopyPropArrayPassTest, CopyViaInserts) { 536 const std::string before = 537 R"( 538OpCapability Shader 539OpMemoryModel Logical GLSL450 540OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 541OpExecutionMode %main OriginUpperLeft 542OpSource HLSL 600 543OpName %type_MyCBuffer "type.MyCBuffer" 544OpMemberName %type_MyCBuffer 0 "Data" 545OpName %MyCBuffer "MyCBuffer" 546OpName %main "main" 547OpName %in_var_INDEX "in.var.INDEX" 548OpName %out_var_SV_Target "out.var.SV_Target" 549OpDecorate %_arr_v4float_uint_8 ArrayStride 16 550OpMemberDecorate %type_MyCBuffer 0 Offset 0 551OpDecorate %type_MyCBuffer Block 552OpDecorate %in_var_INDEX Flat 553OpDecorate %in_var_INDEX Location 0 554OpDecorate %out_var_SV_Target Location 0 555OpDecorate %MyCBuffer DescriptorSet 0 556OpDecorate %MyCBuffer Binding 0 557%float = OpTypeFloat 32 558%v4float = OpTypeVector %float 4 559%uint = OpTypeInt 32 0 560%uint_8 = OpConstant %uint 8 561%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 562%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 563%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 564%void = OpTypeVoid 565%13 = OpTypeFunction %void 566%int = OpTypeInt 32 1 567%_ptr_Input_int = OpTypePointer Input %int 568%_ptr_Output_v4float = OpTypePointer Output %v4float 569%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 570%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 571%int_0 = OpConstant %int 0 572%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 573%_ptr_Function_v4float = OpTypePointer Function %v4float 574%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 575%in_var_INDEX = OpVariable %_ptr_Input_int Input 576%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 577; CHECK: OpFunction 578; CHECK: OpLabel 579; CHECK: OpVariable 580; CHECK: OpAccessChain 581; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 582; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24 583; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]] 584; CHECK: OpStore %out_var_SV_Target [[load]] 585%main = OpFunction %void None %13 586%22 = OpLabel 587%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 588%undef = OpUndef %_arr_v4float_uint_8_0 589%24 = OpLoad %int %in_var_INDEX 590%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 591%26 = OpLoad %_arr_v4float_uint_8 %25 592%27 = OpCompositeExtract %v4float %26 0 593%i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0 594%28 = OpCompositeExtract %v4float %26 1 595%i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1 596%29 = OpCompositeExtract %v4float %26 2 597%i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2 598%30 = OpCompositeExtract %v4float %26 3 599%i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3 600%31 = OpCompositeExtract %v4float %26 4 601%i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4 602%32 = OpCompositeExtract %v4float %26 5 603%i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5 604%33 = OpCompositeExtract %v4float %26 6 605%i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6 606%34 = OpCompositeExtract %v4float %26 7 607%i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7 608OpStore %23 %i7 609%36 = OpAccessChain %_ptr_Function_v4float %23 %24 610%37 = OpLoad %v4float %36 611OpStore %out_var_SV_Target %37 612OpReturn 613OpFunctionEnd 614)"; 615 616 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 617 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 618 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 619 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 620} 621 622TEST_F(CopyPropArrayPassTest, IsomorphicTypes1) { 623 const std::string before = 624 R"( 625; CHECK: [[int:%\w+]] = OpTypeInt 32 0 626; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]] 627; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]] 628; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]] 629; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]] 630; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]] 631; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform 632; CHECK: [[p_a1:%\w+]] = OpTypePointer Uniform [[a1]] 633; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]] 634; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_a1]] [[global_var]] %uint_0 635; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s2]] [[ac1]] %uint_0 636; CHECK: [[ld:%\w+]] = OpLoad [[s2]] [[ac2]] 637; CHECK: [[ex:%\w+]] = OpCompositeExtract [[s1]] [[ld]] 638 OpCapability Shader 639 %1 = OpExtInstImport "GLSL.std.450" 640 OpMemoryModel Logical GLSL450 641 OpEntryPoint Fragment %2 "PS_main" 642 OpExecutionMode %2 OriginUpperLeft 643 OpSource HLSL 600 644 OpDecorate %3 DescriptorSet 0 645 OpDecorate %3 Binding 101 646 %uint = OpTypeInt 32 0 647 %uint_1 = OpConstant %uint 1 648 %s1 = OpTypeStruct %uint 649 %s2 = OpTypeStruct %s1 650%a1 = OpTypeArray %s2 %uint_1 651 %s3 = OpTypeStruct %a1 652 %s1_1 = OpTypeStruct %uint 653%_ptr_Uniform_uint = OpTypePointer Uniform %uint 654 %void = OpTypeVoid 655 %13 = OpTypeFunction %void 656 %uint_0 = OpConstant %uint 0 657 %s1_0 = OpTypeStruct %uint 658 %s2_0 = OpTypeStruct %s1_0 659%a1_0 = OpTypeArray %s2_0 %uint_1 660 %s3_0 = OpTypeStruct %a1_0 661%p_s3 = OpTypePointer Uniform %s3 662%p_s3_0 = OpTypePointer Function %s3_0 663 %3 = OpVariable %p_s3 Uniform 664%p_a1_0 = OpTypePointer Function %a1_0 665%p_s2_0 = OpTypePointer Function %s2_0 666 %2 = OpFunction %void None %13 667 %20 = OpLabel 668 %21 = OpVariable %p_a1_0 Function 669 %22 = OpLoad %s3 %3 670 %23 = OpCompositeExtract %a1 %22 0 671 %24 = OpCompositeExtract %s2 %23 0 672 %25 = OpCompositeExtract %s1 %24 0 673 %26 = OpCompositeExtract %uint %25 0 674 %27 = OpCompositeConstruct %s1_0 %26 675 %32 = OpCompositeConstruct %s2_0 %27 676 %28 = OpCompositeConstruct %a1_0 %32 677 OpStore %21 %28 678 %29 = OpAccessChain %p_s2_0 %21 %uint_0 679 %30 = OpLoad %s2 %29 680 %31 = OpCompositeExtract %s1 %30 0 681 OpReturn 682 OpFunctionEnd 683)"; 684 685 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 686 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 687 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 688 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 689} 690 691TEST_F(CopyPropArrayPassTest, IsomorphicTypes2) { 692 const std::string before = 693 R"( 694; CHECK: [[int:%\w+]] = OpTypeInt 32 0 695; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]] 696; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]] 697; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]] 698; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]] 699; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]] 700; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform 701; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]] 702; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]] 703; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0 704; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0 705; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]] 706; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]] 707 OpCapability Shader 708 %1 = OpExtInstImport "GLSL.std.450" 709 OpMemoryModel Logical GLSL450 710 OpEntryPoint Fragment %2 "PS_main" 711 OpExecutionMode %2 OriginUpperLeft 712 OpSource HLSL 600 713 OpDecorate %3 DescriptorSet 0 714 OpDecorate %3 Binding 101 715 %uint = OpTypeInt 32 0 716 %uint_1 = OpConstant %uint 1 717 %_struct_6 = OpTypeStruct %uint 718 %_struct_7 = OpTypeStruct %_struct_6 719%_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1 720 %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1 721 %_struct_10 = OpTypeStruct %uint 722%_ptr_Uniform_uint = OpTypePointer Uniform %uint 723 %void = OpTypeVoid 724 %13 = OpTypeFunction %void 725 %uint_0 = OpConstant %uint 0 726 %_struct_15 = OpTypeStruct %uint 727%_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1 728%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9 729%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 730 %3 = OpVariable %_ptr_Uniform__struct_9 Uniform 731%_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1 732 %2 = OpFunction %void None %13 733 %20 = OpLabel 734 %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function 735 %22 = OpLoad %_struct_9 %3 736 %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0 737 %24 = OpCompositeExtract %_struct_7 %23 0 738 %25 = OpCompositeExtract %_struct_6 %24 0 739 %26 = OpCompositeExtract %uint %25 0 740 %27 = OpCompositeConstruct %_struct_15 %26 741 %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27 742 OpStore %21 %28 743 %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0 744 %30 = OpLoad %_struct_15 %29 745 %31 = OpCompositeExtract %uint %30 0 746 OpReturn 747 OpFunctionEnd 748)"; 749 750 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 751 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 752 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 753 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 754} 755 756TEST_F(CopyPropArrayPassTest, IsomorphicTypes3) { 757 const std::string before = 758 R"( 759; CHECK: [[int:%\w+]] = OpTypeInt 32 0 760; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]] 761; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]] 762; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]] 763; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]] 764; CHECK: [[s1_1:%\w+]] = OpTypeStruct [[int]] 765; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]] 766; CHECK: [[p_s1_1:%\w+]] = OpTypePointer Function [[s1_1]] 767; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform 768; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]] 769; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]] 770; CHECK: [[var:%\w+]] = OpVariable [[p_s1_1]] Function 771; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0 772; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0 773; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]] 774; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]] 775; CHECK: [[copy:%\w+]] = OpCompositeConstruct [[s1_1]] [[ex]] 776; CHECK: OpStore [[var]] [[copy]] 777 OpCapability Shader 778 %1 = OpExtInstImport "GLSL.std.450" 779 OpMemoryModel Logical GLSL450 780 OpEntryPoint Fragment %2 "PS_main" 781 OpExecutionMode %2 OriginUpperLeft 782 OpSource HLSL 600 783 OpDecorate %3 DescriptorSet 0 784 OpDecorate %3 Binding 101 785 %uint = OpTypeInt 32 0 786 %uint_1 = OpConstant %uint 1 787 %_struct_6 = OpTypeStruct %uint 788 %_struct_7 = OpTypeStruct %_struct_6 789%_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1 790 %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1 791%_ptr_Uniform_uint = OpTypePointer Uniform %uint 792 %void = OpTypeVoid 793 %13 = OpTypeFunction %void 794 %uint_0 = OpConstant %uint 0 795 %_struct_15 = OpTypeStruct %uint 796 %_struct_10 = OpTypeStruct %uint 797%_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1 798%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9 799%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 800 %3 = OpVariable %_ptr_Uniform__struct_9 Uniform 801%_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1 802 %2 = OpFunction %void None %13 803 %20 = OpLabel 804 %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function 805 %var = OpVariable %_ptr_Function__struct_15 Function 806 %22 = OpLoad %_struct_9 %3 807 %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0 808 %24 = OpCompositeExtract %_struct_7 %23 0 809 %25 = OpCompositeExtract %_struct_6 %24 0 810 %26 = OpCompositeExtract %uint %25 0 811 %27 = OpCompositeConstruct %_struct_15 %26 812 %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27 813 OpStore %21 %28 814 %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0 815 %30 = OpLoad %_struct_15 %29 816 OpStore %var %30 817 OpReturn 818 OpFunctionEnd 819)"; 820 821 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 822 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 823 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 824 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 825} 826 827TEST_F(CopyPropArrayPassTest, BadMergingTwoObjects) { 828 // The second element in the |OpCompositeConstruct| is from a different 829 // object. 830 const std::string text = 831 R"(OpCapability Shader 832OpMemoryModel Logical GLSL450 833OpEntryPoint Fragment %main "main" 834OpExecutionMode %main OriginUpperLeft 835OpName %type_ConstBuf "type.ConstBuf" 836OpMemberName %type_ConstBuf 0 "TexSizeU" 837OpMemberName %type_ConstBuf 1 "TexSizeV" 838OpName %ConstBuf "ConstBuf" 839OpName %main "main" 840OpMemberDecorate %type_ConstBuf 0 Offset 0 841OpMemberDecorate %type_ConstBuf 1 Offset 8 842OpDecorate %type_ConstBuf Block 843OpDecorate %ConstBuf DescriptorSet 0 844OpDecorate %ConstBuf Binding 2 845%float = OpTypeFloat 32 846%v2float = OpTypeVector %float 2 847%type_ConstBuf = OpTypeStruct %v2float %v2float 848%_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf 849%void = OpTypeVoid 850%9 = OpTypeFunction %void 851%uint = OpTypeInt 32 0 852%int_0 = OpConstant %uint 0 853%uint_2 = OpConstant %uint 2 854%_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2 855%_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2 856%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float 857%ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform 858%main = OpFunction %void None %9 859%24 = OpLabel 860%25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function 861%27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0 862%28 = OpLoad %v2float %27 863%29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0 864%30 = OpLoad %v2float %29 865%31 = OpFNegate %v2float %30 866%37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %31 867OpStore %25 %37 868OpReturn 869OpFunctionEnd 870)"; 871 872 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 873 text, /* skip_nop = */ true, /* do_validation = */ false); 874 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 875} 876 877TEST_F(CopyPropArrayPassTest, SecondElementNotContained) { 878 // The second element in the |OpCompositeConstruct| is not a memory object. 879 // Make sure no change happends. 880 const std::string text = 881 R"(OpCapability Shader 882OpMemoryModel Logical GLSL450 883OpEntryPoint Fragment %main "main" 884OpExecutionMode %main OriginUpperLeft 885OpName %type_ConstBuf "type.ConstBuf" 886OpMemberName %type_ConstBuf 0 "TexSizeU" 887OpMemberName %type_ConstBuf 1 "TexSizeV" 888OpName %ConstBuf "ConstBuf" 889OpName %main "main" 890OpMemberDecorate %type_ConstBuf 0 Offset 0 891OpMemberDecorate %type_ConstBuf 1 Offset 8 892OpDecorate %type_ConstBuf Block 893OpDecorate %ConstBuf DescriptorSet 0 894OpDecorate %ConstBuf Binding 2 895OpDecorate %ConstBuf2 DescriptorSet 1 896OpDecorate %ConstBuf2 Binding 2 897%float = OpTypeFloat 32 898%v2float = OpTypeVector %float 2 899%type_ConstBuf = OpTypeStruct %v2float %v2float 900%_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf 901%void = OpTypeVoid 902%9 = OpTypeFunction %void 903%uint = OpTypeInt 32 0 904%int_0 = OpConstant %uint 0 905%int_1 = OpConstant %uint 1 906%uint_2 = OpConstant %uint 2 907%_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2 908%_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2 909%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float 910%ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform 911%ConstBuf2 = OpVariable %_ptr_Uniform_type_ConstBuf Uniform 912%main = OpFunction %void None %9 913%24 = OpLabel 914%25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function 915%27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0 916%28 = OpLoad %v2float %27 917%29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf2 %int_1 918%30 = OpLoad %v2float %29 919%37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %30 920OpStore %25 %37 921OpReturn 922OpFunctionEnd 923)"; 924 925 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 926 text, /* skip_nop = */ true, /* do_validation = */ false); 927 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 928} 929// This test will place a load before the store. We cannot propagate in this 930// case. 931TEST_F(CopyPropArrayPassTest, LoadBeforeStore) { 932 const std::string text = 933 R"( 934OpCapability Shader 935OpMemoryModel Logical GLSL450 936OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 937OpExecutionMode %main OriginUpperLeft 938OpSource HLSL 600 939OpName %type_MyCBuffer "type.MyCBuffer" 940OpMemberName %type_MyCBuffer 0 "Data" 941OpName %MyCBuffer "MyCBuffer" 942OpName %main "main" 943OpName %in_var_INDEX "in.var.INDEX" 944OpName %out_var_SV_Target "out.var.SV_Target" 945OpDecorate %_arr_v4float_uint_8 ArrayStride 16 946OpMemberDecorate %type_MyCBuffer 0 Offset 0 947OpDecorate %type_MyCBuffer Block 948OpDecorate %in_var_INDEX Flat 949OpDecorate %in_var_INDEX Location 0 950OpDecorate %out_var_SV_Target Location 0 951OpDecorate %MyCBuffer DescriptorSet 0 952OpDecorate %MyCBuffer Binding 0 953%float = OpTypeFloat 32 954%v4float = OpTypeVector %float 4 955%uint = OpTypeInt 32 0 956%uint_8 = OpConstant %uint 8 957%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 958%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 959%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 960%void = OpTypeVoid 961%13 = OpTypeFunction %void 962%int = OpTypeInt 32 1 963%_ptr_Input_int = OpTypePointer Input %int 964%_ptr_Output_v4float = OpTypePointer Output %v4float 965%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 966%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 967%int_0 = OpConstant %int 0 968%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 969%_ptr_Function_v4float = OpTypePointer Function %v4float 970%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 971%in_var_INDEX = OpVariable %_ptr_Input_int Input 972%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 973%main = OpFunction %void None %13 974%22 = OpLabel 975%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 976%38 = OpAccessChain %_ptr_Function_v4float %23 %24 977%39 = OpLoad %v4float %36 978%24 = OpLoad %int %in_var_INDEX 979%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 980%26 = OpLoad %_arr_v4float_uint_8 %25 981%27 = OpCompositeExtract %v4float %26 0 982%28 = OpCompositeExtract %v4float %26 1 983%29 = OpCompositeExtract %v4float %26 2 984%30 = OpCompositeExtract %v4float %26 3 985%31 = OpCompositeExtract %v4float %26 4 986%32 = OpCompositeExtract %v4float %26 5 987%33 = OpCompositeExtract %v4float %26 6 988%34 = OpCompositeExtract %v4float %26 7 989%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34 990OpStore %23 %35 991%36 = OpAccessChain %_ptr_Function_v4float %23 %24 992%37 = OpLoad %v4float %36 993OpStore %out_var_SV_Target %37 994OpReturn 995OpFunctionEnd 996)"; 997 998 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 999 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1000 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1001 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 1002 text, /* skip_nop = */ true, /* do_validation = */ false); 1003 1004 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1005} 1006 1007// This test will place a load where it is not dominated by the store. We 1008// cannot propagate in this case. 1009TEST_F(CopyPropArrayPassTest, LoadNotDominated) { 1010 const std::string text = 1011 R"( 1012OpCapability Shader 1013OpMemoryModel Logical GLSL450 1014OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 1015OpExecutionMode %main OriginUpperLeft 1016OpSource HLSL 600 1017OpName %type_MyCBuffer "type.MyCBuffer" 1018OpMemberName %type_MyCBuffer 0 "Data" 1019OpName %MyCBuffer "MyCBuffer" 1020OpName %main "main" 1021OpName %in_var_INDEX "in.var.INDEX" 1022OpName %out_var_SV_Target "out.var.SV_Target" 1023OpDecorate %_arr_v4float_uint_8 ArrayStride 16 1024OpMemberDecorate %type_MyCBuffer 0 Offset 0 1025OpDecorate %type_MyCBuffer Block 1026OpDecorate %in_var_INDEX Flat 1027OpDecorate %in_var_INDEX Location 0 1028OpDecorate %out_var_SV_Target Location 0 1029OpDecorate %MyCBuffer DescriptorSet 0 1030OpDecorate %MyCBuffer Binding 0 1031%bool = OpTypeBool 1032%true = OpConstantTrue %bool 1033%float = OpTypeFloat 32 1034%v4float = OpTypeVector %float 4 1035%uint = OpTypeInt 32 0 1036%uint_8 = OpConstant %uint 8 1037%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 1038%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 1039%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 1040%void = OpTypeVoid 1041%13 = OpTypeFunction %void 1042%int = OpTypeInt 32 1 1043%_ptr_Input_int = OpTypePointer Input %int 1044%_ptr_Output_v4float = OpTypePointer Output %v4float 1045%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 1046%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 1047%int_0 = OpConstant %int 0 1048%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 1049%_ptr_Function_v4float = OpTypePointer Function %v4float 1050%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 1051%in_var_INDEX = OpVariable %_ptr_Input_int Input 1052%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 1053%main = OpFunction %void None %13 1054%22 = OpLabel 1055%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 1056OpSelectionMerge %merge None 1057OpBranchConditional %true %if %else 1058%if = OpLabel 1059%24 = OpLoad %int %in_var_INDEX 1060%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1061%26 = OpLoad %_arr_v4float_uint_8 %25 1062%27 = OpCompositeExtract %v4float %26 0 1063%28 = OpCompositeExtract %v4float %26 1 1064%29 = OpCompositeExtract %v4float %26 2 1065%30 = OpCompositeExtract %v4float %26 3 1066%31 = OpCompositeExtract %v4float %26 4 1067%32 = OpCompositeExtract %v4float %26 5 1068%33 = OpCompositeExtract %v4float %26 6 1069%34 = OpCompositeExtract %v4float %26 7 1070%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34 1071OpStore %23 %35 1072%38 = OpAccessChain %_ptr_Function_v4float %23 %24 1073%39 = OpLoad %v4float %36 1074OpBranch %merge 1075%else = OpLabel 1076%36 = OpAccessChain %_ptr_Function_v4float %23 %24 1077%37 = OpLoad %v4float %36 1078OpBranch %merge 1079%merge = OpLabel 1080%phi = OpPhi %out_var_SV_Target %39 %if %37 %else 1081OpStore %out_var_SV_Target %phi 1082OpReturn 1083OpFunctionEnd 1084)"; 1085 1086 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1087 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1088 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1089 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 1090 text, /* skip_nop = */ true, /* do_validation = */ false); 1091 1092 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1093} 1094 1095// This test has a partial store to the variable. We cannot propagate in this 1096// case. 1097TEST_F(CopyPropArrayPassTest, PartialStore) { 1098 const std::string text = 1099 R"( 1100OpCapability Shader 1101OpMemoryModel Logical GLSL450 1102OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 1103OpExecutionMode %main OriginUpperLeft 1104OpSource HLSL 600 1105OpName %type_MyCBuffer "type.MyCBuffer" 1106OpMemberName %type_MyCBuffer 0 "Data" 1107OpName %MyCBuffer "MyCBuffer" 1108OpName %main "main" 1109OpName %in_var_INDEX "in.var.INDEX" 1110OpName %out_var_SV_Target "out.var.SV_Target" 1111OpDecorate %_arr_v4float_uint_8 ArrayStride 16 1112OpMemberDecorate %type_MyCBuffer 0 Offset 0 1113OpDecorate %type_MyCBuffer Block 1114OpDecorate %in_var_INDEX Flat 1115OpDecorate %in_var_INDEX Location 0 1116OpDecorate %out_var_SV_Target Location 0 1117OpDecorate %MyCBuffer DescriptorSet 0 1118OpDecorate %MyCBuffer Binding 0 1119%float = OpTypeFloat 32 1120%v4float = OpTypeVector %float 4 1121%uint = OpTypeInt 32 0 1122%uint_8 = OpConstant %uint 8 1123%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 1124%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 1125%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 1126%void = OpTypeVoid 1127%13 = OpTypeFunction %void 1128%int = OpTypeInt 32 1 1129%_ptr_Input_int = OpTypePointer Input %int 1130%_ptr_Output_v4float = OpTypePointer Output %v4float 1131%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 1132%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 1133%int_0 = OpConstant %int 0 1134%f0 = OpConstant %float 0 1135%v4const = OpConstantComposite %v4float %f0 %f0 %f0 %f0 1136%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 1137%_ptr_Function_v4float = OpTypePointer Function %v4float 1138%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 1139%in_var_INDEX = OpVariable %_ptr_Input_int Input 1140%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 1141%main = OpFunction %void None %13 1142%22 = OpLabel 1143%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 1144%24 = OpLoad %int %in_var_INDEX 1145%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1146%26 = OpLoad %_arr_v4float_uint_8 %25 1147%27 = OpCompositeExtract %v4float %26 0 1148%28 = OpCompositeExtract %v4float %26 1 1149%29 = OpCompositeExtract %v4float %26 2 1150%30 = OpCompositeExtract %v4float %26 3 1151%31 = OpCompositeExtract %v4float %26 4 1152%32 = OpCompositeExtract %v4float %26 5 1153%33 = OpCompositeExtract %v4float %26 6 1154%34 = OpCompositeExtract %v4float %26 7 1155%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34 1156OpStore %23 %35 1157%36 = OpAccessChain %_ptr_Function_v4float %23 %24 1158%37 = OpLoad %v4float %36 1159 OpStore %36 %v4const 1160OpStore %out_var_SV_Target %37 1161OpReturn 1162OpFunctionEnd 1163)"; 1164 1165 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1166 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1167 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1168 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 1169 text, /* skip_nop = */ true, /* do_validation = */ false); 1170 1171 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1172} 1173 1174// This test does not have a proper copy of an object. We cannot propagate in 1175// this case. 1176TEST_F(CopyPropArrayPassTest, NotACopy) { 1177 const std::string text = 1178 R"( 1179OpCapability Shader 1180OpMemoryModel Logical GLSL450 1181OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 1182OpExecutionMode %main OriginUpperLeft 1183OpSource HLSL 600 1184OpName %type_MyCBuffer "type.MyCBuffer" 1185OpMemberName %type_MyCBuffer 0 "Data" 1186OpName %MyCBuffer "MyCBuffer" 1187OpName %main "main" 1188OpName %in_var_INDEX "in.var.INDEX" 1189OpName %out_var_SV_Target "out.var.SV_Target" 1190OpDecorate %_arr_v4float_uint_8 ArrayStride 16 1191OpMemberDecorate %type_MyCBuffer 0 Offset 0 1192OpDecorate %type_MyCBuffer Block 1193OpDecorate %in_var_INDEX Flat 1194OpDecorate %in_var_INDEX Location 0 1195OpDecorate %out_var_SV_Target Location 0 1196OpDecorate %MyCBuffer DescriptorSet 0 1197OpDecorate %MyCBuffer Binding 0 1198%float = OpTypeFloat 32 1199%v4float = OpTypeVector %float 4 1200%uint = OpTypeInt 32 0 1201%uint_8 = OpConstant %uint 8 1202%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 1203%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 1204%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 1205%void = OpTypeVoid 1206%13 = OpTypeFunction %void 1207%int = OpTypeInt 32 1 1208%_ptr_Input_int = OpTypePointer Input %int 1209%_ptr_Output_v4float = OpTypePointer Output %v4float 1210%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 1211%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 1212%int_0 = OpConstant %int 0 1213%f0 = OpConstant %float 0 1214%v4const = OpConstantComposite %v4float %f0 %f0 %f0 %f0 1215%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 1216%_ptr_Function_v4float = OpTypePointer Function %v4float 1217%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 1218%in_var_INDEX = OpVariable %_ptr_Input_int Input 1219%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 1220%main = OpFunction %void None %13 1221%22 = OpLabel 1222%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 1223%24 = OpLoad %int %in_var_INDEX 1224%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1225%26 = OpLoad %_arr_v4float_uint_8 %25 1226%27 = OpCompositeExtract %v4float %26 0 1227%28 = OpCompositeExtract %v4float %26 0 1228%29 = OpCompositeExtract %v4float %26 2 1229%30 = OpCompositeExtract %v4float %26 3 1230%31 = OpCompositeExtract %v4float %26 4 1231%32 = OpCompositeExtract %v4float %26 5 1232%33 = OpCompositeExtract %v4float %26 6 1233%34 = OpCompositeExtract %v4float %26 7 1234%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34 1235OpStore %23 %35 1236%36 = OpAccessChain %_ptr_Function_v4float %23 %24 1237%37 = OpLoad %v4float %36 1238OpStore %out_var_SV_Target %37 1239OpReturn 1240OpFunctionEnd 1241)"; 1242 1243 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1244 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1245 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1246 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 1247 text, /* skip_nop = */ true, /* do_validation = */ false); 1248 1249 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1250} 1251 1252TEST_F(CopyPropArrayPassTest, BadCopyViaInserts1) { 1253 const std::string text = 1254 R"( 1255OpCapability Shader 1256OpMemoryModel Logical GLSL450 1257OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 1258OpExecutionMode %main OriginUpperLeft 1259OpSource HLSL 600 1260OpName %type_MyCBuffer "type.MyCBuffer" 1261OpMemberName %type_MyCBuffer 0 "Data" 1262OpName %MyCBuffer "MyCBuffer" 1263OpName %main "main" 1264OpName %in_var_INDEX "in.var.INDEX" 1265OpName %out_var_SV_Target "out.var.SV_Target" 1266OpDecorate %_arr_v4float_uint_8 ArrayStride 16 1267OpMemberDecorate %type_MyCBuffer 0 Offset 0 1268OpDecorate %type_MyCBuffer Block 1269OpDecorate %in_var_INDEX Flat 1270OpDecorate %in_var_INDEX Location 0 1271OpDecorate %out_var_SV_Target Location 0 1272OpDecorate %MyCBuffer DescriptorSet 0 1273OpDecorate %MyCBuffer Binding 0 1274%float = OpTypeFloat 32 1275%v4float = OpTypeVector %float 4 1276%uint = OpTypeInt 32 0 1277%uint_8 = OpConstant %uint 8 1278%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 1279%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 1280%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 1281%void = OpTypeVoid 1282%13 = OpTypeFunction %void 1283%int = OpTypeInt 32 1 1284%_ptr_Input_int = OpTypePointer Input %int 1285%_ptr_Output_v4float = OpTypePointer Output %v4float 1286%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 1287%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 1288%int_0 = OpConstant %int 0 1289%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 1290%_ptr_Function_v4float = OpTypePointer Function %v4float 1291%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 1292%in_var_INDEX = OpVariable %_ptr_Input_int Input 1293%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 1294%main = OpFunction %void None %13 1295%22 = OpLabel 1296%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 1297%undef = OpUndef %_arr_v4float_uint_8_0 1298%24 = OpLoad %int %in_var_INDEX 1299%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1300%26 = OpLoad %_arr_v4float_uint_8 %25 1301%27 = OpCompositeExtract %v4float %26 0 1302%i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0 1303%28 = OpCompositeExtract %v4float %26 1 1304%i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1 1305%29 = OpCompositeExtract %v4float %26 2 1306%i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 3 1307%30 = OpCompositeExtract %v4float %26 3 1308%i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3 1309%31 = OpCompositeExtract %v4float %26 4 1310%i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4 1311%32 = OpCompositeExtract %v4float %26 5 1312%i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5 1313%33 = OpCompositeExtract %v4float %26 6 1314%i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6 1315%34 = OpCompositeExtract %v4float %26 7 1316%i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7 1317OpStore %23 %i7 1318%36 = OpAccessChain %_ptr_Function_v4float %23 %24 1319%37 = OpLoad %v4float %36 1320OpStore %out_var_SV_Target %37 1321OpReturn 1322OpFunctionEnd 1323)"; 1324 1325 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1326 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1327 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1328 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 1329 text, /* skip_nop = */ true, /* do_validation = */ false); 1330 1331 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1332} 1333 1334TEST_F(CopyPropArrayPassTest, BadCopyViaInserts2) { 1335 const std::string text = 1336 R"( 1337OpCapability Shader 1338OpMemoryModel Logical GLSL450 1339OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 1340OpExecutionMode %main OriginUpperLeft 1341OpSource HLSL 600 1342OpName %type_MyCBuffer "type.MyCBuffer" 1343OpMemberName %type_MyCBuffer 0 "Data" 1344OpName %MyCBuffer "MyCBuffer" 1345OpName %main "main" 1346OpName %in_var_INDEX "in.var.INDEX" 1347OpName %out_var_SV_Target "out.var.SV_Target" 1348OpDecorate %_arr_v4float_uint_8 ArrayStride 16 1349OpMemberDecorate %type_MyCBuffer 0 Offset 0 1350OpDecorate %type_MyCBuffer Block 1351OpDecorate %in_var_INDEX Flat 1352OpDecorate %in_var_INDEX Location 0 1353OpDecorate %out_var_SV_Target Location 0 1354OpDecorate %MyCBuffer DescriptorSet 0 1355OpDecorate %MyCBuffer Binding 0 1356%float = OpTypeFloat 32 1357%v4float = OpTypeVector %float 4 1358%uint = OpTypeInt 32 0 1359%uint_8 = OpConstant %uint 8 1360%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 1361%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 1362%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 1363%void = OpTypeVoid 1364%13 = OpTypeFunction %void 1365%int = OpTypeInt 32 1 1366%_ptr_Input_int = OpTypePointer Input %int 1367%_ptr_Output_v4float = OpTypePointer Output %v4float 1368%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 1369%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 1370%int_0 = OpConstant %int 0 1371%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 1372%_ptr_Function_v4float = OpTypePointer Function %v4float 1373%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 1374%in_var_INDEX = OpVariable %_ptr_Input_int Input 1375%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 1376%main = OpFunction %void None %13 1377%22 = OpLabel 1378%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 1379%undef = OpUndef %_arr_v4float_uint_8_0 1380%24 = OpLoad %int %in_var_INDEX 1381%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1382%26 = OpLoad %_arr_v4float_uint_8 %25 1383%27 = OpCompositeExtract %v4float %26 0 1384%i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0 1385%28 = OpCompositeExtract %v4float %26 1 1386%i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1 1387%29 = OpCompositeExtract %v4float %26 3 1388%i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2 1389%30 = OpCompositeExtract %v4float %26 3 1390%i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3 1391%31 = OpCompositeExtract %v4float %26 4 1392%i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4 1393%32 = OpCompositeExtract %v4float %26 5 1394%i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5 1395%33 = OpCompositeExtract %v4float %26 6 1396%i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6 1397%34 = OpCompositeExtract %v4float %26 7 1398%i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7 1399OpStore %23 %i7 1400%36 = OpAccessChain %_ptr_Function_v4float %23 %24 1401%37 = OpLoad %v4float %36 1402OpStore %out_var_SV_Target %37 1403OpReturn 1404OpFunctionEnd 1405)"; 1406 1407 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1408 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1409 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1410 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 1411 text, /* skip_nop = */ true, /* do_validation = */ false); 1412 1413 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1414} 1415 1416TEST_F(CopyPropArrayPassTest, BadCopyViaInserts3) { 1417 const std::string text = 1418 R"( 1419OpCapability Shader 1420OpMemoryModel Logical GLSL450 1421OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 1422OpExecutionMode %main OriginUpperLeft 1423OpSource HLSL 600 1424OpName %type_MyCBuffer "type.MyCBuffer" 1425OpMemberName %type_MyCBuffer 0 "Data" 1426OpName %MyCBuffer "MyCBuffer" 1427OpName %main "main" 1428OpName %in_var_INDEX "in.var.INDEX" 1429OpName %out_var_SV_Target "out.var.SV_Target" 1430OpDecorate %_arr_v4float_uint_8 ArrayStride 16 1431OpMemberDecorate %type_MyCBuffer 0 Offset 0 1432OpDecorate %type_MyCBuffer Block 1433OpDecorate %in_var_INDEX Flat 1434OpDecorate %in_var_INDEX Location 0 1435OpDecorate %out_var_SV_Target Location 0 1436OpDecorate %MyCBuffer DescriptorSet 0 1437OpDecorate %MyCBuffer Binding 0 1438%float = OpTypeFloat 32 1439%v4float = OpTypeVector %float 4 1440%uint = OpTypeInt 32 0 1441%uint_8 = OpConstant %uint 8 1442%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 1443%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 1444%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 1445%void = OpTypeVoid 1446%13 = OpTypeFunction %void 1447%int = OpTypeInt 32 1 1448%_ptr_Input_int = OpTypePointer Input %int 1449%_ptr_Output_v4float = OpTypePointer Output %v4float 1450%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 1451%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 1452%int_0 = OpConstant %int 0 1453%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 1454%_ptr_Function_v4float = OpTypePointer Function %v4float 1455%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 1456%in_var_INDEX = OpVariable %_ptr_Input_int Input 1457%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 1458%main = OpFunction %void None %13 1459%22 = OpLabel 1460%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 1461%undef = OpUndef %_arr_v4float_uint_8_0 1462%24 = OpLoad %int %in_var_INDEX 1463%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1464%26 = OpLoad %_arr_v4float_uint_8 %25 1465%28 = OpCompositeExtract %v4float %26 1 1466%i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %undef 1 1467%29 = OpCompositeExtract %v4float %26 2 1468%i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2 1469%30 = OpCompositeExtract %v4float %26 3 1470%i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3 1471%31 = OpCompositeExtract %v4float %26 4 1472%i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4 1473%32 = OpCompositeExtract %v4float %26 5 1474%i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5 1475%33 = OpCompositeExtract %v4float %26 6 1476%i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6 1477%34 = OpCompositeExtract %v4float %26 7 1478%i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7 1479OpStore %23 %i7 1480%36 = OpAccessChain %_ptr_Function_v4float %23 %24 1481%37 = OpLoad %v4float %36 1482OpStore %out_var_SV_Target %37 1483OpReturn 1484OpFunctionEnd 1485)"; 1486 1487 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1488 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1489 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1490 auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>( 1491 text, /* skip_nop = */ true, /* do_validation = */ false); 1492 1493 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1494} 1495 1496TEST_F(CopyPropArrayPassTest, AtomicAdd) { 1497 const std::string before = R"(OpCapability SampledBuffer 1498OpCapability StorageImageExtendedFormats 1499OpCapability ImageBuffer 1500OpCapability Shader 1501%1 = OpExtInstImport "GLSL.std.450" 1502OpMemoryModel Logical GLSL450 1503OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID 1504OpExecutionMode %2 LocalSize 64 1 1 1505OpSource HLSL 600 1506OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId 1507OpDecorate %4 DescriptorSet 4 1508OpDecorate %4 Binding 70 1509%uint = OpTypeInt 32 0 1510%6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui 1511%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 1512%_ptr_Function_6 = OpTypePointer Function %6 1513%void = OpTypeVoid 1514%10 = OpTypeFunction %void 1515%uint_0 = OpConstant %uint 0 1516%uint_1 = OpConstant %uint 1 1517%v3uint = OpTypeVector %uint 3 1518%_ptr_Input_v3uint = OpTypePointer Input %v3uint 1519%_ptr_Image_uint = OpTypePointer Image %uint 1520%4 = OpVariable %_ptr_UniformConstant_6 UniformConstant 1521%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input 1522%2 = OpFunction %void None %10 1523%17 = OpLabel 1524%16 = OpVariable %_ptr_Function_6 Function 1525%18 = OpLoad %6 %4 1526OpStore %16 %18 1527%19 = OpImageTexelPointer %_ptr_Image_uint %16 %uint_0 %uint_0 1528%20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1 1529OpReturn 1530OpFunctionEnd 1531)"; 1532 1533 const std::string after = R"(OpCapability SampledBuffer 1534OpCapability StorageImageExtendedFormats 1535OpCapability ImageBuffer 1536OpCapability Shader 1537%1 = OpExtInstImport "GLSL.std.450" 1538OpMemoryModel Logical GLSL450 1539OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID 1540OpExecutionMode %2 LocalSize 64 1 1 1541OpSource HLSL 600 1542OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId 1543OpDecorate %4 DescriptorSet 4 1544OpDecorate %4 Binding 70 1545%uint = OpTypeInt 32 0 1546%6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui 1547%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 1548%_ptr_Function_6 = OpTypePointer Function %6 1549%void = OpTypeVoid 1550%10 = OpTypeFunction %void 1551%uint_0 = OpConstant %uint 0 1552%uint_1 = OpConstant %uint 1 1553%v3uint = OpTypeVector %uint 3 1554%_ptr_Input_v3uint = OpTypePointer Input %v3uint 1555%_ptr_Image_uint = OpTypePointer Image %uint 1556%4 = OpVariable %_ptr_UniformConstant_6 UniformConstant 1557%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input 1558%2 = OpFunction %void None %10 1559%17 = OpLabel 1560%16 = OpVariable %_ptr_Function_6 Function 1561%18 = OpLoad %6 %4 1562OpStore %16 %18 1563%19 = OpImageTexelPointer %_ptr_Image_uint %4 %uint_0 %uint_0 1564%20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1 1565OpReturn 1566OpFunctionEnd 1567)"; 1568 1569 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1570 SinglePassRunAndCheck<CopyPropagateArrays>(before, after, true, true); 1571} 1572 1573TEST_F(CopyPropArrayPassTest, IndexIsNullConstnat) { 1574 const std::string text = R"( 1575; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform 1576; CHECK: [[null:%\w+]] = OpConstantNull %uint 1577; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_uint_uint_1 [[var]] %uint_0 %uint_0 1578; CHECK: OpAccessChain %_ptr_Uniform_uint [[ac1]] [[null]] 1579; CHECK-NEXT: OpReturn 1580 OpCapability Shader 1581 OpMemoryModel Logical GLSL450 1582 OpEntryPoint Fragment %main "main" 1583 OpExecutionMode %main OriginUpperLeft 1584 OpSource HLSL 600 1585 OpDecorate %myCBuffer DescriptorSet 0 1586 OpDecorate %myCBuffer Binding 0 1587 OpDecorate %_arr_v4float_uint_1 ArrayStride 16 1588 OpMemberDecorate %MyConstantBuffer 0 Offset 0 1589 OpMemberDecorate %type_myCBuffer 0 Offset 0 1590 OpDecorate %type_myCBuffer Block 1591 %uint = OpTypeInt 32 0 1592 %int_0 = OpConstant %uint 0 1593 %uint_1 = OpConstant %uint 1 1594%_arr_v4float_uint_1 = OpTypeArray %uint %uint_1 1595%MyConstantBuffer = OpTypeStruct %_arr_v4float_uint_1 1596%type_myCBuffer = OpTypeStruct %MyConstantBuffer 1597%_ptr_Uniform_type_myCBuffer = OpTypePointer Uniform %type_myCBuffer 1598%_arr_v4float_uint_1_0 = OpTypeArray %uint %uint_1 1599 %void = OpTypeVoid 1600 %19 = OpTypeFunction %void 1601%_ptr_Function_v4float = OpTypePointer Function %uint 1602%_ptr_Uniform_MyConstantBuffer = OpTypePointer Uniform %MyConstantBuffer 1603 %myCBuffer = OpVariable %_ptr_Uniform_type_myCBuffer Uniform 1604%_ptr_Function__arr_v4float_uint_1_0 = OpTypePointer Function %_arr_v4float_uint_1_0 1605 %23 = OpConstantNull %uint 1606 %main = OpFunction %void None %19 1607 %24 = OpLabel 1608 %25 = OpVariable %_ptr_Function__arr_v4float_uint_1_0 Function 1609 %26 = OpAccessChain %_ptr_Uniform_MyConstantBuffer %myCBuffer %int_0 1610 %27 = OpLoad %MyConstantBuffer %26 1611 %28 = OpCompositeExtract %_arr_v4float_uint_1 %27 0 1612 %29 = OpCompositeExtract %uint %28 0 1613 %30 = OpCompositeConstruct %_arr_v4float_uint_1_0 %29 1614 OpStore %25 %30 1615 %31 = OpAccessChain %_ptr_Function_v4float %25 %23 1616 OpReturn 1617 OpFunctionEnd 1618)"; 1619 1620 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1621 SinglePassRunAndMatch<CopyPropagateArrays>(text, true); 1622} 1623 1624TEST_F(CopyPropArrayPassTest, DebugDeclare) { 1625 const std::string before = 1626 R"(OpCapability Shader 1627%ext = OpExtInstImport "OpenCL.DebugInfo.100" 1628OpMemoryModel Logical GLSL450 1629OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 1630OpExecutionMode %main OriginUpperLeft 1631OpSource HLSL 600 1632%file_name = OpString "test" 1633%float_name = OpString "float" 1634%main_name = OpString "main" 1635%f_name = OpString "f" 1636OpName %type_MyCBuffer "type.MyCBuffer" 1637OpMemberName %type_MyCBuffer 0 "Data" 1638OpName %MyCBuffer "MyCBuffer" 1639OpName %main "main" 1640OpName %in_var_INDEX "in.var.INDEX" 1641OpName %out_var_SV_Target "out.var.SV_Target" 1642OpDecorate %_arr_v4float_uint_8 ArrayStride 16 1643OpMemberDecorate %type_MyCBuffer 0 Offset 0 1644OpDecorate %type_MyCBuffer Block 1645OpDecorate %in_var_INDEX Flat 1646OpDecorate %in_var_INDEX Location 0 1647OpDecorate %out_var_SV_Target Location 0 1648OpDecorate %MyCBuffer DescriptorSet 0 1649OpDecorate %MyCBuffer Binding 0 1650%float = OpTypeFloat 32 1651%v4float = OpTypeVector %float 4 1652%uint = OpTypeInt 32 0 1653%uint_8 = OpConstant %uint 8 1654%uint_32 = OpConstant %uint 32 1655%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 1656%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 1657%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 1658%void = OpTypeVoid 1659%13 = OpTypeFunction %void 1660%int = OpTypeInt 32 1 1661%_ptr_Input_int = OpTypePointer Input %int 1662%_ptr_Output_v4float = OpTypePointer Output %v4float 1663%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 1664%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 1665%int_0 = OpConstant %int 0 1666%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 1667%_ptr_Function_v4float = OpTypePointer Function %v4float 1668%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 1669%in_var_INDEX = OpVariable %_ptr_Input_int Input 1670%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 1671%null_expr = OpExtInst %void %ext DebugExpression 1672%src = OpExtInst %void %ext DebugSource %file_name 1673%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL 1674%dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float 1675%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf 1676%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main 1677 1678; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref 1679; CHECK: [[dbg_f:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable 1680%dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal 1681 1682; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]] 1683; CHECK: OpAccessChain 1684; CHECK: [[newptr:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1685; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_f]] [[newptr]] [[deref_expr]] 1686; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[newptr]] %24 1687; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]] 1688; CHECK: OpStore %out_var_SV_Target [[load]] 1689%main = OpFunction %void None %13 1690%22 = OpLabel 1691%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 1692%24 = OpLoad %int %in_var_INDEX 1693%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1694%26 = OpLoad %_arr_v4float_uint_8 %25 1695%27 = OpCompositeExtract %v4float %26 0 1696%28 = OpCompositeExtract %v4float %26 1 1697%29 = OpCompositeExtract %v4float %26 2 1698%30 = OpCompositeExtract %v4float %26 3 1699%31 = OpCompositeExtract %v4float %26 4 1700%32 = OpCompositeExtract %v4float %26 5 1701%33 = OpCompositeExtract %v4float %26 6 1702%34 = OpCompositeExtract %v4float %26 7 1703%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34 1704OpStore %23 %35 1705%decl = OpExtInst %void %ext DebugDeclare %dbg_f %23 %null_expr 1706%36 = OpAccessChain %_ptr_Function_v4float %23 %24 1707%37 = OpLoad %v4float %36 1708OpStore %out_var_SV_Target %37 1709OpReturn 1710OpFunctionEnd 1711)"; 1712 1713 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1714 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1715 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1716 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 1717} 1718 1719TEST_F(CopyPropArrayPassTest, DebugValue) { 1720 const std::string before = 1721 R"(OpCapability Shader 1722%ext = OpExtInstImport "OpenCL.DebugInfo.100" 1723OpMemoryModel Logical GLSL450 1724OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target 1725OpExecutionMode %main OriginUpperLeft 1726OpSource HLSL 600 1727%file_name = OpString "test" 1728%float_name = OpString "float" 1729%main_name = OpString "main" 1730%f_name = OpString "f" 1731OpName %type_MyCBuffer "type.MyCBuffer" 1732OpMemberName %type_MyCBuffer 0 "Data" 1733OpName %MyCBuffer "MyCBuffer" 1734OpName %main "main" 1735OpName %in_var_INDEX "in.var.INDEX" 1736OpName %out_var_SV_Target "out.var.SV_Target" 1737OpDecorate %_arr_v4float_uint_8 ArrayStride 16 1738OpMemberDecorate %type_MyCBuffer 0 Offset 0 1739OpDecorate %type_MyCBuffer Block 1740OpDecorate %in_var_INDEX Flat 1741OpDecorate %in_var_INDEX Location 0 1742OpDecorate %out_var_SV_Target Location 0 1743OpDecorate %MyCBuffer DescriptorSet 0 1744OpDecorate %MyCBuffer Binding 0 1745%float = OpTypeFloat 32 1746%v4float = OpTypeVector %float 4 1747%uint = OpTypeInt 32 0 1748%uint_8 = OpConstant %uint 8 1749%uint_32 = OpConstant %uint 32 1750%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8 1751%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8 1752%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer 1753%void = OpTypeVoid 1754%13 = OpTypeFunction %void 1755%int = OpTypeInt 32 1 1756%_ptr_Input_int = OpTypePointer Input %int 1757%_ptr_Output_v4float = OpTypePointer Output %v4float 1758%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8 1759%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0 1760%int_0 = OpConstant %int 0 1761%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8 1762%_ptr_Function_v4float = OpTypePointer Function %v4float 1763%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform 1764%in_var_INDEX = OpVariable %_ptr_Input_int Input 1765%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output 1766 1767; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref 1768; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]] 1769%deref = OpExtInst %void %ext DebugOperation Deref 1770%expr = OpExtInst %void %ext DebugExpression %deref 1771%src = OpExtInst %void %ext DebugSource %file_name 1772%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL 1773%dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float 1774%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf 1775%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main 1776 1777; CHECK: [[dbg_f:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable 1778%dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal 1779%main = OpFunction %void None %13 1780%22 = OpLabel 1781%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function 1782%24 = OpLoad %int %in_var_INDEX 1783%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1784%26 = OpLoad %_arr_v4float_uint_8 %25 1785%27 = OpCompositeExtract %v4float %26 0 1786%28 = OpCompositeExtract %v4float %26 1 1787%29 = OpCompositeExtract %v4float %26 2 1788%30 = OpCompositeExtract %v4float %26 3 1789%31 = OpCompositeExtract %v4float %26 4 1790%32 = OpCompositeExtract %v4float %26 5 1791%33 = OpCompositeExtract %v4float %26 6 1792%34 = OpCompositeExtract %v4float %26 7 1793%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34 1794OpStore %23 %35 1795 1796; CHECK: OpAccessChain 1797; CHECK: [[newptr:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0 1798; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_f]] [[newptr]] [[deref_expr]] 1799; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[newptr]] %24 1800; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]] 1801; CHECK: OpStore %out_var_SV_Target [[load]] 1802%decl = OpExtInst %void %ext DebugValue %dbg_f %23 %expr 1803%36 = OpAccessChain %_ptr_Function_v4float %23 %24 1804%37 = OpLoad %v4float %36 1805OpStore %out_var_SV_Target %37 1806OpReturn 1807OpFunctionEnd 1808)"; 1809 1810 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1811 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 1812 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1813 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 1814} 1815 1816TEST_F(CopyPropArrayPassTest, FunctionDeclaration) { 1817 // Make sure the pass works with a function declaration that is called. 1818 const std::string text = R"(OpCapability Addresses 1819OpCapability Linkage 1820OpCapability Kernel 1821OpCapability Int8 1822%1 = OpExtInstImport "OpenCL.std" 1823OpMemoryModel Physical64 OpenCL 1824OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" 1825OpExecutionMode %2 ContractionOff 1826OpSource Unknown 0 1827OpDecorate %3 LinkageAttributes "julia_error_7712" Import 1828%void = OpTypeVoid 1829%5 = OpTypeFunction %void 1830%3 = OpFunction %void None %5 1831OpFunctionEnd 1832%2 = OpFunction %void None %5 1833%6 = OpLabel 1834%7 = OpFunctionCall %void %3 1835OpReturn 1836OpFunctionEnd 1837)"; 1838 1839 SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false); 1840} 1841 1842// Since Spir-V 1.4, resources that are used by a shader must be on the 1843// OpEntryPoint instruction with the inputs and outputs. This test ensures that 1844// this does not stop the pass from working. 1845TEST_F(CopyPropArrayPassTest, EntryPointUser) { 1846 const std::string before = R"(OpCapability Shader 1847OpMemoryModel Logical GLSL450 1848OpEntryPoint GLCompute %main "main" %g_rwTexture3d 1849OpExecutionMode %main LocalSize 256 1 1 1850OpSource HLSL 660 1851OpName %type_3d_image "type.3d.image" 1852OpName %g_rwTexture3d "g_rwTexture3d" 1853OpName %main "main" 1854OpDecorate %g_rwTexture3d DescriptorSet 0 1855OpDecorate %g_rwTexture3d Binding 0 1856%uint = OpTypeInt 32 0 1857%uint_0 = OpConstant %uint 0 1858%uint_1 = OpConstant %uint 1 1859%uint_2 = OpConstant %uint 2 1860%uint_3 = OpConstant %uint 3 1861%v3uint = OpTypeVector %uint 3 1862%10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3 1863%type_3d_image = OpTypeImage %uint 3D 2 0 0 2 R32ui 1864%_ptr_UniformConstant_type_3d_image = OpTypePointer UniformConstant %type_3d_image 1865%void = OpTypeVoid 1866%13 = OpTypeFunction %void 1867%_ptr_Function_type_3d_image = OpTypePointer Function %type_3d_image 1868%_ptr_Image_uint = OpTypePointer Image %uint 1869%g_rwTexture3d = OpVariable %_ptr_UniformConstant_type_3d_image UniformConstant 1870%main = OpFunction %void None %13 1871%16 = OpLabel 1872%17 = OpVariable %_ptr_Function_type_3d_image Function 1873%18 = OpLoad %type_3d_image %g_rwTexture3d 1874OpStore %17 %18 1875; CHECK: %19 = OpImageTexelPointer %_ptr_Image_uint %g_rwTexture3d %10 %uint_0 1876%19 = OpImageTexelPointer %_ptr_Image_uint %17 %10 %uint_0 1877%20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1 1878OpReturn 1879OpFunctionEnd 1880)"; 1881 1882 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1883 SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); 1884 SinglePassRunAndMatch<CopyPropagateArrays>(before, false); 1885} 1886 1887// As per SPIRV spec, struct cannot be indexed with non-constant indices 1888// through OpAccessChain, only arrays. 1889// The copy-propagate-array pass tries to remove superfluous copies when the 1890// original array could be indexed instead of the copy. 1891// 1892// This test verifies we handle this case: 1893// struct SRC { int field1; ...; int fieldN } 1894// int tmp_arr[N] = { SRC.field1, ..., SRC.fieldN } 1895// return tmp_arr[index]; 1896// 1897// In such case, we cannot optimize the access: this array was added to allow 1898// dynamic indexing in the struct. 1899TEST_F(CopyPropArrayPassTest, StructIndexCannotBecomeDynamic) { 1900 const std::string text = R"(OpCapability Shader 1901OpMemoryModel Logical GLSL450 1902OpEntryPoint Vertex %1 "main" 1903OpDecorate %2 DescriptorSet 0 1904OpDecorate %2 Binding 0 1905OpMemberDecorate %_struct_3 0 Offset 0 1906OpDecorate %_struct_3 Block 1907%int = OpTypeInt 32 1 1908%int_0 = OpConstant %int 0 1909%float = OpTypeFloat 32 1910%v4float = OpTypeVector %float 4 1911%_struct_3 = OpTypeStruct %v4float 1912%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 1913%uint = OpTypeInt 32 0 1914%void = OpTypeVoid 1915%11 = OpTypeFunction %void 1916%_ptr_Function_uint = OpTypePointer Function %uint 1917%13 = OpTypeFunction %v4float %_ptr_Function_uint 1918%uint_1 = OpConstant %uint 1 1919%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 1920%_ptr_Function__arr_v4float_uint_1 = OpTypePointer Function %_arr_v4float_uint_1 1921%_ptr_Function_v4float = OpTypePointer Function %v4float 1922%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float 1923%2 = OpVariable %_ptr_Uniform__struct_3 Uniform 1924%19 = OpUndef %v4float 1925%1 = OpFunction %void None %11 1926%20 = OpLabel 1927OpReturn 1928OpFunctionEnd 1929%21 = OpFunction %v4float None %13 1930%22 = OpFunctionParameter %_ptr_Function_uint 1931%23 = OpLabel 1932%24 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function 1933%25 = OpAccessChain %_ptr_Uniform_v4float %2 %int_0 1934%26 = OpLoad %v4float %25 1935%27 = OpCompositeConstruct %_arr_v4float_uint_1 %26 1936OpStore %24 %27 1937%28 = OpLoad %uint %22 1938%29 = OpAccessChain %_ptr_Function_v4float %24 %28 1939OpReturnValue %19 1940OpFunctionEnd 1941)"; 1942 1943 SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false); 1944} 1945} // namespace 1946} // namespace opt 1947} // namespace spvtools 1948