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.
}
}
+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) {
// 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);
// 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_;
// 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;
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(
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