From e065cc208f499f906301f92c6e9e51881b3943e9 Mon Sep 17 00:00:00 2001 From: Steven Perron <31666470+s-perron@users.noreply.github.com> Date: Wed, 15 Aug 2018 09:14:21 -0400 Subject: [PATCH] Keep decorations when replacing loads in access-chain-convert. (#1829) In local-access-chain-convert, we replace loads by load the entire variable, then doing the extract. The extract will have the same value as the load. However, if the load has a decoration on it, the decoration is lost because we do not copy any them to the new id. This is fixed by rewritting the load into the extract and keeping the same result id. This change has the effect that we do not call DCEInst on the loads because the load is not being deleted, but replaced. This could leave OpAccessChain instructions around that are not used. This is not a problem for -O and -Os. They run local_single_*_elim passes and then dead code elimination. The dce will remove the unused access chains, and the load elimination passes work even if there are unused access chains. I have added test to them to ensure they will not loss opportunities. Fixes #1787. --- .../opt/local_access_chain_convert_pass.cpp | 44 +- source/opt/local_access_chain_convert_pass.h | 11 +- source/opt/local_single_block_elim_pass.cpp | 1 + test/opt/local_access_chain_convert_test.cpp | 383 +++++------------- test/opt/local_single_block_elim.cpp | 77 ++++ test/opt/local_single_store_elim_test.cpp | 74 ++++ 6 files changed, 290 insertions(+), 300 deletions(-) diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index 20e1030b8..6d540751d 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -16,8 +16,9 @@ #include "source/opt/local_access_chain_convert_pass.h" -#include "source/opt/ir_context.h" -#include "source/opt/iterator.h" +#include "ir_builder.h" +#include "ir_context.h" +#include "iterator.h" namespace spvtools { namespace opt { @@ -69,24 +70,29 @@ void LocalAccessChainConvertPass::AppendConstantOperands( }); } -uint32_t LocalAccessChainConvertPass::GenAccessChainLoadReplacement( - const Instruction* ptrInst, - std::vector>* newInsts) { +void LocalAccessChainConvertPass::ReplaceAccessChainLoad( + const Instruction* address_inst, Instruction* original_load) { // Build and append load of variable in ptrInst + std::vector> new_inst; uint32_t varId; uint32_t varPteTypeId; const uint32_t ldResultId = - BuildAndAppendVarLoad(ptrInst, &varId, &varPteTypeId, newInsts); + BuildAndAppendVarLoad(address_inst, &varId, &varPteTypeId, &new_inst); + original_load->InsertBefore(std::move(new_inst)); - // Build and append Extract - const uint32_t extResultId = TakeNextId(); - const uint32_t ptrPteTypeId = GetPointeeTypeId(ptrInst); - std::vector ext_in_opnds = { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ldResultId}}}; - AppendConstantOperands(ptrInst, &ext_in_opnds); - BuildAndAppendInst(SpvOpCompositeExtract, ptrPteTypeId, extResultId, - ext_in_opnds, newInsts); - return extResultId; + // Rewrite |original_load| into an extract. + Instruction::OperandList new_operands; + + // copy the result id and the type id to the new operand list. + new_operands.emplace_back(original_load->GetOperand(0)); + new_operands.emplace_back(original_load->GetOperand(1)); + + new_operands.emplace_back( + Operand({spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ldResultId}})); + AppendConstantOperands(address_inst, &new_operands); + original_load->SetOpcode(SpvOpCompositeExtract); + original_load->ReplaceOperands(new_operands); + context()->UpdateDefUse(original_load); } void LocalAccessChainConvertPass::GenAccessChainStoreReplacement( @@ -200,13 +206,7 @@ bool LocalAccessChainConvertPass::ConvertLocalAccessChains(Function* func) { if (!IsNonPtrAccessChain(ptrInst->opcode())) break; if (!IsTargetVar(varId)) break; std::vector> newInsts; - uint32_t replId = GenAccessChainLoadReplacement(ptrInst, &newInsts); - context()->KillNamesAndDecorates(&*ii); - context()->ReplaceAllUsesWith(ii->result_id(), replId); - dead_instructions.push_back(&*ii); - ++ii; - ii = ii.InsertBefore(std::move(newInsts)); - ++ii; + ReplaceAccessChainLoad(ptrInst, &*ii); modified = true; } break; case SpvOpStore: { diff --git a/source/opt/local_access_chain_convert_pass.h b/source/opt/local_access_chain_convert_pass.h index fc5936160..9d06890bf 100644 --- a/source/opt/local_access_chain_convert_pass.h +++ b/source/opt/local_access_chain_convert_pass.h @@ -86,11 +86,12 @@ class LocalAccessChainConvertPass : public MemPass { const Instruction* ptrInst, uint32_t valId, std::vector>* newInsts); - // For the (constant index) access chain |ptrInst|, create an - // equivalent load and extract. Append to |newInsts|. - uint32_t GenAccessChainLoadReplacement( - const Instruction* ptrInst, - std::vector>* newInsts); + // For the (constant index) access chain |address_inst|, create an + // equivalent load and extract that replaces |original_load|. The result id + // of the extract will be the same as the original result id of + // |original_load|. + void ReplaceAccessChainLoad(const Instruction* address_inst, + Instruction* original_load); // Return true if all indices of access chain |acp| are OpConstant integers bool IsConstantIndexAccessChain(const Instruction* acp) const; diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index 19dde6a11..bb909f4aa 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -78,6 +78,7 @@ bool LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElim( if (prev_store != var2store_.end() && instructions_to_save.count(prev_store->second) == 0) { instructions_to_kill.push_back(prev_store->second); + modified = true; } bool kill_store = false; diff --git a/test/opt/local_access_chain_convert_test.cpp b/test/opt/local_access_chain_convert_test.cpp index 94456da85..f15a95071 100644 --- a/test/opt/local_access_chain_convert_test.cpp +++ b/test/opt/local_access_chain_convert_test.cpp @@ -24,6 +24,8 @@ namespace { using LocalAccessChainConvertTest = PassTest<::testing::Test>; +#ifdef SPIRV_EFFCEE + TEST_F(LocalAccessChainConvertTest, StructOfVecsOfFloatConverted) { // #version 140 // @@ -68,38 +70,18 @@ OpName %gl_FragColor "gl_FragColor" %_ptr_Function_v4float = OpTypePointer Function %v4float %_ptr_Output_v4float = OpTypePointer Output %v4float %gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string predefs_after = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %S_t "S_t" -OpMemberName %S_t 0 "v0" -OpMemberName %S_t 1 "v1" -OpName %s0 "s0" -OpName %BaseColor "BaseColor" -OpName %gl_FragColor "gl_FragColor" -%void = OpTypeVoid -%8 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%S_t = OpTypeStruct %v4float %v4float -%_ptr_Function_S_t = OpTypePointer Function %S_t -%int = OpTypeInt 32 1 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output )"; const std::string before = - R"(%main = OpFunction %void None %8 + R"( +; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor +; CHECK: [[ld1:%\w+]] = OpLoad %S_t %s0 +; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1 +; CHECK: OpStore %s0 [[ex1]] +; CHECK: [[ld2:%\w+]] = OpLoad %S_t %s0 +; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1 +; CHECK: OpStore %gl_FragColor [[ex2]] +%main = OpFunction %void None %8 %17 = OpLabel %s0 = OpVariable %_ptr_Function_S_t Function %18 = OpLoad %v4float %BaseColor @@ -112,23 +94,8 @@ OpReturn OpFunctionEnd )"; - const std::string after = - R"(%main = OpFunction %void None %8 -%17 = OpLabel -%s0 = OpVariable %_ptr_Function_S_t Function -%18 = OpLoad %v4float %BaseColor -%22 = OpLoad %S_t %s0 -%23 = OpCompositeInsert %S_t %18 %22 1 -OpStore %s0 %23 -%24 = OpLoad %S_t %s0 -%25 = OpCompositeExtract %v4float %24 1 -OpStore %gl_FragColor %25 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck( - predefs_before + before, predefs_after + after, true, true); + SinglePassRunAndMatch(predefs_before + before, + true); } TEST_F(LocalAccessChainConvertTest, InBoundsAccessChainsConverted) { @@ -175,38 +142,18 @@ OpName %gl_FragColor "gl_FragColor" %_ptr_Function_v4float = OpTypePointer Function %v4float %_ptr_Output_v4float = OpTypePointer Output %v4float %gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string predefs_after = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %S_t "S_t" -OpMemberName %S_t 0 "v0" -OpMemberName %S_t 1 "v1" -OpName %s0 "s0" -OpName %BaseColor "BaseColor" -OpName %gl_FragColor "gl_FragColor" -%void = OpTypeVoid -%8 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%S_t = OpTypeStruct %v4float %v4float -%_ptr_Function_S_t = OpTypePointer Function %S_t -%int = OpTypeInt 32 1 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output )"; const std::string before = - R"(%main = OpFunction %void None %8 + R"( +; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor +; CHECK: [[ld1:%\w+]] = OpLoad %S_t %s0 +; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1 +; CHECK: OpStore %s0 [[ex1]] +; CHECK: [[ld2:%\w+]] = OpLoad %S_t %s0 +; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1 +; CHECK: OpStore %gl_FragColor [[ex2]] +%main = OpFunction %void None %8 %17 = OpLabel %s0 = OpVariable %_ptr_Function_S_t Function %18 = OpLoad %v4float %BaseColor @@ -219,23 +166,8 @@ OpReturn OpFunctionEnd )"; - const std::string after = - R"(%main = OpFunction %void None %8 -%17 = OpLabel -%s0 = OpVariable %_ptr_Function_S_t Function -%18 = OpLoad %v4float %BaseColor -%22 = OpLoad %S_t %s0 -%23 = OpCompositeInsert %S_t %18 %22 1 -OpStore %s0 %23 -%24 = OpLoad %S_t %s0 -%25 = OpCompositeExtract %v4float %24 1 -OpStore %gl_FragColor %25 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck( - predefs_before + before, predefs_after + after, true, true); + SinglePassRunAndMatch(predefs_before + before, + true); } TEST_F(LocalAccessChainConvertTest, TwoUsesofSingleChainConverted) { @@ -282,38 +214,18 @@ OpName %gl_FragColor "gl_FragColor" %_ptr_Function_v4float = OpTypePointer Function %v4float %_ptr_Output_v4float = OpTypePointer Output %v4float %gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string predefs_after = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %S_t "S_t" -OpMemberName %S_t 0 "v0" -OpMemberName %S_t 1 "v1" -OpName %s0 "s0" -OpName %BaseColor "BaseColor" -OpName %gl_FragColor "gl_FragColor" -%void = OpTypeVoid -%8 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%S_t = OpTypeStruct %v4float %v4float -%_ptr_Function_S_t = OpTypePointer Function %S_t -%int = OpTypeInt 32 1 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output )"; const std::string before = - R"(%main = OpFunction %void None %8 + R"( +; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor +; CHECK: [[ld1:%\w+]] = OpLoad %S_t %s0 +; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1 +; CHECK: OpStore %s0 [[ex1]] +; CHECK: [[ld2:%\w+]] = OpLoad %S_t %s0 +; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1 +; CHECK: OpStore %gl_FragColor [[ex2]] +%main = OpFunction %void None %8 %17 = OpLabel %s0 = OpVariable %_ptr_Function_S_t Function %18 = OpLoad %v4float %BaseColor @@ -325,23 +237,8 @@ OpReturn OpFunctionEnd )"; - const std::string after = - R"(%main = OpFunction %void None %8 -%17 = OpLabel -%s0 = OpVariable %_ptr_Function_S_t Function -%18 = OpLoad %v4float %BaseColor -%21 = OpLoad %S_t %s0 -%22 = OpCompositeInsert %S_t %18 %21 1 -OpStore %s0 %22 -%23 = OpLoad %S_t %s0 -%24 = OpCompositeExtract %v4float %23 1 -OpStore %gl_FragColor %24 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck( - predefs_before + before, predefs_after + after, true, true); + SinglePassRunAndMatch(predefs_before + before, + true); } TEST_F(LocalAccessChainConvertTest, OpaqueConverted) { @@ -349,7 +246,8 @@ TEST_F(LocalAccessChainConvertTest, OpaqueConverted) { // at the moment const std::string predefs = - R"(OpCapability Shader + R"( +OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %outColor %texCoords @@ -392,7 +290,13 @@ OpDecorate %sampler15 DescriptorSet 0 )"; const std::string before = - R"(%main = OpFunction %void None %12 + R"( +; CHECK: [[l1:%\w+]] = OpLoad %S_t %param +; CHECK: [[e1:%\w+]] = OpCompositeExtract {{%\w+}} [[l1]] 2 +; CHECK: [[l2:%\w+]] = OpLoad %S_t %param +; CHECK: [[e2:%\w+]] = OpCompositeExtract {{%\w+}} [[l2]] 0 +; CHECK: OpImageSampleImplicitLod {{%\w+}} [[e1]] [[e2]] +%main = OpFunction %void None %12 %28 = OpLabel %s0 = OpVariable %_ptr_Function_S_t Function %param = OpVariable %_ptr_Function_S_t Function @@ -412,31 +316,6 @@ OpStore %param %33 OpStore %outColor %38 OpReturn OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %12 -%28 = OpLabel -%s0 = OpVariable %_ptr_Function_S_t Function -%param = OpVariable %_ptr_Function_S_t Function -%29 = OpLoad %v2float %texCoords -%45 = OpLoad %S_t %s0 -%46 = OpCompositeInsert %S_t %29 %45 0 -OpStore %s0 %46 -%31 = OpLoad %18 %sampler15 -%47 = OpLoad %S_t %s0 -%48 = OpCompositeInsert %S_t %31 %47 2 -OpStore %s0 %48 -%33 = OpLoad %S_t %s0 -OpStore %param %33 -%49 = OpLoad %S_t %param -%50 = OpCompositeExtract %18 %49 2 -%51 = OpLoad %S_t %param -%52 = OpCompositeExtract %v2float %51 0 -%38 = OpImageSampleImplicitLod %v4float %50 %52 -OpStore %outColor %38 -OpReturn -OpFunctionEnd )"; const std::string remain = @@ -453,8 +332,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck( - predefs + before + remain, predefs + after + remain, true, true); + SinglePassRunAndMatch(predefs + before + remain, + true); } TEST_F(LocalAccessChainConvertTest, NestedStructsConverted) { @@ -509,41 +388,18 @@ OpName %gl_FragColor "gl_FragColor" %_ptr_Function_v4float = OpTypePointer Function %v4float %_ptr_Output_v4float = OpTypePointer Output %v4float %gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string predefs_after = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %S1_t "S1_t" -OpMemberName %S1_t 0 "v1" -OpName %S2_t "S2_t" -OpMemberName %S2_t 0 "v2" -OpMemberName %S2_t 1 "s1" -OpName %s2 "s2" -OpName %BaseColor "BaseColor" -OpName %gl_FragColor "gl_FragColor" -%void = OpTypeVoid -%9 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%S1_t = OpTypeStruct %v4float -%S2_t = OpTypeStruct %v4float %S1_t -%_ptr_Function_S2_t = OpTypePointer Function %S2_t -%int = OpTypeInt 32 1 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output )"; const std::string before = - R"(%main = OpFunction %void None %9 + R"( +; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor +; CHECK: [[ld1:%\w+]] = OpLoad %S2_t %s2 +; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S2_t [[st_id]] [[ld1]] 1 0 +; CHECK: OpStore %s2 [[ex1]] +; CHECK: [[ld2:%\w+]] = OpLoad %S2_t %s2 +; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1 0 +; CHECK: OpStore %gl_FragColor [[ex2]] +%main = OpFunction %void None %9 %19 = OpLabel %s2 = OpVariable %_ptr_Function_S2_t Function %20 = OpLoad %v4float %BaseColor @@ -556,25 +412,67 @@ OpReturn OpFunctionEnd )"; - const std::string after = - R"(%main = OpFunction %void None %9 -%19 = OpLabel -%s2 = OpVariable %_ptr_Function_S2_t Function -%20 = OpLoad %v4float %BaseColor -%24 = OpLoad %S2_t %s2 -%25 = OpCompositeInsert %S2_t %20 %24 1 0 -OpStore %s2 %25 -%26 = OpLoad %S2_t %s2 -%27 = OpCompositeExtract %v4float %26 1 0 -OpStore %gl_FragColor %27 + SinglePassRunAndMatch(predefs_before + before, + true); +} + +TEST_F(LocalAccessChainConvertTest, SomeAccessChainsHaveNoUse) { + // Based on HLSL source code: + // struct S { + // float f; + // }; + + // float main(float input : A) : B { + // S local = { input }; + // return local.f; + // } + + const std::string predefs = R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %in_var_A %out_var_B +OpName %main "main" +OpName %in_var_A "in.var.A" +OpName %out_var_B "out.var.B" +OpName %S "S" +OpName %local "local" +%int = OpTypeInt 32 1 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Output_float = OpTypePointer Output %float +%S = OpTypeStruct %float +%_ptr_Function_S = OpTypePointer Function %S +%int_0 = OpConstant %int 0 +%in_var_A = OpVariable %_ptr_Input_float Input +%out_var_B = OpVariable %_ptr_Output_float Output +%main = OpFunction %void None %8 +%15 = OpLabel +%local = OpVariable %_ptr_Function_S Function +%16 = OpLoad %float %in_var_A +%17 = OpCompositeConstruct %S %16 +OpStore %local %17 +)"; + + const std::string before = + R"( +; CHECK: [[ld:%\w+]] = OpLoad %S %local +; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 +; CHECK: OpStore %out_var_B [[ex]] +%18 = OpAccessChain %_ptr_Function_float %local %int_0 +%19 = OpAccessChain %_ptr_Function_float %local %int_0 +%20 = OpLoad %float %18 +OpStore %out_var_B %20 OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck( - predefs_before + before, predefs_after + after, true, true); + SinglePassRunAndMatch(predefs + before, true); } +#endif // SPIRV_EFFCEE + TEST_F(LocalAccessChainConvertTest, DynamicallyIndexedVarNotConverted) { // #version 140 // @@ -651,67 +549,6 @@ OpFunctionEnd true); } -TEST_F(LocalAccessChainConvertTest, SomeAccessChainsHaveNoUse) { - // Based on HLSL source code: - // struct S { - // float f; - // }; - - // float main(float input : A) : B { - // S local = { input }; - // return local.f; - // } - - const std::string predefs = R"(OpCapability Shader -OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %main "main" %in_var_A %out_var_B -OpName %main "main" -OpName %in_var_A "in.var.A" -OpName %out_var_B "out.var.B" -OpName %S "S" -OpName %local "local" -%int = OpTypeInt 32 1 -%void = OpTypeVoid -%8 = OpTypeFunction %void -%float = OpTypeFloat 32 -%_ptr_Function_float = OpTypePointer Function %float -%_ptr_Input_float = OpTypePointer Input %float -%_ptr_Output_float = OpTypePointer Output %float -%S = OpTypeStruct %float -%_ptr_Function_S = OpTypePointer Function %S -%int_0 = OpConstant %int 0 -%in_var_A = OpVariable %_ptr_Input_float Input -%out_var_B = OpVariable %_ptr_Output_float Output -%main = OpFunction %void None %8 -%15 = OpLabel -%local = OpVariable %_ptr_Function_S Function -%16 = OpLoad %float %in_var_A -%17 = OpCompositeConstruct %S %16 -OpStore %local %17 -)"; - - const std::string before = - R"(%18 = OpAccessChain %_ptr_Function_float %local %int_0 -%19 = OpAccessChain %_ptr_Function_float %local %int_0 -%20 = OpLoad %float %18 -OpStore %out_var_B %20 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%19 = OpAccessChain %_ptr_Function_float %local %int_0 -%21 = OpLoad %S %local -%22 = OpCompositeExtract %float %21 0 -OpStore %out_var_B %22 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck( - predefs + before, predefs + after, true, true); -} - // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Assorted vector and matrix types diff --git a/test/opt/local_single_block_elim.cpp b/test/opt/local_single_block_elim.cpp index 29d978a21..da7540e6b 100644 --- a/test/opt/local_single_block_elim.cpp +++ b/test/opt/local_single_block_elim.cpp @@ -983,6 +983,83 @@ OpFunctionEnd SinglePassRunAndCheck( predefs_before + before, predefs_before + after, true, true); } + +// Test that that an unused OpAccessChain between two store does does not +// hinders the removal of the first store. We need to check this because +// local-access-chain-convert does always remove the OpAccessChain instructions +// that become dead. + +TEST_F(LocalSingleBlockLoadStoreElimTest, + StoreElimIfInterveningUnusedAccessChain) { + const std::string predefs = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %BaseColor0 %Idx %BaseColor1 %OutColor +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpName %main "main" +OpName %v "v" +OpName %BaseColor0 "BaseColor0" +OpName %Idx "Idx" +OpName %BaseColor1 "BaseColor1" +OpName %OutColor "OutColor" +OpDecorate %BaseColor0 Location 0 +OpDecorate %Idx Flat +OpDecorate %Idx Location 2 +OpDecorate %BaseColor1 Location 1 +OpDecorate %OutColor Location 0 +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v4float = OpTypePointer Input %v4float +%BaseColor0 = OpVariable %_ptr_Input_v4float Input +%_ptr_Function_float = OpTypePointer Function %float +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%Idx = OpVariable %_ptr_Input_int Input +%BaseColor1 = OpVariable %_ptr_Input_v4float Input +%float_0_100000001 = OpConstant %float 0.100000001 +%19 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%OutColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string before = + R"(%main = OpFunction %void None %10 +%21 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%22 = OpLoad %v4float %BaseColor0 +OpStore %v %22 +%23 = OpLoad %int %Idx +%24 = OpAccessChain %_ptr_Function_float %v %23 +%26 = OpLoad %v4float %BaseColor1 +%27 = OpFAdd %v4float %26 %19 +OpStore %v %27 +OpReturn +OpFunctionEnd +)"; + + const std::string after = + R"(%main = OpFunction %void None %10 +%21 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%22 = OpLoad %v4float %BaseColor0 +%23 = OpLoad %int %Idx +%24 = OpAccessChain %_ptr_Function_float %v %23 +%26 = OpLoad %v4float %BaseColor1 +%27 = OpFAdd %v4float %26 %19 +OpStore %v %27 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + predefs + before, predefs + after, true, true); +} // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Other target variable types diff --git a/test/opt/local_single_store_elim_test.cpp b/test/opt/local_single_store_elim_test.cpp index 51bd5d29f..23e82ba86 100644 --- a/test/opt/local_single_store_elim_test.cpp +++ b/test/opt/local_single_store_elim_test.cpp @@ -771,6 +771,80 @@ OpFunctionEnd SinglePassRunAndCheck(before, after, true, true); } +// Test that that an unused OpAccessChain between a store and a use does does +// not hinders the replacement of the use. We need to check this because +// local-access-chain-convert does always remove the OpAccessChain instructions +// that become dead. + +TEST_F(LocalSingleStoreElimTest, + StoreElimWithUnusedInterveningAccessChainLoad) { + // Last load of v is eliminated, but access chain load and store of v isn't + // + // #version 140 + // + // in vec4 BaseColor; + // + // void main() + // { + // vec4 v = BaseColor; + // float f = v[3]; + // gl_FragColor = v * f; + // } + + const std::string predefs = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +OpName %main "main" +OpName %v "v" +OpName %BaseColor "BaseColor" +OpName %gl_FragColor "gl_FragColor" +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v4float = OpTypePointer Input %v4float +%BaseColor = OpVariable %_ptr_Input_v4float Input +%_ptr_Function_float = OpTypePointer Function %float +%uint = OpTypeInt 32 0 +%uint_3 = OpConstant %uint 3 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%gl_FragColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string before = + R"(%main = OpFunction %void None %8 +%17 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%18 = OpLoad %v4float %BaseColor +OpStore %v %18 +%19 = OpAccessChain %_ptr_Function_float %v %uint_3 +%21 = OpLoad %v4float %v +OpStore %gl_FragColor %21 +OpReturn +OpFunctionEnd +)"; + + const std::string after = + R"(%main = OpFunction %void None %8 +%17 = OpLabel +%v = OpVariable %_ptr_Function_v4float Function +%18 = OpLoad %v4float %BaseColor +OpStore %v %18 +%19 = OpAccessChain %_ptr_Function_float %v %uint_3 +OpStore %gl_FragColor %18 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(predefs + before, + predefs + after, true, true); +} // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Other types