// exception then zap the landing pad, turning its invokes into calls.
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.
+
+ // If RI->getValue() is a landing pad, check if the first instruction is
+ // the same landing pad that caused control to branch here. If RI->getValue
+ // is a phi of landing pad, check its predecessor blocks to see if any of
+ // them contains a trivial landing pad.
+ if (RI->getValue() != LPInst && !isa<PHINode>(RI->getValue()))
return false;
- // Check that there are no other instructions except for debug intrinsics.
- BasicBlock::iterator I = LPInst->getIterator(), E = RI->getIterator();
+ // Check that there are no other instructions except for debug intrinsics
+ // between the landing pad (or phi of landing pad) and resume instruction.
+ BasicBlock::iterator I = cast<Instruction>(RI->getValue()), E = RI;
while (++I != E)
if (!isa<DbgInfoIntrinsic>(I))
return false;
+ SmallVector<BasicBlock *, 4> TrivialUnwindBlocks;
+ if (RI->getValue() == LPInst) {
+ // Landing pad is in current block, which has already been checked.
+ TrivialUnwindBlocks.push_back(BB);
+ } else {
+ // Check incoming blocks to see if any of them are trivial.
+ auto *PhiLPInst = cast<PHINode>(RI->getValue());
+ for (unsigned i = 0; i < PhiLPInst->getNumIncomingValues(); i++) {
+ auto *IncomingBB = PhiLPInst->getIncomingBlock(i);
+ auto *IncomingValue = PhiLPInst->getIncomingValue(i);
+
+ 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();
+ E = IncomingBB->getTerminator();
+ while (++I != E)
+ if (!isa<DbgInfoIntrinsic>(I)) {
+ isTrivial = false;
+ break;
+ }
+
+ if (isTrivial)
+ TrivialUnwindBlocks.push_back(IncomingBB);
+ }
+ }
+
// Turn all invokes that unwind here into calls and delete the basic block.
- for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE;) {
- BasicBlock *Pred = *PI++;
- removeUnwindEdge(Pred);
+ for (auto *TrivialBB : TrivialUnwindBlocks) {
+ if (isa<PHINode>(RI->getValue())) {
+ // Blocks that will be deleted should also be removed
+ // from the phi node.
+ BB->removePredecessor(TrivialBB, true);
+ }
+
+ for (pred_iterator PI = pred_begin(TrivialBB), PE = pred_end(TrivialBB);
+ PI != PE;) {
+ BasicBlock *Pred = *PI++;
+ removeUnwindEdge(Pred);
+ }
+
+ // The landingpad is now unreachable. Zap it.
+ if (TrivialBB == BB)
+ BB = nullptr;
+ TrivialBB->eraseFromParent();
}
- // The landingpad is now unreachable. Zap it.
- BB->eraseFromParent();
- return true;
+ // Delete the resume block if all its predecessors have been deleted, and we
+ // haven't already deleted it above when deleting the landing pad blocks.
+ if (BB && pred_begin(BB) == pred_end(BB)) {
+ BB->eraseFromParent();
+ }
+
+ return TrivialUnwindBlocks.size() != 0;
}
bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) {
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 @test2(i1 %cond) personality i32 (...)* @__gxx_personality_v0 {
+entry:
+; CHECK-LABEL: @test2(
+; 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
+
+lpad2:
+ %1 = landingpad { i8*, i32 }
+ cleanup
+ br label %rethrow
+
+rethrow:
+ %lp = phi { i8*, i32 } [%0, %lpad1], [%1, %lpad2]
+ resume { i8*, i32 } %lp
+}
+
declare i32 @__gxx_personality_v0(...)