[llvm] 6cdf596 - [InstCombine] If inst in unreachable refers to an inst change it to poison (#78444)

via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 6 00:42:37 PST 2024


Author: hanbeom
Date: 2024-03-06T09:42:33+01:00
New Revision: 6cdf596c52f028ea7d150e0696f967fbff443ccf

URL: https://github.com/llvm/llvm-project/commit/6cdf596c52f028ea7d150e0696f967fbff443ccf
DIFF: https://github.com/llvm/llvm-project/commit/6cdf596c52f028ea7d150e0696f967fbff443ccf.diff

LOG: [InstCombine] If inst in unreachable refers to an inst change it to poison (#78444)

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 a return instruction in an
unreachable basic block to poison if it refers to the instruction,
allowing the instruction to be properly processed.

Fixes #65107.

Added: 
    

Modified: 
    llvm/include/llvm/Transforms/Utils/Local.h
    llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
    llvm/lib/Transforms/Utils/Local.cpp
    llvm/test/Transforms/InstCombine/phi-select-constant.ll
    llvm/test/Transforms/InstCombine/pr63791.ll
    llvm/test/Transforms/InstCombine/sink_to_unreachable.ll
    llvm/test/Transforms/InstCombine/unreachable-code.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h
index 8dc843d2eaf604..cc133628743629 100644
--- a/llvm/include/llvm/Transforms/Utils/Local.h
+++ b/llvm/include/llvm/Transforms/Utils/Local.h
@@ -357,6 +357,13 @@ Value *salvageDebugInfoImpl(Instruction &I, uint64_t CurrentLocOps,
 bool replaceAllDbgUsesWith(Instruction &From, Value &To, Instruction &DomPoint,
                            DominatorTree &DT);
 
+/// If a terminator in an unreachable basic block has an operand of type
+/// Instruction, transform it into poison. Return true if any operands
+/// are changed to poison. Original Values prior to being changed to poison
+/// are returned in \p PoisonedValues.
+bool handleUnreachableTerminator(Instruction *I,
+                                 SmallVectorImpl<Value *> &PoisonedValues);
+
 /// 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 80ce0c9275b2cb..fec33c5ea53b41 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3241,9 +3241,12 @@ void InstCombinerImpl::handleUnreachableFrom(
     MadeIRChange = true;
   }
 
-  // RemoveDIs: to match behaviour in dbg.value mode, drop debug-info on
-  // terminator too.
-  BB->getTerminator()->dropDbgValues();
+  SmallVector<Value *> Changed;
+  if (handleUnreachableTerminator(BB->getTerminator(), Changed)) {
+    MadeIRChange = true;
+    for (Value *V : Changed)
+      addToWorklist(cast<Instruction>(V));
+  }
 
   // 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 c4a8843f2840b3..d3bb89075015e9 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -2762,6 +2762,23 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To,
   return false;
 }
 
+bool llvm::handleUnreachableTerminator(
+    Instruction *I, SmallVectorImpl<Value *> &PoisonedValues) {
+  bool Changed = false;
+  // RemoveDIs: erase debug-info on this instruction manually.
+  I->dropDbgValues();
+  for (Use &U : I->operands()) {
+    Value *Op = U.get();
+    if (isa<Instruction>(Op) && !Op->getType()->isTokenTy()) {
+      U.set(PoisonValue::get(Op->getType()));
+      PoisonedValues.push_back(Op);
+      Changed = true;
+    }
+  }
+
+  return Changed;
+}
+
 std::pair<unsigned, unsigned>
 llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) {
   unsigned NumDeadInst = 0;
@@ -2769,8 +2786,9 @@ 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();
+  SmallVector<Value *> Uses;
+  handleUnreachableTerminator(EndInst, Uses);
+
   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 1260ef47f65ef4..601a3d208a0841 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 a489b2e3e6221a..78cc1130fb33f0 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 e788b634da8868..02ed22217854ea 100644
--- a/llvm/test/Transforms/InstCombine/sink_to_unreachable.ll
+++ b/llvm/test/Transforms/InstCombine/sink_to_unreachable.ll
@@ -157,3 +157,157 @@ 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:       unreach2:
+; CHECK-NEXT:    invoke void @__CxxFrameHandler3(ptr poison)
+; CHECK-NEXT:            to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]]
+; CHECK:       unreach3:
+; CHECK-NEXT:    [[CLEAN:%.*]] = cleanuppad within none []
+; CHECK-NEXT:    invoke void @__CxxFrameHandler3(ptr poison) [ "funclet"(token [[CLEAN]]) ]
+; 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
+
+unreach2:
+  invoke void @__CxxFrameHandler3(ptr %gep)
+  to label %dummy unwind label %icatch.dispatch
+
+unreach3:
+  %clean = cleanuppad within none []
+  invoke void @__CxxFrameHandler3(ptr %gep) [ "funclet"(token %clean) ]
+  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(...)

diff  --git a/llvm/test/Transforms/InstCombine/unreachable-code.ll b/llvm/test/Transforms/InstCombine/unreachable-code.ll
index 72ef1c79f3a8e5..bb4be9fa71f83c 100644
--- a/llvm/test/Transforms/InstCombine/unreachable-code.ll
+++ b/llvm/test/Transforms/InstCombine/unreachable-code.ll
@@ -540,6 +540,63 @@ bb2:
   br label %bb
 }
 
+declare void @invoke(ptr)
+declare i32 @__gxx_personality_v0(...)
+define void @test(i1 %x) personality ptr @__gxx_personality_v0  {
+; CHECK-LABEL: define void @test
+; CHECK-SAME: (i1 [[X:%.*]]) personality ptr @__gxx_personality_v0 {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[X]], label [[IF_ELSE:%.*]], label [[CLEAN1:%.*]]
+; CHECK:       if.else:
+; CHECK-NEXT:    store i32 1, ptr undef, align 4
+; CHECK-NEXT:    invoke void @invoke(ptr poison)
+; CHECK-NEXT:            to label [[CONT:%.*]] unwind label [[LPAD5:%.*]]
+; CHECK:       cont:
+; CHECK-NEXT:    invoke void @invoke(ptr poison)
+; CHECK-NEXT:            to label [[CLEAN1]] unwind label [[LPAD6:%.*]]
+; CHECK:       lpad5:
+; CHECK-NEXT:    [[TMP0:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT:            cleanup
+; CHECK-NEXT:    br label [[CLEAN1]]
+; CHECK:       lpad6:
+; CHECK-NEXT:    [[TMP1:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT:            cleanup
+; CHECK-NEXT:    br label [[CLEAN2:%.*]]
+; CHECK:       clean1:
+; CHECK-NEXT:    ret void
+; CHECK:       clean2:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %ref = alloca ptr
+  br i1 %x, label %if.else, label %clean1
+
+if.else:
+  store i32 1, ptr undef
+  invoke void @invoke(ptr %ref)
+  to label %cont unwind label %lpad5
+
+cont:
+  invoke void @invoke(ptr %ref)
+  to label %clean1 unwind label %lpad6
+
+lpad5:
+  %13 = landingpad { ptr, i32 }
+  cleanup
+  br label %clean1
+
+lpad6:
+  %14 = landingpad { ptr, i32 }
+  cleanup
+  br label %clean2
+
+clean1:
+  ret void
+
+clean2:
+  ret void
+}
+
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
 ; DEFAULT_ITER: {{.*}}
 ; MAX1: {{.*}}


        


More information about the llvm-commits mailing list