mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-22 19:50:05 +00:00
Preserve OpenCL.DebugInfo.100 through private-to-local pass (#3571)
A debug instruction must not have any impact on the private-to-local optimization.
This commit is contained in:
parent
767518e8e1
commit
7c901a49c9
@ -36,7 +36,9 @@ static const uint32_t kDebugValueOperandExpressionIndex = 6;
|
||||
static const uint32_t kDebugOperationOperandOperationIndex = 4;
|
||||
static const uint32_t kOpVariableOperandStorageClassIndex = 2;
|
||||
static const uint32_t kDebugLocalVariableOperandParentIndex = 9;
|
||||
static const uint32_t kDebugOperationOperandOpCodeIndex = 4;
|
||||
static const uint32_t kExtInstInstructionInIdx = 1;
|
||||
static const uint32_t kDebugGlobalVariableOperandFlagsIndex = 12;
|
||||
static const uint32_t kDebugLocalVariableOperandFlagsIndex = 10;
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
@ -556,7 +558,7 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
|
||||
|
||||
if (deref_operation_ == nullptr &&
|
||||
dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation &&
|
||||
dbg_inst->GetSingleWordOperand(kDebugOperationOperandOpCodeIndex) ==
|
||||
dbg_inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex) ==
|
||||
OpenCLDebugInfo100Deref) {
|
||||
deref_operation_ = dbg_inst;
|
||||
}
|
||||
@ -581,6 +583,56 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
|
||||
}
|
||||
}
|
||||
|
||||
void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
|
||||
Instruction* dbg_global_var, Instruction* local_var) {
|
||||
if (dbg_global_var->GetOpenCL100DebugOpcode() !=
|
||||
OpenCLDebugInfo100DebugGlobalVariable) {
|
||||
return;
|
||||
}
|
||||
assert(local_var->opcode() == SpvOpVariable ||
|
||||
local_var->opcode() == SpvOpFunctionParameter);
|
||||
|
||||
// Convert |dbg_global_var| to DebugLocalVariable
|
||||
dbg_global_var->SetInOperand(kExtInstInstructionInIdx,
|
||||
{OpenCLDebugInfo100DebugLocalVariable});
|
||||
auto flags = dbg_global_var->GetSingleWordOperand(
|
||||
kDebugGlobalVariableOperandFlagsIndex);
|
||||
for (uint32_t i = dbg_global_var->NumInOperands() - 1;
|
||||
i >= kDebugLocalVariableOperandFlagsIndex; --i) {
|
||||
dbg_global_var->RemoveOperand(i);
|
||||
}
|
||||
dbg_global_var->SetOperand(kDebugLocalVariableOperandFlagsIndex, {flags});
|
||||
context()->ForgetUses(dbg_global_var);
|
||||
context()->AnalyzeUses(dbg_global_var);
|
||||
|
||||
// Create a DebugDeclare
|
||||
std::unique_ptr<Instruction> new_dbg_decl(new Instruction(
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
context()->TakeNextId(),
|
||||
{
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugDeclare)}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{dbg_global_var->result_id()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {local_var->result_id()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{GetEmptyDebugExpression()->result_id()}},
|
||||
}));
|
||||
auto* added_dbg_decl =
|
||||
local_var->NextNode()->InsertBefore(std::move(new_dbg_decl));
|
||||
if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
|
||||
context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_decl);
|
||||
if (context()->AreAnalysesValid(
|
||||
IRContext::Analysis::kAnalysisInstrToBlockMapping)) {
|
||||
auto insert_blk = context()->get_instr_block(local_var);
|
||||
context()->set_instr_block(added_dbg_decl, insert_blk);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
|
||||
deref_operation_ = nullptr;
|
||||
debug_info_none_inst_ = nullptr;
|
||||
@ -638,7 +690,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
dbg_instr_itr->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugOperation &&
|
||||
dbg_instr_itr->GetSingleWordOperand(
|
||||
kDebugOperationOperandOpCodeIndex) == OpenCLDebugInfo100Deref) {
|
||||
kDebugOperationOperandOperationIndex) ==
|
||||
OpenCLDebugInfo100Deref) {
|
||||
deref_operation_ = &*dbg_instr_itr;
|
||||
break;
|
||||
}
|
||||
|
@ -153,6 +153,11 @@ class DebugInfoManager {
|
||||
// Function storage class. Otherwise, returns 0.
|
||||
uint32_t GetVariableIdOfDebugValueUsedForDeclare(Instruction* inst);
|
||||
|
||||
// Converts DebugGlobalVariable |dbg_global_var| to a DebugLocalVariable and
|
||||
// creates a DebugDeclare mapping the new DebugLocalVariable to |local_var|.
|
||||
void ConvertDebugGlobalToLocalVariable(Instruction* dbg_global_var,
|
||||
Instruction* local_var);
|
||||
|
||||
private:
|
||||
IRContext* context() { return context_; }
|
||||
|
||||
|
@ -138,7 +138,7 @@ bool PrivateToLocalPass::MoveVariable(Instruction* variable,
|
||||
function->begin()->begin()->InsertBefore(move(var));
|
||||
|
||||
// Update uses where the type may have changed.
|
||||
return UpdateUses(variable->result_id());
|
||||
return UpdateUses(variable);
|
||||
}
|
||||
|
||||
uint32_t PrivateToLocalPass::GetNewType(uint32_t old_type_id) {
|
||||
@ -157,6 +157,10 @@ uint32_t PrivateToLocalPass::GetNewType(uint32_t old_type_id) {
|
||||
bool PrivateToLocalPass::IsValidUse(const Instruction* inst) const {
|
||||
// The cases in this switch have to match the cases in |UpdateUse|.
|
||||
// If we don't know how to update it, it is not valid.
|
||||
if (inst->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugGlobalVariable) {
|
||||
return true;
|
||||
}
|
||||
switch (inst->opcode()) {
|
||||
case SpvOpLoad:
|
||||
case SpvOpStore:
|
||||
@ -175,10 +179,16 @@ bool PrivateToLocalPass::IsValidUse(const Instruction* inst) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool PrivateToLocalPass::UpdateUse(Instruction* inst) {
|
||||
bool PrivateToLocalPass::UpdateUse(Instruction* inst, Instruction* user) {
|
||||
// The cases in this switch have to match the cases in |IsValidUse|. If we
|
||||
// don't think it is valid, the optimization will not view the variable as a
|
||||
// candidate, and therefore the use will not be updated.
|
||||
if (inst->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugGlobalVariable) {
|
||||
context()->get_debug_info_mgr()->ConvertDebugGlobalToLocalVariable(inst,
|
||||
user);
|
||||
return true;
|
||||
}
|
||||
switch (inst->opcode()) {
|
||||
case SpvOpLoad:
|
||||
case SpvOpStore:
|
||||
@ -196,7 +206,7 @@ bool PrivateToLocalPass::UpdateUse(Instruction* inst) {
|
||||
context()->AnalyzeUses(inst);
|
||||
|
||||
// Update uses where the type may have changed.
|
||||
if (!UpdateUses(inst->result_id())) {
|
||||
if (!UpdateUses(inst)) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
@ -211,13 +221,14 @@ bool PrivateToLocalPass::UpdateUse(Instruction* inst) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PrivateToLocalPass::UpdateUses(uint32_t id) {
|
||||
bool PrivateToLocalPass::UpdateUses(Instruction* inst) {
|
||||
uint32_t id = inst->result_id();
|
||||
std::vector<Instruction*> uses;
|
||||
context()->get_def_use_mgr()->ForEachUser(
|
||||
id, [&uses](Instruction* use) { uses.push_back(use); });
|
||||
|
||||
for (Instruction* use : uses) {
|
||||
if (!UpdateUse(use)) {
|
||||
if (!UpdateUse(use, inst)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ class PrivateToLocalPass : public Pass {
|
||||
|
||||
// Updates |inst|, and any instruction dependent on |inst|, to reflect the
|
||||
// change of the base pointer now pointing to the function storage class.
|
||||
bool UpdateUse(Instruction* inst);
|
||||
bool UpdateUses(uint32_t id);
|
||||
bool UpdateUse(Instruction* inst, Instruction* user);
|
||||
bool UpdateUses(Instruction* inst);
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
|
@ -452,6 +452,50 @@ TEST_F(PrivateToLocalTest, IdBoundOverflow1) {
|
||||
EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(PrivateToLocalTest, DebugPrivateToLocal) {
|
||||
// Debug instructions must not have any impact on changing the private
|
||||
// variable to a local.
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
%10 = OpExtInstImport "OpenCL.DebugInfo.100"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
%11 = OpString "test"
|
||||
OpSource GLSL 430
|
||||
%13 = OpTypeInt 32 0
|
||||
%14 = OpConstant %13 32
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeFunction %3
|
||||
; CHECK: [[float:%[a-zA-Z_\d]+]] = OpTypeFloat 32
|
||||
%5 = OpTypeFloat 32
|
||||
; CHECK: [[newtype:%[a-zA-Z_\d]+]] = OpTypePointer Function [[float]]
|
||||
%6 = OpTypePointer Private %5
|
||||
; CHECK-NOT: OpVariable [[.+]] Private
|
||||
%8 = OpVariable %6 Private
|
||||
|
||||
%12 = OpExtInst %3 %10 DebugTypeBasic %11 %14 Float
|
||||
%15 = OpExtInst %3 %10 DebugSource %11
|
||||
%16 = OpExtInst %3 %10 DebugCompilationUnit 1 4 %15 GLSL
|
||||
; CHECK-NOT: DebugGlobalVariable
|
||||
; CHECK: [[dbg_newvar:%[a-zA-Z_\d]+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLocalVariable
|
||||
%17 = OpExtInst %3 %10 DebugGlobalVariable %11 %12 %15 0 0 %16 %11 %8 FlagIsDefinition
|
||||
|
||||
; CHECK: OpFunction
|
||||
%2 = OpFunction %3 None %4
|
||||
; CHECK: OpLabel
|
||||
%7 = OpLabel
|
||||
; CHECK-NEXT: [[newvar:%[a-zA-Z_\d]+]] = OpVariable [[newtype]] Function
|
||||
; CHECK-NEXT: DebugDeclare [[dbg_newvar]] [[newvar]]
|
||||
; CHECK: OpLoad [[float]] [[newvar]]
|
||||
%9 = OpLoad %5 %8
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
SinglePassRunAndMatch<PrivateToLocalPass>(text, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
Loading…
Reference in New Issue
Block a user