Generate constants directly in CreateDebugInlinedAt (#4572)

Do this if Constant or DefUse managers are invalid. Using the
ConstantManager attempts to regenerate the DefUseManager
which is not valid during inlining.
This commit is contained in:
Greg Fischer 2021-10-19 18:27:16 -06:00 committed by GitHub
parent 7a7a69037e
commit 001604bd4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 245 additions and 3 deletions

View File

@ -146,6 +146,25 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
}
}
// Create new constant directly into global value area, bypassing the
// Constant manager. This is used when the DefUse or Constant managers
// are invalid and cannot be regenerated due to the module being in an
// inconsistant state e.g. in the middle of significant modification
// such as inlining. Invalidate Constant and DefUse managers if used.
uint32_t AddNewConstInGlobals(IRContext* context, uint32_t const_value) {
uint32_t id = context->TakeNextId();
std::unique_ptr<Instruction> new_const(new Instruction(
context, SpvOpConstant, context->get_type_mgr()->GetUIntTypeId(), id,
{
{spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
{const_value}},
}));
context->module()->AddGlobalValue(std::move(new_const));
context->InvalidateAnalyses(IRContext::kAnalysisConstants);
context->InvalidateAnalyses(IRContext::kAnalysisDefUse);
return id;
}
uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
const DebugScope& scope) {
uint32_t setId = GetDbgSetImportId();
@ -194,10 +213,18 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex);
// If we need the line number as an ID, generate that constant now.
// If Constant or DefUse managers are invalid, generate constant
// directly into the global value section of the module; do not
// use Constant manager which may attempt to invoke building of the
// DefUse manager which cannot be done during inlining. The extra
// constants that may be generated here is likely not significant
// and will likely be cleaned up in later passes.
if (line_number_type == spv_operand_type_t::SPV_OPERAND_TYPE_ID) {
uint32_t line_id =
context()->get_constant_mgr()->GetUIntConst(line_number);
line_number = line_id;
if (!context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse) ||
!context()->AreAnalysesValid(IRContext::Analysis::kAnalysisConstants))
line_number = AddNewConstInGlobals(context(), line_number);
else
line_number = context()->get_constant_mgr()->GetUIntConst(line_number);
}
}

View File

