Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -141,6 +141,8 @@ 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 @@ } 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(RI->getValue())) + return SimplifyCommonResume(RI); + else if (isa(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(RI->getValue())->getIterator(), + E = RI->getIterator(); + while (++I != E) + if (!isa(I)) + return false; + + SmallSet TrivialUnwindBlocks; + auto *PhiLPInst = cast(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(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(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(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(); Index: test/Transforms/SimplifyCFG/bug-25299.ll =================================================================== --- test/Transforms/SimplifyCFG/bug-25299.ll +++ test/Transforms/SimplifyCFG/bug-25299.ll @@ -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() \ No newline at end of file Index: test/Transforms/SimplifyCFG/invoke_unwind.ll =================================================================== --- test/Transforms/SimplifyCFG/invoke_unwind.ll +++ test/Transforms/SimplifyCFG/invoke_unwind.ll @@ -30,4 +30,46 @@ 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(...)