Handle execution termination instructions when building edges.

This fixes issue https://github.com/KhronosGroup/SPIRV-Tools/issues/1153.

When building CFG edges, edges out of a OpKill and OpUnreachable
instruction should be directed to the CFG's pseudo exit block.
This commit is contained in:
Diego Novillo 2018-01-03 15:25:03 -05:00
parent 135150a1a8
commit 5f100789fb
6 changed files with 51 additions and 3 deletions

View File

@ -413,9 +413,13 @@ bool spvOpcodeIsReturn(SpvOp opcode) {
}
}
bool spvOpcodeIsReturnOrAbort(SpvOp opcode) {
return spvOpcodeIsReturn(opcode) || opcode == SpvOpKill ||
opcode == SpvOpUnreachable;
}
bool spvOpcodeIsBlockTerminator(SpvOp opcode) {
return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturn(opcode) ||
opcode == SpvOpKill || opcode == SpvOpUnreachable;
return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
}
bool spvOpcodeIsBaseOpaqueType(SpvOp opcode) {

View File

@ -103,6 +103,10 @@ bool spvOpcodeIsBranch(SpvOp opcode);
// Returns true if the given opcode is a return instruction.
bool spvOpcodeIsReturn(SpvOp opcode);
// Returns true if the given opcode is a return instruction or it aborts
// execution.
bool spvOpcodeIsReturnOrAbort(SpvOp opcode);
// Returns true if the given opcode is a basic block terminator.
bool spvOpcodeIsBlockTerminator(SpvOp opcode);

View File

@ -147,6 +147,9 @@ class BasicBlock {
// caller.
bool IsReturn() const { return ctail()->IsReturn(); }
// Returns true if this basic block exits this function or aborts execution.
bool IsReturnOrAbort() const { return ctail()->IsReturnOrAbort(); }
private:
// The enclosing function.
Function* function_;

View File

@ -317,6 +317,9 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
// and return to its caller
bool IsReturn() const { return spvOpcodeIsReturn(opcode()); }
// Returns true if this instruction exits this function or aborts execution.
bool IsReturnOrAbort() const { return spvOpcodeIsReturnOrAbort(opcode()); }
// Returns the id for the |element|'th subtype. If the |this| is not a
// composite type, this function returns 0.
uint32_t GetTypeComponent(uint32_t element) const;

View File

@ -193,7 +193,7 @@ void SSAPropagator::Initialize(ir::Function* fn) {
bb_succs_[&block].push_back(Edge(&block, succ_bb));
bb_preds_[succ_bb].push_back(Edge(succ_bb, &block));
});
if (block.IsReturn()) {
if (block.IsReturnOrAbort()) {
bb_succs_[&block].push_back(
Edge(&block, ctx_->cfg()->pseudo_exit_block()));
bb_preds_[ctx_->cfg()->pseudo_exit_block()].push_back(

View File

@ -381,6 +381,40 @@ TEST_F(CCPTest, NoLoadStorePropagation) {
SinglePassRunAndMatch<opt::CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, HandleAbortInstructions) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%bool = OpTypeBool
; CHECK: %true = OpConstantTrue %bool
%int_3 = OpConstant %int 3
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%4 = OpLabel
%9 = OpIAdd %int %int_3 %int_1
%6 = OpSGreaterThan %bool %9 %int_3
OpSelectionMerge %23 None
; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
OpBranchConditional %6 %22 %23
%22 = OpLabel
OpKill
%23 = OpLabel
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<opt::CCPPass>(spv_asm, true);
}
#endif
} // namespace