Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions llvm/include/llvm/Transforms/Utils/Local.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3231,9 +3231,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))
Expand Down
22 changes: 20 additions & 2 deletions llvm/lib/Transforms/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2762,15 +2762,33 @@ 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;
unsigned NumDeadDbgInst = 0;
// 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();
Expand Down
3 changes: 1 addition & 2 deletions llvm/test/Transforms/InstCombine/phi-select-constant.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/InstCombine/pr63791.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
154 changes: 154 additions & 0 deletions llvm/test/Transforms/InstCombine/sink_to_unreachable.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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(...)
57 changes: 57 additions & 0 deletions llvm/test/Transforms/InstCombine/unreachable-code.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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: {{.*}}