Fix OpLine bug of merge-blocks pass (#3130)

As explained in #3118, spirv-opt merge-blocks pass causes a
spirv-val error when an OpBranch has an OpLine in front of it.

OpLoopMerge
OpBranch ; Will be killed by merge-blocks pass
OpLabel  ; Will be killed by merge-blocks pass
OpLine   ; will be placed between OpLoopMerge and OpBranch - error!
OpBranch

To fix this issue, this commit moves line info of OpBranch to
OpLoopMerge.

Fixes #3118
This commit is contained in:
Jaebaek Seo 2020-01-14 14:35:21 -05:00 committed by GitHub
parent 8013d477ae
commit f8d7df760c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 1 deletions

View File

@ -171,8 +171,17 @@ void MergeWithSuccessor(IRContext* context, Function* func,
// flow declaration.
context->KillInst(merge_inst);
} else {
// Move OpLine/OpNoLine information to merge_inst. This solves
// the validation error that OpLine is placed between OpLoopMerge
// and OpBranchConditional.
auto terminator = bi->terminator();
auto& vec = terminator->dbg_line_insts();
auto& new_vec = merge_inst->dbg_line_insts();
new_vec.insert(new_vec.end(), vec.begin(), vec.end());
terminator->clear_dbg_line_insts();
// Move the merge instruction to just before the terminator.
merge_inst->InsertBefore(bi->terminator());
merge_inst->InsertBefore(terminator);
}
}
context->ReplaceAllUsesWith(lab_id, bi->id());

View File

@ -172,6 +172,9 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
return dbg_line_insts_;
}
// Clear line-related debug instructions attached to this instruction.
void clear_dbg_line_insts() { dbg_line_insts_.clear(); }
// Same semantics as in the base class except the list the InstructionList
// containing |pos| will now assume ownership of |this|.
// inline void MoveBefore(Instruction* pos);

View File

@ -423,6 +423,42 @@ OpFunctionEnd
SinglePassRunAndMatch<BlockMergePass>(text, true);
}
TEST_F(BlockMergeTest, MergeContinueWithOpLine) {
const std::string text = R"(
; CHECK: OpBranch [[header:%\w+]]
; CHECK: [[header]] = OpLabel
; CHECK-NEXT: OpLogicalAnd
; CHECK-NEXT: OpLine {{%\w+}} 1 1
; CHECK-NEXT: OpLoopMerge {{%\w+}} [[header]] None
; CHECK-NEXT: OpBranch [[header]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%src = OpString "test.shader"
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
%false = OpConstantFalse %bool
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%entry = OpLabel
OpBranch %header
%header = OpLabel
OpLoopMerge %merge %continue None
OpBranch %continue
%continue = OpLabel
%op = OpLogicalAnd %bool %true %false
OpLine %src 1 1
OpBranch %header
%merge = OpLabel
OpUnreachable
OpFunctionEnd
)";
SinglePassRunAndMatch<BlockMergePass>(text, true);
}
TEST_F(BlockMergeTest, TwoHeadersCannotBeMerged) {
const std::string text = R"(
; CHECK: OpBranch [[loop_header:%\w+]]