[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