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:
Jaebaek Seo 2020-07-27 09:27:47 -04:00 committed by GitHub
parent 767518e8e1
commit 7c901a49c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 10 deletions

View File

@ -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;
}

View File

@ -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_; }

View File

@ -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;
}
}

View File

@ -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

View File

@ -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