Upgrade elim-local-single-block for OpenCL.DebugInfo.100 (#3451)
Creates a DebugValue when removing a store to a local variable.
diff --git a/source/opt/debug_info_manager.cpp b/source/opt/debug_info_manager.cpp
index e0c946e..6f1aa2e 100644
--- a/source/opt/debug_info_manager.cpp
+++ b/source/opt/debug_info_manager.cpp
@@ -369,6 +369,11 @@
std::move(new_inlined_at));
}
+bool DebugInfoManager::IsDebugDeclared(uint32_t variable_id) {
+ auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
+ return dbg_decl_itr != var_id_to_dbg_decl_.end();
+}
+
uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) {
auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope);
assert(dbg_scope_itr != id_to_dbg_inst_.end());
diff --git a/source/opt/debug_info_manager.h b/source/opt/debug_info_manager.h
index e8de5a4..438e7c6 100644
--- a/source/opt/debug_info_manager.h
+++ b/source/opt/debug_info_manager.h
@@ -133,6 +133,9 @@
uint32_t BuildDebugInlinedAtChain(uint32_t callee_inlined_at,
DebugInlinedAtContext* inlined_at_ctx);
+ // Return true if |variable_id| has DebugDeclare or DebugVal.
+ bool IsDebugDeclared(uint32_t variable_id);
+
// Generates a DebugValue instruction with value |value_id| for every local
// variable that is in the scope of |scope_and_line| and whose memory is
// |variable_id| and inserts it after the instruction |insert_pos|.
diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp
index 401dad8..dea612e 100644
--- a/source/opt/local_single_block_elim_pass.cpp
+++ b/source/opt/local_single_block_elim_pass.cpp
@@ -31,6 +31,11 @@
bool LocalSingleBlockLoadStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) {
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
if (get_def_use_mgr()->WhileEachUser(ptrId, [this](Instruction* user) {
+ auto dbg_op = user->GetOpenCL100DebugOpcode();
+ if (dbg_op == OpenCLDebugInfo100DebugDeclare ||
+ dbg_op == OpenCLDebugInfo100DebugValue) {
+ return true;
+ }
SpvOp op = user->opcode();
if (IsNonPtrAccessChain(op) || op == SpvOpCopyObject) {
if (!HasOnlySupportedRefs(user->result_id())) {
@@ -73,10 +78,12 @@
// variable.
if (ptrInst->opcode() == SpvOpVariable) {
// If a previous store to same variable, mark the store
- // for deletion if not still used.
+ // for deletion if not still used. Don't delete store
+ // if debugging; let ssa-rewrite and DCE handle it
auto prev_store = var2store_.find(varId);
if (prev_store != var2store_.end() &&
- instructions_to_save.count(prev_store->second) == 0) {
+ instructions_to_save.count(prev_store->second) == 0 &&
+ !get_debug_info_mgr()->IsDebugDeclared(varId)) {
instructions_to_kill.push_back(prev_store->second);
modified = true;
}
diff --git a/test/opt/local_single_block_elim.cpp b/test/opt/local_single_block_elim.cpp
index 402352d..8e1cee6 100644
--- a/test/opt/local_single_block_elim.cpp
+++ b/test/opt/local_single_block_elim.cpp
@@ -1118,6 +1118,340 @@
)";
SinglePassRunAndMatch<LocalSingleBlockLoadStoreElimPass>(text, false);
}
+
+TEST_F(LocalSingleBlockLoadStoreElimTest, DebugDeclareTest) {
+ // If OpenCL.DebugInfo.100 enabled, check that store/load is still
+ // optimized, but stores are not deleted for store/store.
+ //
+ // struct PS_INPUT {
+ // float4 c0 : COLOR0;
+ // float4 c1 : COLOR1;
+ // };
+ //
+ // struct PS_OUTPUT {
+ // float4 vColor : SV_Target0;
+ // };
+ //
+ // PS_OUTPUT MainPs(PS_INPUT i) {
+ // PS_OUTPUT ps_output;
+ // float4 c;
+ // c = i.c0;
+ // c += i.c1;
+ // c /= 2.0;
+ // ps_output.vColor = c;
+ // return ps_output;
+ // }
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "OpenCL.DebugInfo.100"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %MainPs "MainPs" %in_var_COLOR0 %in_var_COLOR1 %out_var_SV_Target0
+ OpExecutionMode %MainPs OriginUpperLeft
+ %6 = OpString "foo3.frag"
+ %7 = OpString "PS_OUTPUT"
+ %8 = OpString "float"
+ %9 = OpString "vColor"
+ %10 = OpString "PS_INPUT"
+ %11 = OpString "c1"
+ %12 = OpString "c0"
+ %13 = OpString "src.MainPs"
+ %14 = OpString "c"
+ %15 = OpString "ps_output"
+ %16 = OpString "i"
+ OpName %in_var_COLOR0 "in.var.COLOR0"
+ OpName %in_var_COLOR1 "in.var.COLOR1"
+ OpName %out_var_SV_Target0 "out.var.SV_Target0"
+ OpName %MainPs "MainPs"
+ OpName %PS_INPUT "PS_INPUT"
+ OpMemberName %PS_INPUT 0 "c0"
+ OpMemberName %PS_INPUT 1 "c1"
+ OpName %param_var_i "param.var.i"
+ OpName %PS_OUTPUT "PS_OUTPUT"
+ OpMemberName %PS_OUTPUT 0 "vColor"
+ OpName %src_MainPs "src.MainPs"
+ OpName %i "i"
+ OpName %bb_entry "bb.entry"
+ OpName %ps_output "ps_output"
+ OpName %c "c"
+ OpDecorate %in_var_COLOR0 Location 0
+ OpDecorate %in_var_COLOR1 Location 1
+ OpDecorate %out_var_SV_Target0 Location 0
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %int_1 = OpConstant %int 1
+ %float = OpTypeFloat 32
+ %float_2 = OpConstant %float 2
+ %v4float = OpTypeVector %float 4
+ %31 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
+ %uint = OpTypeInt 32 0
+ %uint_32 = OpConstant %uint 32
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %void = OpTypeVoid
+ %uint_128 = OpConstant %uint 128
+ %uint_0 = OpConstant %uint 0
+ %uint_256 = OpConstant %uint 256
+ %40 = OpTypeFunction %void
+ %PS_INPUT = OpTypeStruct %v4float %v4float
+%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
+ %PS_OUTPUT = OpTypeStruct %v4float
+ %42 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
+%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%in_var_COLOR0 = OpVariable %_ptr_Input_v4float Input
+%in_var_COLOR1 = OpVariable %_ptr_Input_v4float Input
+%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output
+ %45 = OpExtInst %void %1 DebugSource %6
+ %46 = OpExtInst %void %1 DebugCompilationUnit 1 4 %45 HLSL
+ %47 = OpExtInst %void %1 DebugTypeComposite %7 Structure %45 8 1 %46 %7 %uint_128 FlagIsProtected|FlagIsPrivate %48
+ %49 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 Float
+ %50 = OpExtInst %void %1 DebugTypeVector %49 4
+ %48 = OpExtInst %void %1 DebugTypeMember %9 %50 %45 10 5 %47 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
+ %51 = OpExtInst %void %1 DebugTypeComposite %10 Structure %45 2 1 %46 %10 %uint_256 FlagIsProtected|FlagIsPrivate %52 %53
+ %53 = OpExtInst %void %1 DebugTypeMember %11 %50 %45 5 5 %51 %uint_128 %uint_128 FlagIsProtected|FlagIsPrivate
+ %52 = OpExtInst %void %1 DebugTypeMember %12 %50 %45 4 5 %51 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
+ %54 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %47 %51
+ %55 = OpExtInst %void %1 DebugFunction %13 %54 %45 13 1 %46 %13 FlagIsProtected|FlagIsPrivate 14 %src_MainPs
+ %56 = OpExtInst %void %1 DebugLexicalBlock %45 14 1 %55
+ %57 = OpExtInst %void %1 DebugLocalVariable %14 %50 %45 16 12 %56 FlagIsLocal
+ %58 = OpExtInst %void %1 DebugLocalVariable %15 %47 %45 15 15 %56 FlagIsLocal
+ %59 = OpExtInst %void %1 DebugExpression
+ %60 = OpExtInst %void %1 DebugLocalVariable %16 %51 %45 13 29 %55 FlagIsLocal 1
+ %61 = OpExtInst %void %1 DebugLocalVariable %14 %50 %45 16 12 %55 FlagIsLocal 1
+ %MainPs = OpFunction %void None %40
+ %62 = OpLabel
+%param_var_i = OpVariable %_ptr_Function_PS_INPUT Function
+ %63 = OpLoad %v4float %in_var_COLOR0
+ %64 = OpLoad %v4float %in_var_COLOR1
+ %65 = OpCompositeConstruct %PS_INPUT %63 %64
+ OpStore %param_var_i %65
+ %66 = OpFunctionCall %PS_OUTPUT %src_MainPs %param_var_i
+ %67 = OpCompositeExtract %v4float %66 0
+ OpStore %out_var_SV_Target0 %67
+ OpReturn
+ OpFunctionEnd
+ OpLine %6 13 1
+ %src_MainPs = OpFunction %PS_OUTPUT None %42
+ %83 = OpExtInst %void %1 DebugScope %55
+ OpLine %6 13 29
+ %i = OpFunctionParameter %_ptr_Function_PS_INPUT
+ %69 = OpExtInst %void %1 DebugDeclare %60 %i %59
+ %84 = OpExtInst %void %1 DebugNoScope
+ %bb_entry = OpLabel
+ %85 = OpExtInst %void %1 DebugScope %56
+ %ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
+ %c = OpVariable %_ptr_Function_v4float Function
+ %71 = OpExtInst %void %1 DebugDeclare %61 %c %59
+ OpLine %6 18 9
+ %72 = OpAccessChain %_ptr_Function_v4float %i %int_0
+ OpLine %6 18 13
+ %73 = OpLoad %v4float %72
+ OpLine %6 18 5
+ OpStore %c %73
+;CHECK: OpStore %c %73
+ OpLine %6 19 10
+ %74 = OpAccessChain %_ptr_Function_v4float %i %int_1
+ OpLine %6 19 14
+ %75 = OpLoad %v4float %74
+ OpLine %6 19 5
+ %76 = OpLoad %v4float %c
+;CHECK-NOT: OpLine %6 19 5
+;CHECK-NOT: %76 = OpLoad %v4float %c
+ OpLine %6 19 7
+ %77 = OpFAdd %v4float %76 %75
+;CHECK-NOT: %77 = OpFAdd %v4float %76 %75
+;CHECK: %77 = OpFAdd %v4float %73 %75
+ OpLine %6 19 5
+ OpStore %c %77
+;CHECK: OpStore %c %77
+ OpLine %6 20 5
+ %78 = OpLoad %v4float %c
+;CHECK-NOT: OpLine %6 20 5
+;CHECK-NOT: %78 = OpLoad %v4float %c
+ OpLine %6 20 7
+ %79 = OpFDiv %v4float %78 %31
+;CHECK-NOT %79 = OpFDiv %v4float %78 %31
+;CHECK: %79 = OpFDiv %v4float %77 %31
+ OpLine %6 20 5
+ OpStore %c %79
+;CHECK: OpStore %c %79
+ OpLine %6 22 26
+ %80 = OpLoad %v4float %c
+;CHECK-NOT: OpLine %6 22 26
+;CHECK-NOT: %80 = OpLoad %v4float %c
+ OpLine %6 22 5
+ %81 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
+ OpStore %81 %80
+;CHECK-NOT: OpStore %81 %80
+;CHECK: OpStore %81 %79
+ OpLine %6 23 12
+ %82 = OpLoad %PS_OUTPUT %ps_output
+ OpLine %6 23 5
+ OpReturnValue %82
+ %86 = OpExtInst %void %1 DebugNoScope
+ OpFunctionEnd
+ )";
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<LocalSingleBlockLoadStoreElimPass>(text, false);
+}
+TEST_F(LocalSingleBlockLoadStoreElimTest, DebugValueTest) {
+ // If OpenCL.DebugInfo.100 enabled, check that store/load is still
+ // optimized, but stores are not deleted for store/store.
+ // Same source as DebugDeclareTest; DebugDeclare replaced with
+ // equivalent DebugValue
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "OpenCL.DebugInfo.100"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %MainPs "MainPs" %in_var_COLOR0 %in_var_COLOR1 %out_var_SV_Target0
+ OpExecutionMode %MainPs OriginUpperLeft
+ %6 = OpString "foo3.frag"
+ %7 = OpString "PS_OUTPUT"
+ %8 = OpString "float"
+ %9 = OpString "vColor"
+ %10 = OpString "PS_INPUT"
+ %11 = OpString "c1"
+ %12 = OpString "c0"
+ %13 = OpString "src.MainPs"
+ %14 = OpString "c"
+ %15 = OpString "ps_output"
+ %16 = OpString "i"
+ OpName %in_var_COLOR0 "in.var.COLOR0"
+ OpName %in_var_COLOR1 "in.var.COLOR1"
+ OpName %out_var_SV_Target0 "out.var.SV_Target0"
+ OpName %MainPs "MainPs"
+ OpName %PS_INPUT "PS_INPUT"
+ OpMemberName %PS_INPUT 0 "c0"
+ OpMemberName %PS_INPUT 1 "c1"
+ OpName %param_var_i "param.var.i"
+ OpName %PS_OUTPUT "PS_OUTPUT"
+ OpMemberName %PS_OUTPUT 0 "vColor"
+ OpName %src_MainPs "src.MainPs"
+ OpName %i "i"
+ OpName %bb_entry "bb.entry"
+ OpName %ps_output "ps_output"
+ OpName %c "c"
+ OpDecorate %in_var_COLOR0 Location 0
+ OpDecorate %in_var_COLOR1 Location 1
+ OpDecorate %out_var_SV_Target0 Location 0
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %int_1 = OpConstant %int 1
+ %float = OpTypeFloat 32
+ %float_2 = OpConstant %float 2
+ %v4float = OpTypeVector %float 4
+ %31 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
+ %uint = OpTypeInt 32 0
+ %uint_32 = OpConstant %uint 32
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %void = OpTypeVoid
+ %uint_128 = OpConstant %uint 128
+ %uint_0 = OpConstant %uint 0
+ %uint_256 = OpConstant %uint 256
+ %40 = OpTypeFunction %void
+ %PS_INPUT = OpTypeStruct %v4float %v4float
+%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
+ %PS_OUTPUT = OpTypeStruct %v4float
+ %42 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
+%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%in_var_COLOR0 = OpVariable %_ptr_Input_v4float Input
+%in_var_COLOR1 = OpVariable %_ptr_Input_v4float Input
+%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output
+ %45 = OpExtInst %void %1 DebugSource %6
+ %46 = OpExtInst %void %1 DebugCompilationUnit 1 4 %45 HLSL
+ %47 = OpExtInst %void %1 DebugTypeComposite %7 Structure %45 8 1 %46 %7 %uint_128 FlagIsProtected|FlagIsPrivate %48
+ %49 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 Float
+ %50 = OpExtInst %void %1 DebugTypeVector %49 4
+ %48 = OpExtInst %void %1 DebugTypeMember %9 %50 %45 10 5 %47 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
+ %51 = OpExtInst %void %1 DebugTypeComposite %10 Structure %45 2 1 %46 %10 %uint_256 FlagIsProtected|FlagIsPrivate %52 %53
+ %53 = OpExtInst %void %1 DebugTypeMember %11 %50 %45 5 5 %51 %uint_128 %uint_128 FlagIsProtected|FlagIsPrivate
+ %52 = OpExtInst %void %1 DebugTypeMember %12 %50 %45 4 5 %51 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
+ %54 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %47 %51
+ %55 = OpExtInst %void %1 DebugFunction %13 %54 %45 13 1 %46 %13 FlagIsProtected|FlagIsPrivate 14 %src_MainPs
+ %56 = OpExtInst %void %1 DebugLexicalBlock %45 14 1 %55
+ %57 = OpExtInst %void %1 DebugLocalVariable %14 %50 %45 16 12 %56 FlagIsLocal
+ %58 = OpExtInst %void %1 DebugLocalVariable %15 %47 %45 15 15 %56 FlagIsLocal
+ %59 = OpExtInst %void %1 DebugExpression %60 = OpExtInst %void %1 DebugOperation Deref %61 = OpExtInst
+%void %1 DebugExpression %60 %62 = OpExtInst %void %1 DebugLocalVariable %16 %51
+%45 13 29 %55 FlagIsLocal 1 %63 = OpExtInst %void %1 DebugLocalVariable %14 %50
+%45 16 12 %55 FlagIsLocal 1 %MainPs = OpFunction %void None %40 %64 = OpLabel
+%param_var_i = OpVariable %_ptr_Function_PS_INPUT Function
+ %65 = OpLoad %v4float %in_var_COLOR0
+ %66 = OpLoad %v4float %in_var_COLOR1
+ %67 = OpCompositeConstruct %PS_INPUT %65 %66
+ OpStore %param_var_i %67
+ %68 = OpFunctionCall %PS_OUTPUT %src_MainPs %param_var_i
+ %69 = OpCompositeExtract %v4float %68 0
+ OpStore %out_var_SV_Target0 %69
+ OpReturn
+ OpFunctionEnd
+ OpLine %6 13 1
+ %src_MainPs = OpFunction %PS_OUTPUT None %42
+ %70 = OpExtInst %void %1 DebugScope %55
+ OpLine %6 13 29
+ %i = OpFunctionParameter %_ptr_Function_PS_INPUT
+ %71 = OpExtInst %void %1 DebugDeclare %62 %i %59
+ %72 = OpExtInst %void %1 DebugNoScope
+ %bb_entry = OpLabel
+ %73 = OpExtInst %void %1 DebugScope %56
+ %ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
+ %c = OpVariable %_ptr_Function_v4float Function
+ %74 = OpExtInst %void %1 DebugValue %63 %c %61
+ OpLine %6 18 9
+ %75 = OpAccessChain %_ptr_Function_v4float %i %int_0
+ OpLine %6 18 13
+ %76 = OpLoad %v4float %75
+ OpLine %6 18 5
+ OpStore %c %76
+;CHECK: OpStore %c %76
+ OpLine %6 19 10
+ %77 = OpAccessChain %_ptr_Function_v4float %i %int_1
+ OpLine %6 19 14
+ %78 = OpLoad %v4float %77
+ OpLine %6 19 5
+ %79 = OpLoad %v4float %c
+;CHECK-NOT: OpLine %6 19 5
+;CHECK-NOT: %79 = OpLoad %v4float %c
+ OpLine %6 19 7
+ %80 = OpFAdd %v4float %79 %78
+;CHECK-NOT: %80 = OpFAdd %v4float %79 %78
+;CHECK: %80 = OpFAdd %v4float %76 %78
+ OpLine %6 19 5
+ OpStore %c %80
+;CHECK: OpStore %c %80
+ OpLine %6 20 5
+ %81 = OpLoad %v4float %c
+;CHECK-NOT: OpLine %6 20 5
+;CHECK-NOT: %81 = OpLoad %v4float %c
+ OpLine %6 20 7
+ %82 = OpFDiv %v4float %81 %31
+;CHECK-NOT: %82 = OpFDiv %v4float %81 %31
+;CHECK: %82 = OpFDiv %v4float %80 %31
+ OpLine %6 20 5
+ OpStore %c %82
+;CHECK: OpStore %c %82
+ OpLine %6 22 26
+ %83 = OpLoad %v4float %c
+;CHECK-NOT: OpLine %6 22 26
+;CHECK-NOT: %83 = OpLoad %v4float %c
+ OpLine %6 22 5
+ %84 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
+ OpStore %84 %83
+;CHECK-NOT: OpStore %84 %83
+;CHECK: OpStore %84 %82
+ OpLine %6 23 12
+ %85 = OpLoad %PS_OUTPUT %ps_output
+ OpLine %6 23 5
+ OpReturnValue %85
+ %86 = OpExtInst %void %1 DebugNoScope
+ OpFunctionEnd
+ )";
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<LocalSingleBlockLoadStoreElimPass>(text, false);
+}
+
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// Other target variable types