Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Workaround AccessChain function arguments for DebugDeclare #5275

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions source/opt/inline_exhaustive_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,97 @@

namespace spvtools {
namespace opt {
namespace {
// Indices of operands in SPIR-V instructions
constexpr int kSpvFunctionCallArgumentId = 3;
} // namespace

Pass::Status InlineExhaustivePass::PassAccessChainByVariable(Function* func, BasicBlock::iterator call_inst_itr) {
Pass::Status status = Pass::Status::SuccessWithoutChange;

// Iterate over the function arguments.
for(uint32_t arg_idx = kSpvFunctionCallArgumentId; arg_idx < call_inst_itr->NumOperands(); ++arg_idx) {
uint32_t arg_id = call_inst_itr->GetSingleWordOperand(arg_idx);
// Look for function arguments that are access chains.
auto arg_inst = get_def_use_mgr()->GetDef(arg_id);
if(arg_inst->opcode() == spv::Op::OpAccessChain) {
// Create a new variable.
auto var_result_id = TakeNextId();
std::unique_ptr<Instruction> var_inst(new Instruction(
context(), spv::Op::OpVariable, arg_inst->type_id(), var_result_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
{(uint32_t)spv::StorageClass::Function}}}));

// Update the def/use of the instruction and set its basic block.
context()->AnalyzeDefUse(&*var_inst);
auto basic_block = &*func->begin();
context()->set_instr_block(&*var_inst, basic_block);

// Insert the variable at the head of the first block.
func->begin()->begin().InsertBefore(std::move(var_inst));

// Insert instructions to copy the access chain pointee into the variable before the function call.
auto type_mgr = context()->get_type_mgr();
auto pointee_type_id = type_mgr->GetId(type_mgr->GetType(arg_inst->type_id())->AsPointer()->pointee_type());
auto load_result_id = TakeNextId();
auto debug_line_inst = call_inst_itr->dbg_line_inst();
auto debug_scope = call_inst_itr->GetDebugScope();
auto load_ac_inst = MakeLoad(pointee_type_id, load_result_id, arg_id,
debug_line_inst, debug_scope, basic_block);
call_inst_itr->InsertBefore(std::move(load_ac_inst));

auto store_var_inst = MakeStore(var_result_id, load_result_id, debug_line_inst,
debug_scope, basic_block);
call_inst_itr->InsertBefore(std::move(store_var_inst));

// Substitute the variable into the function call argument.
call_inst_itr->SetOperand(arg_idx, {var_result_id});

// Insert instructions to copy the variable back into the access chain pointee after the function call.
load_result_id = TakeNextId();
auto insert_iter = call_inst_itr->NextNode();
auto load_var_inst = MakeLoad(arg_inst->type_id(), load_result_id, var_result_id,
debug_line_inst, debug_scope, basic_block);
insert_iter->InsertBefore(std::move(load_var_inst));

auto store_ac_inst = MakeStore(arg_id, load_result_id, debug_line_inst,
debug_scope, basic_block);
insert_iter->InsertBefore(std::move(store_ac_inst));

status = Pass::Status::SuccessWithChange;
}
}

return status;
}

std::unique_ptr<Instruction> InlineExhaustivePass::MakeLoad(uint32_t result_type_id,
uint32_t result_id, uint32_t pointer_id, Instruction const* debug_line_inst,
DebugScope const& debug_scope, BasicBlock* basic_block) {
std::unique_ptr<Instruction> load_inst(
new Instruction(context(), spv::Op::OpLoad, result_type_id, result_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {pointer_id}}}));
load_inst->AddDebugLine(debug_line_inst);
load_inst->SetDebugScope(debug_scope);
context()->AnalyzeDefUse(&*load_inst);
context()->set_instr_block(&*load_inst, basic_block);

return load_inst;
}

