From: Diego Novillo Date: Wed, 3 Jan 2018 20:25:03 +0000 (-0500) Subject: Handle execution termination instructions when building edges. X-Git-Tag: upstream/2018.6~591 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5f100789fb8dc220626996ad8afb160ccb602691;p=platform%2Fupstream%2FSPIRV-Tools.git 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. --- diff --git a/source/opcode.cpp b/source/opcode.cpp index c76f1b4..cacb005 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -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) { diff --git a/source/opcode.h b/source/opcode.h index 6c73178..c56b0cf 100644 --- a/source/opcode.h +++ b/source/opcode.h @@ -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); diff --git a/source/opt/basic_block.h b/source/opt/basic_block.h index 8498ec0..751b3a2 100644 --- a/source/opt/basic_block.h +++ b/source/opt/basic_block.h @@ -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_; diff --git a/source/opt/instruction.h b/source/opt/instruction.h index 3c5d027..913695b 100644 --- a/source/opt/instruction.h +++ b/source/opt/instruction.h @@ -317,6 +317,9 @@ class Instruction : public utils::IntrusiveNodeBase { // 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; diff --git a/source/opt/propagator.cpp b/source/opt/propagator.cpp index 0ac1310..10b3a31 100644 --- a/source/opt/propagator.cpp +++ b/source/opt/propagator.cpp @@ -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( diff --git a/test/opt/ccp_test.cpp b/test/opt/ccp_test.cpp index aa7aada..ecec49d 100644 --- a/test/opt/ccp_test.cpp +++ b/test/opt/ccp_test.cpp @@ -381,6 +381,40 @@ TEST_F(CCPTest, NoLoadStorePropagation) { SinglePassRunAndMatch(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(spv_asm, true); +} + #endif } // namespace