Handle execution termination instructions when building edges.
authorDiego Novillo <dnovillo@google.com>
Wed, 3 Jan 2018 20:25:03 +0000 (15:25 -0500)
committerDiego Novillo <dnovillo@google.com>
Wed, 3 Jan 2018 20:25:03 +0000 (15:25 -0500)
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.

source/opcode.cpp
source/opcode.h
source/opt/basic_block.h
source/opt/instruction.h
source/opt/propagator.cpp
test/opt/ccp_test.cpp

index c76f1b4..cacb005 100644 (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) {
index 6c73178..c56b0cf 100644 (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);
 
index 8498ec0..751b3a2 100644 (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_;
index 3c5d027..913695b 100644 (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;
index 0ac1310..10b3a31 100644 (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(
index aa7aada..ecec49d 100644 (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