std::unique_ptr<Instruction> InlineExhaustivePass::MakeStore(uint32_t pointer_id, uint32_t object_id,
Instruction const* debug_line_inst, DebugScope const& debug_scope, BasicBlock* basic_block) {
std::unique_ptr<Instruction> store_inst(
new Instruction(context(), spv::Op::OpStore, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {pointer_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {object_id}}}));
store_inst->AddDebugLine(debug_line_inst);
store_inst->SetDebugScope(debug_scope);
context()->AnalyzeDefUse(&*store_inst);
context()->set_instr_block(&*store_inst, basic_block);

return store_inst;
}

Pass::Status InlineExhaustivePass::InlineExhaustive(Function* func) {
bool modified = false;
Expand Down Expand Up @@ -58,8 +149,33 @@ Pass::Status InlineExhaustivePass::InlineExhaustive(Function* func) {
return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
}

Pass::Status InlineExhaustivePass::FindAndReplaceAccessChains(Function* func) {
Pass::Status status = Pass::Status::SuccessWithoutChange;

for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
if (IsInlinableFunctionCall(&*ii)) {
status = CombineStatus(status, PassAccessChainByVariable(func, ii));
}
}
}

return status;
}

Pass::Status InlineExhaustivePass::ProcessImpl() {
Status status = Status::SuccessWithoutChange;

// Substitute variables for access chain function agruments.
if (get_feature_mgr()->HasExtension(kSPV_KHR_non_semantic_info) &&
get_module()->GetExtInstImportId("NonSemantic.Shader.DebugInfo.100") != 0) {
ProcessFunction pfn = [&status, this](Function* fp) {
status = CombineStatus(status, FindAndReplaceAccessChains(fp));
return false;
};
context()->ProcessReachableCallTree(pfn);
}

// Attempt exhaustive inlining on each entry point function in module
ProcessFunction pfn = [&status, this](Function* fp) {
status = CombineStatus(status, InlineExhaustive(fp));
Expand Down
23 changes: 23 additions & 0 deletions source/opt/inline_exhaustive_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,34 @@ class InlineExhaustivePass : public InlinePass {

const char* name() const override { return "inline-entry-points-exhaustive"; }

protected:
// Substitute a variable for an access chain function argument. See FindAndReplaceAccessChains.
Pass::Status PassAccessChainByVariable(Function* func, BasicBlock::iterator call_inst_itr);

// Make a load instruction;
std::unique_ptr<Instruction> MakeLoad(uint32_t result_type_id, uint32_t result_id,
uint32_t pointer_id, Instruction const* debug_line_inst, DebugScope const& debug_scope,
BasicBlock* basic_block);

std::unique_ptr<Instruction> MakeStore(uint32_t pointer_id, uint32_t object_id,
Instruction const* debug_line_inst, DebugScope const& debug_scope, BasicBlock* basic_block);

private:
// Exhaustively inline all function calls in func as well as in
// all code that is inlined into func. Returns the status.
Status InlineExhaustive(Function* func);

// Substitute variables for access chain function arguments. For each function argument
// that is an access chain, create a new variable, copy the access chain pointee into the
// variable before the function call, substitute the variable in the function call,
// and copy the variable back into the access chain pointee after the function call.
//
// This is a workaround for NonSemantic.Shader.DebugInfo.100. DebugDeclare expects the
// operand variable to be a result id of an OpVariable or OpFunctionParameter. However,
// function arguments may contain OpAccessChains during legalization which causes problems
// for DebugDeclare.
Pass::Status FindAndReplaceAccessChains(Function* func);

void Initialize();
Pass::Status ProcessImpl();
};
Expand Down
2 changes: 1 addition & 1 deletion source/opt/inline_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ bool InlinePass::GenInlineCode(
return true;
});

// Inline DebugClare instructions in the callee's header.
// Inline DebugDeclare instructions in the callee's header.
calleeFn->ForEachDebugInstructionsInHeader(
[&new_blk_ptr, &callee2caller, &inlined_at_ctx, this](Instruction* inst) {
InlineSingleInstruction(
Expand Down