[llvm] [InstCombine] If inst in unreachable refers to an inst change it to poison (#65107) (PR #78444)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 30 09:58:07 PST 2024


https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/78444

>From a092ee44024841825089a8e7523c1272863c74fe Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Sat, 20 Jan 2024 04:22:57 +0900
Subject: [PATCH] [InstCombine] If Inst in unreachable refers to Inst change it
 to poison (#65107)

Instructions in unreachable basic blocks are removed, but terminators
are not. In this case, even instructions that are only referenced by
a terminator, such as a return instruction, cannot be processed
properly.

This patch changes the operand of terminator instruction in an
unreachable basic block to poison if it refers to the instruction,
allowing the instruction to be properly processed.
---
 llvm/include/llvm/Transforms/Utils/Local.h    |   4 +
 .../InstCombine/InstructionCombining.cpp      |   5 +-
 llvm/lib/Transforms/Utils/Local.cpp           |  20 ++-
 .../InstCombine/phi-select-constant.ll        |   3 +-
 llvm/test/Transforms/InstCombine/pr63791.ll   |   2 +-
 .../InstCombine/sink_to_unreachable.ll        | 138 ++++++++++++++++++
 6 files changed, 164 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h
index 2df3c9049c7d6..20deee8c29b4f 100644
--- a/llvm/include/llvm/Transforms/Utils/Local.h
+++ b/llvm/include/llvm/Transforms/Utils/Local.h
@@ -357,6 +357,10 @@ Value *salvageDebugInfoImpl(Instruction &I, uint64_t CurrentLocOps,
 bool replaceAllDbgUsesWith(Instruction &From, Value &To, Instruction &DomPoint,
                            DominatorTree &DT);
 
+/// if the terminator in an unreachable basic block refers to an instruction
+/// transform it to poison.
+void handleUnreachableTerminator(Instruction *I);
+
 /// Remove all instructions from a basic block other than its terminator
 /// and any present EH pad instructions. Returns a pair where the first element
 /// is the number of instructions (excluding debug info intrinsics) that have
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 7f2018b3a1995..3bf1a510ae69c 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3100,9 +3100,8 @@ void InstCombinerImpl::handleUnreachableFrom(
     MadeIRChange = true;
   }
 
-  // RemoveDIs: to match behaviour in dbg.value mode, drop debug-info on
-  // terminator too.
-  BB->getTerminator()->dropDbgValues();
+  // if terminator refer instruction, transform it into poison.
+  handleUnreachableTerminator(BB->getTerminator());
 
   // Handle potentially dead successors.
   for (BasicBlock *Succ : successors(BB))
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index c76cc9db16d7e..44385df59c84c 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -2770,6 +2770,20 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To,
   return false;
 }
 
+void llvm::handleUnreachableTerminator(Instruction *I) {
+  // RemoveDIs: erase debug-info on this instruction manually.
+  I->dropDbgValues();
+  unsigned Opcode = I->getOpcode();
+  if (Opcode >= Instruction::Ret && Opcode <= Instruction::Invoke &&
+      I->getNumOperands() > 0) {
+    unsigned OpNum = isa<InvokeInst>(I) ? I->getNumOperands() - 1 : 0;
+    Value *Op = I->getOperand(OpNum);
+    if (Op == nullptr || !isa<Instruction>(Op) || isa<Constant>(Op))
+      return;
+    I->setOperand(OpNum, PoisonValue::get(Op->getType()));
+  }
+}
+
 std::pair<unsigned, unsigned>
 llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) {
   unsigned NumDeadInst = 0;
@@ -2777,8 +2791,10 @@ llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) {
   // Delete the instructions backwards, as it has a reduced likelihood of
   // having to update as many def-use and use-def chains.
   Instruction *EndInst = BB->getTerminator(); // Last not to be deleted.
-  // RemoveDIs: erasing debug-info must be done manually.
-  EndInst->dropDbgValues();
+
+  // if terminator refer instruction, transform it into poison.
+  handleUnreachableTerminator(EndInst);
+
   while (EndInst != &BB->front()) {
     // Delete the next to last instruction.
     Instruction *Inst = &*--EndInst->getIterator();
diff --git a/llvm/test/Transforms/InstCombine/phi-select-constant.ll b/llvm/test/Transforms/InstCombine/phi-select-constant.ll
index 1260ef47f65ef..601a3d208a084 100644
--- a/llvm/test/Transforms/InstCombine/phi-select-constant.ll
+++ b/llvm/test/Transforms/InstCombine/phi-select-constant.ll
@@ -140,12 +140,11 @@ end:
 define i16 @sink_to_unreachable_crash(i1 %a)  {
 ; CHECK-LABEL: @sink_to_unreachable_crash(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[A:%.*]], i16 0, i16 5
 ; CHECK-NEXT:    br label [[INF_LOOP:%.*]]
 ; CHECK:       inf_loop:
 ; CHECK-NEXT:    br label [[INF_LOOP]]
 ; CHECK:       unreachable:
-; CHECK-NEXT:    ret i16 [[S]]
+; CHECK-NEXT:    ret i16 poison
 ;
 entry:
   %s = select i1 %a, i16 0, i16 5
diff --git a/llvm/test/Transforms/InstCombine/pr63791.ll b/llvm/test/Transforms/InstCombine/pr63791.ll
index a489b2e3e6221..78cc1130fb33f 100644
--- a/llvm/test/Transforms/InstCombine/pr63791.ll
+++ b/llvm/test/Transforms/InstCombine/pr63791.ll
@@ -17,7 +17,7 @@ define void @y() {
 ; CHECK:       for.cond5.preheader.i:
 ; CHECK-NEXT:    br i1 false, label [[FOR_INC19_I:%.*]], label [[FOR_COND1_LOOPEXIT_I:%.*]]
 ; CHECK:       for.inc19.i:
-; CHECK-NEXT:    br i1 false, label [[FOR_INC19_I]], label [[FOR_COND1_LOOPEXIT_I]]
+; CHECK-NEXT:    br i1 poison, label [[FOR_INC19_I]], label [[FOR_COND1_LOOPEXIT_I]]
 ;
 entry:
   br label %for.cond.i
diff --git a/llvm/test/Transforms/InstCombine/sink_to_unreachable.ll b/llvm/test/Transforms/InstCombine/sink_to_unreachable.ll
index e788b634da886..af2acd2d3d264 100644
--- a/llvm/test/Transforms/InstCombine/sink_to_unreachable.ll
+++ b/llvm/test/Transforms/InstCombine/sink_to_unreachable.ll
@@ -157,3 +157,141 @@ bb3:
   %p = phi i32 [0, %bb1], [%a, %bb2]
   ret i32 %p
 }
+
+define i1 @sink_to_unreachable_ret(i16 %X)  {
+; CHECK-LABEL: @sink_to_unreachable_ret(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
+; CHECK:       unreach:
+; CHECK-NEXT:    ret i1 poison
+;
+entry:
+  br label %loop
+
+loop:
+  %p = icmp sgt i16 %X, 16
+  br i1 true, label %loop, label %unreach
+
+unreach:
+  ret i1 %p
+}
+
+define void @sink_to_unreachable_condbr(i16 %X)  {
+; CHECK-LABEL: @sink_to_unreachable_condbr(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
+; CHECK:       unreach:
+; CHECK-NEXT:    br i1 poison, label [[DUMMY:%.*]], label [[LOOP]]
+; CHECK:       dummy:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  br label %loop
+
+loop:
+  %p = icmp sgt i16 %X, 16
+  br i1 true, label %loop, label %unreach
+
+unreach:
+  br i1 %p, label %dummy, label %loop
+
+dummy:
+  unreachable
+}
+
+define void @sink_to_unreachable_switch(i16 %X)  {
+; CHECK-LABEL: @sink_to_unreachable_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
+; CHECK:       unreach:
+; CHECK-NEXT:    switch i16 poison, label [[UNREACH_RET:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       unreach.ret:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  br label %loop
+
+loop:
+  %quantum = srem i16 %X, 32
+  br i1 true, label %loop, label %unreach
+
+unreach:
+  switch i16 %quantum, label %unreach.ret []
+
+unreach.ret:
+  unreachable
+}
+
+define void @sink_to_unreachable_indirectbr(ptr %Ptr)  {
+; CHECK-LABEL: @sink_to_unreachable_indirectbr(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
+; CHECK:       unreach:
+; CHECK-NEXT:    indirectbr ptr poison, [label %loop]
+;
+entry:
+  br label %loop
+
+loop:
+  %gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
+  br i1 true, label %loop, label %unreach
+
+unreach:
+  indirectbr ptr %gep, [label %loop]
+}
+
+define void @sink_to_unreachable_invoke(ptr %Ptr) personality ptr @__CxxFrameHandler3 {
+; CHECK-LABEL: @sink_to_unreachable_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
+; CHECK:       unreach:
+; CHECK-NEXT:    invoke void poison(i1 false)
+; CHECK-NEXT:            to label [[DUMMY:%.*]] unwind label [[ICATCH_DISPATCH:%.*]]
+; CHECK:       icatch.dispatch:
+; CHECK-NEXT:    [[TMP1:%.*]] = catchswitch within none [label %icatch] unwind to caller
+; CHECK:       icatch:
+; CHECK-NEXT:    [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 64, ptr null]
+; CHECK-NEXT:    catchret from [[TMP2]] to label [[DUMMY2:%.*]]
+; CHECK:       dummy:
+; CHECK-NEXT:    ret void
+; CHECK:       dummy2:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
+  br i1 true, label %loop, label %unreach
+
+unreach:
+  invoke void %gep(i1 false)
+  to label %dummy unwind label %icatch.dispatch
+
+icatch.dispatch:
+  %tmp1 = catchswitch within none [label %icatch] unwind to caller
+
+icatch:
+  %tmp2 = catchpad within %tmp1 [ptr null, i32 64, ptr null]
+  catchret from %tmp2 to label %dummy2
+
+dummy:
+  ret void
+
+dummy2:
+  ret void
+}
+
+declare void @may_throw()
+declare i32 @__CxxFrameHandler3(...)



More information about the llvm-commits mailing list