[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:
Chen Li 2016-01-10 05:48:01 +00:00
parent 2adaa98927
commit 1689c2f54b
3 changed files with 175 additions and 6 deletions

View File

@ -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();

View File

@ -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()

View File

@ -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(...)