@ -185,6 +185,122 @@ void main(float in_var_color : COLOR) {
100U);
}
TEST(DebugInfoManager, CreateDebugInlinedAtWithConstantManager) {
// Show that CreateDebugInlinedAt will use the Constant manager to generate
// its line operand if the Constant and DefUse managers are valid. This is
// proven by checking that the id for the line operand 7 is the same as the
// existing constant 7.
//
// int function1() {
// return 1;
// }
//
// void main() {
// function1();
// }
const std::string text = R"(OpCapability Shader
OpExtension "SPV_KHR_non_semantic_info"
%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%3 = OpString "parent3.hlsl"
%8 = OpString "int"
%19 = OpString "function1"
%20 = OpString ""
%26 = OpString "main"
OpName %main "main"
OpName %src_main "src.main"
OpName %bb_entry "bb.entry"
OpName %function1 "function1"
OpName %bb_entry_0 "bb.entry"
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%uint = OpTypeInt 32 0
%uint_32 = OpConstant %uint 32
%void = OpTypeVoid
%uint_4 = OpConstant %uint 4
%uint_0 = OpConstant %uint 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%uint_5 = OpConstant %uint 5
%uint_2 = OpConstant %uint 2
%uint_17 = OpConstant %uint 17
%uint_6 = OpConstant %uint 6
%uint_13 = OpConstant %uint 13
%100 = OpConstant %uint 7
%31 = OpTypeFunction %void
%42 = OpTypeFunction %int
%10 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_4 %uint_0
%13 = OpExtInst %void %1 DebugTypeFunction %uint_3 %10
%15 = OpExtInst %void %1 DebugSource %3
%16 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %15 %uint_5
%21 = OpExtInst %void %1 DebugFunction %19 %13 %15 %uint_2 %uint_1 %16 %20 %uint_3 %uint_2
%23 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_2 %uint_17 %21
%25 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void
%27 = OpExtInst %void %1 DebugFunction %26 %25 %15 %uint_6 %uint_1 %16 %20 %uint_3 %uint_6
%29 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_6 %uint_13 %27
%main = OpFunction %void None %31
%32 = OpLabel
%33 = OpFunctionCall %void %src_main
OpLine %3 8 1
OpReturn
OpFunctionEnd
OpLine %3 6 1
%src_main = OpFunction %void None %31
OpNoLine
%bb_entry = OpLabel
%47 = OpExtInst %void %1 DebugScope %27
%37 = OpExtInst %void %1 DebugFunctionDefinition %27 %src_main
%48 = OpExtInst %void %1 DebugScope %29
OpLine %3 7 3
%39 = OpFunctionCall %int %function1
%49 = OpExtInst %void %1 DebugScope %27
OpLine %3 8 1
OpReturn
%50 = OpExtInst %void %1 DebugNoScope
OpFunctionEnd
OpLine %3 2 1
%function1 = OpFunction %int None %42
OpNoLine
%bb_entry_0 = OpLabel
%51 = OpExtInst %void %1 DebugScope %21
%45 = OpExtInst %void %1 DebugFunctionDefinition %21 %function1
%52 = OpExtInst %void %1 DebugScope %23
OpLine %3 3 3
OpReturnValue %int_1
%53 = OpExtInst %void %1 DebugNoScope
OpFunctionEnd
)";
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
const uint32_t line_number = 7U;
Instruction line(context.get(), SpvOpLine);
line.SetInOperands({
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {5U}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {0U}},
});
DebugScope scope(29U, 0U);
auto db_manager = context.get()->get_debug_info_mgr();
auto du_manager = context.get()->get_def_use_mgr();
auto c_manager = context.get()->get_constant_mgr();
(void)du_manager;
(void)c_manager;
uint32_t inlined_at_id = db_manager->CreateDebugInlinedAt(&line, scope);
auto* inlined_at = db_manager->GetDebugInlinedAt(inlined_at_id);
EXPECT_NE(inlined_at, nullptr);
EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex),
100);
}
TEST(DebugInfoManager, GetDebugInfoNone) {
const std::string text = R"(
OpCapability Shader

View File

@ -4236,6 +4236,105 @@ OpFunctionEnd
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
}
TEST_F(InlineTest, CreateConstantForInlinedAt) {
// This shader causes CreateDebugInlinedAt to generate a constant.
// Using the Constant manager would attempt to build the invalidated
// DefUse manager during inlining which could cause an assert because
// the function is in an inconsistant state. This test verifies that
// CreateDebugInlinedAt detects that the DefUse manager is disabled
// and creates a duplicate constant safely without the Constant manager.
//
// int function1() {
// return 1;
// }
//
// void main() {
// function1();
// }
const std::string text = R"(OpCapability Shader
; CHECK: %uint_7 = OpConstant %uint 7
; CHECK: %uint_7_0 = OpConstant %uint 7
; CHECK: OpExtInst %void %1 DebugInlinedAt %uint_7_0
OpExtension "SPV_KHR_non_semantic_info"
%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%3 = OpString "parent3.hlsl"
%8 = OpString "int"
%19 = OpString "function1"
%20 = OpString ""
%26 = OpString "main"
OpName %main "main"
OpName %src_main "src.main"
OpName %bb_entry "bb.entry"
OpName %function1 "function1"
OpName %bb_entry_0 "bb.entry"
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%uint = OpTypeInt 32 0
%uint_32 = OpConstant %uint 32
%void = OpTypeVoid
%uint_4 = OpConstant %uint 4
%uint_0 = OpConstant %uint 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%uint_5 = OpConstant %uint 5
%uint_2 = OpConstant %uint 2
%uint_17 = OpConstant %uint 17
%uint_6 = OpConstant %uint 6
%uint_13 = OpConstant %uint 13
%uint_7 = OpConstant %uint 7
%31 = OpTypeFunction %void
%42 = OpTypeFunction %int
%10 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_4 %uint_0
%13 = OpExtInst %void %1 DebugTypeFunction %uint_3 %10
%15 = OpExtInst %void %1 DebugSource %3
%16 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %15 %uint_5
%21 = OpExtInst %void %1 DebugFunction %19 %13 %15 %uint_2 %uint_1 %16 %20 %uint_3 %uint_2
%23 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_2 %uint_17 %21
%25 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void
%27 = OpExtInst %void %1 DebugFunction %26 %25 %15 %uint_6 %uint_1 %16 %20 %uint_3 %uint_6
%29 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_6 %uint_13 %27
%main = OpFunction %void None %31
%32 = OpLabel
%33 = OpFunctionCall %void %src_main
OpLine %3 8 1
OpReturn
OpFunctionEnd
OpLine %3 6 1
%src_main = OpFunction %void None %31
OpNoLine
%bb_entry = OpLabel
%47 = OpExtInst %void %1 DebugScope %27
%37 = OpExtInst %void %1 DebugFunctionDefinition %27 %src_main
%48 = OpExtInst %void %1 DebugScope %29
OpLine %3 7 3
%39 = OpFunctionCall %int %function1
%49 = OpExtInst %void %1 DebugScope %27
OpLine %3 8 1
OpReturn
%50 = OpExtInst %void %1 DebugNoScope
OpFunctionEnd
OpLine %3 2 1
%function1 = OpFunction %int None %42
OpNoLine
%bb_entry_0 = OpLabel
%51 = OpExtInst %void %1 DebugScope %21
%45 = OpExtInst %void %1 DebugFunctionDefinition %21 %function1
%52 = OpExtInst %void %1 DebugScope %23
OpLine %3 3 3
OpReturnValue %int_1
%53 = OpExtInst %void %1 DebugNoScope
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_VULKAN_1_2);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// Empty modules