forked from OSchip/llvm-project
[SimplifyCFG] Extend SimplifyResume to handle phi of trivial landing pad.
Summary: This is a fix of D13718. D13718 was committed but then reverted because of the following bug: https://llvm.org/bugs/show_bug.cgi?id=25299 This patch fixes the issue shown in the bug. Reviewers: majnemer, reames Subscribers: jevinskie, llvm-commits Differential Revision: http://reviews.llvm.org/D14308 llvm-svn: 257277
This commit is contained in:
parent
2adaa98927
commit
1689c2f54b
|
@ -141,6 +141,8 @@ class SimplifyCFGOpt {
|
|||
|
||||
bool SimplifyReturn(ReturnInst *RI, IRBuilder<> &Builder);
|
||||
bool SimplifyResume(ResumeInst *RI, IRBuilder<> &Builder);
|
||||
bool SimplifySingleResume(ResumeInst *RI);
|
||||
bool SimplifyCommonResume(ResumeInst *RI);
|
||||
bool SimplifyCleanupReturn(CleanupReturnInst *RI);
|
||||
bool SimplifyUnreachable(UnreachableInst *UI);
|
||||
bool SimplifySwitch(SwitchInst *SI, IRBuilder<> &Builder);
|
||||
|
@ -3239,14 +3241,99 @@ static bool SimplifyBranchOnICmpChain(BranchInst *BI, IRBuilder<> &Builder,
|
|||
}
|
||||
|
||||
bool SimplifyCFGOpt::SimplifyResume(ResumeInst *RI, IRBuilder<> &Builder) {
|
||||
// If this is a trivial landing pad that just continues unwinding the caught
|
||||
// exception then zap the landing pad, turning its invokes into calls.
|
||||
if (isa<PHINode>(RI->getValue()))
|
||||
return SimplifyCommonResume(RI);
|
||||
else if (isa<LandingPadInst>(RI->getParent()->getFirstNonPHI()) &&
|
||||
RI->getValue() == RI->getParent()->getFirstNonPHI())
|
||||
// The resume must unwind the exception that caused control to branch here.
|
||||
return SimplifySingleResume(RI);
|
||||
}
|
||||
|
||||
// Simplify resume that is shared by several landing pads (phi of landing pad).
|
||||
bool SimplifyCFGOpt::SimplifyCommonResume(ResumeInst *RI) {
|
||||
BasicBlock *BB = RI->getParent();
|
||||
|
||||
// Check that there are no other instructions except for debug intrinsics
|
||||
// between the phi of landing pads (RI->getValue()) and resume instruction.
|
||||
BasicBlock::iterator I = cast<Instruction>(RI->getValue())->getIterator(),
|
||||
E = RI->getIterator();
|
||||
while (++I != E)
|
||||
if (!isa<DbgInfoIntrinsic>(I))
|
||||
return false;
|
||||
|
||||
SmallSet<BasicBlock *, 4> TrivialUnwindBlocks;
|
||||
auto *PhiLPInst = cast<PHINode>(RI->getValue());
|
||||
|
||||
// Check incoming blocks to see if any of them are trivial.
|
||||
for (unsigned Idx = 0, End = PhiLPInst->getNumIncomingValues();
|
||||
Idx != End; Idx++) {
|
||||
auto *IncomingBB = PhiLPInst->getIncomingBlock(Idx);
|
||||
auto *IncomingValue = PhiLPInst->getIncomingValue(Idx);
|
||||
|
||||
// If the block has other successors, we can not delete it because
|
||||
// it has other dependents.
|
||||
if (IncomingBB->getUniqueSuccessor() != BB)
|
||||
continue;
|
||||
|
||||
auto *LandingPad =
|
||||
dyn_cast<LandingPadInst>(IncomingBB->getFirstNonPHI());
|
||||
// Not the landing pad that caused the control to branch here.
|
||||
if (IncomingValue != LandingPad)
|
||||
continue;
|
||||
|
||||
bool isTrivial = true;
|
||||
|
||||
I = IncomingBB->getFirstNonPHI()->getIterator();
|
||||
E = IncomingBB->getTerminator()->getIterator();
|
||||
while (++I != E)
|
||||
if (!isa<DbgInfoIntrinsic>(I)) {
|
||||
isTrivial = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isTrivial)
|
||||
TrivialUnwindBlocks.insert(IncomingBB);
|
||||
}
|
||||
|
||||
// If no trivial unwind blocks, don't do any simplifications.
|
||||
if (TrivialUnwindBlocks.empty()) return false;
|
||||
|
||||
// Turn all invokes that unwind here into calls.
|
||||
for (auto *TrivialBB : TrivialUnwindBlocks) {
|
||||
// Blocks that will be simplified should be removed from the phi node.
|
||||
// Note there could be multiple edges to the resume block, and we need
|
||||
// to remove them all.
|
||||
while (PhiLPInst->getBasicBlockIndex(TrivialBB) != -1)
|
||||
BB->removePredecessor(TrivialBB, true);
|
||||
|
||||
for (pred_iterator PI = pred_begin(TrivialBB), PE = pred_end(TrivialBB);
|
||||
PI != PE;) {
|
||||
BasicBlock *Pred = *PI++;
|
||||
removeUnwindEdge(Pred);
|
||||
}
|
||||
|
||||
// In each SimplifyCFG run, only the current processed block can be erased.
|
||||
// Otherwise, it will break the iteration of SimplifyCFG pass. So instead
|
||||
// of erasing TrivialBB, we only remove the branch to the common resume
|
||||
// block so that we can later erase the resume block since it has no
|
||||
// predecessors.
|
||||
TrivialBB->getTerminator()->eraseFromParent();
|
||||
new UnreachableInst(RI->getContext(), TrivialBB);
|
||||
}
|
||||
|
||||
// Delete the resume block if all its predecessors have been removed.
|
||||
if (pred_empty(BB))
|
||||
BB->eraseFromParent();
|
||||
|
||||
return !TrivialUnwindBlocks.empty();
|
||||
}
|
||||
|
||||
// Simplify resume that is only used by a single (non-phi) landing pad.
|
||||
bool SimplifyCFGOpt::SimplifySingleResume(ResumeInst *RI) {
|
||||
BasicBlock *BB = RI->getParent();
|
||||
LandingPadInst *LPInst = dyn_cast<LandingPadInst>(BB->getFirstNonPHI());
|
||||
if (RI->getValue() != LPInst)
|
||||
// Not a landing pad, or the resume is not unwinding the exception that
|
||||
// caused control to branch here.
|
||||
return false;
|
||||
assert (RI->getValue() == LPInst &&
|
||||
"Resume must unwind the exception that caused control to here");
|
||||
|
||||
// Check that there are no other instructions except for debug intrinsics.
|
||||
BasicBlock::iterator I = LPInst->getIterator(), E = RI->getIterator();
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
; RUN: opt < %s -simplifycfg -S | FileCheck %s
|
||||
|
||||
;; Test case for bug 25299, contributed by David Majnemer.
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define void @f(i1 %B) personality i1 undef {
|
||||
entry:
|
||||
;CHECK: entry
|
||||
;CHECK-NEXT: call void @g()
|
||||
invoke void @g()
|
||||
to label %continue unwind label %unwind
|
||||
|
||||
unwind: ; preds = %entry
|
||||
%tmp101 = landingpad { i8*, i32 }
|
||||
cleanup
|
||||
br i1 %B, label %resume, label %then
|
||||
|
||||
then: ; preds = %cleanup1
|
||||
br label %resume
|
||||
|
||||
resume: ; preds = %cleanup2, %then, %cleanup1, %unwind
|
||||
%tmp104 = phi { i8*, i32 } [ %tmp101, %then ], [ %tmp106, %cleanup2 ], [ %tmp101, %unwind ]
|
||||
;CHECK-NOT: resume { i8*, i32 } %tmp104
|
||||
resume { i8*, i32 } %tmp104
|
||||
|
||||
continue: ; preds = %entry, %continue
|
||||
;CHECK: continue: ; preds = %entry, %continue
|
||||
;CHECK-NEXT: call void @g()
|
||||
invoke void @g()
|
||||
to label %continue unwind label %cleanup2
|
||||
|
||||
cleanup2: ; preds = %continue
|
||||
%tmp106 = landingpad { i8*, i32 }
|
||||
cleanup
|
||||
br label %resume
|
||||
}
|
||||
|
||||
declare void @g()
|
|
@ -30,4 +30,46 @@ Rethrow:
|
|||
resume { i8*, i32 } %exn
|
||||
}
|
||||
|
||||
declare i64 @dummy1()
|
||||
declare i64 @dummy2()
|
||||
|
||||
; This testcase checks to see if simplifycfg pass can convert two invoke
|
||||
; instructions to call instructions if they share a common trivial unwind
|
||||
; block.
|
||||
define i64 @test3(i1 %cond) personality i32 (...)* @__gxx_personality_v0 {
|
||||
entry:
|
||||
; CHECK-LABEL: @test3(
|
||||
; CHECK: %call1 = call i64 @dummy1()
|
||||
; CHECK: %call2 = call i64 @dummy2()
|
||||
; CHECK-NOT: resume { i8*, i32 } %lp
|
||||
br i1 %cond, label %br1, label %br2
|
||||
|
||||
br1:
|
||||
%call1 = invoke i64 @dummy1()
|
||||
to label %invoke.cont unwind label %lpad1
|
||||
|
||||
br2:
|
||||
%call2 = invoke i64 @dummy2()
|
||||
to label %invoke.cont unwind label %lpad2
|
||||
|
||||
invoke.cont:
|
||||
%c = phi i64 [%call1, %br1], [%call2, %br2]
|
||||
ret i64 %c
|
||||
|
||||
|
||||
lpad1:
|
||||
%0 = landingpad { i8*, i32 }
|
||||
cleanup
|
||||
br label %rethrow
|
||||
|
||||
rethrow:
|
||||
%lp = phi { i8*, i32 } [%0, %lpad1], [%1, %lpad2]
|
||||
resume { i8*, i32 } %lp
|
||||
|
||||
lpad2:
|
||||
%1 = landingpad { i8*, i32 }
|
||||
cleanup
|
||||
br label %rethrow
|
||||
}
|
||||
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
|
|
Loading…
Reference in New Issue