aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/VMCore/AutoUpgrade.cpp147
1 files changed, 113 insertions, 34 deletions
diff --git a/lib/VMCore/AutoUpgrade.cpp b/lib/VMCore/AutoUpgrade.cpp
index 7b0b34ed89..2c327660d4 100644
--- a/lib/VMCore/AutoUpgrade.cpp
+++ b/lib/VMCore/AutoUpgrade.cpp
@@ -387,10 +387,9 @@ void llvm::UpgradeExceptionHandling(Module *M) {
Type *SelTy = Type::getInt32Ty(Context);
Type *LPadSlotTy = StructType::get(ExnTy, SelTy, NULL);
- // This map stores the slots where the exception object and selector value are
- // stored within a function.
- SmallPtrSet<Instruction*, 32> DeadInsts;
- DenseMap<Function*, std::pair<Value*, Value*> > FnToLPadSlotMap;
+ // This map links the invoke instruction with the eh.exception and eh.selector
+ // calls associated with it.
+ DenseMap<InvokeInst*, std::pair<Value*, Value*> > InvokeToIntrinsicsMap;
for (Module::iterator
I = M->begin(), E = M->end(); I != E; ++I) {
Function &F = *I;
@@ -401,47 +400,127 @@ void llvm::UpgradeExceptionHandling(Module *M) {
InvokeInst *Inst = dyn_cast<InvokeInst>(BB->getTerminator());
if (!Inst) continue;
BasicBlock *UnwindDest = Inst->getUnwindDest();
- if (UnwindDest->isLandingPad()) continue; // All ready converted.
-
- // Store the exception object and selector value in the entry block.
- Value *ExnSlot = 0;
- Value *SelSlot = 0;
- if (!FnToLPadSlotMap[&F].first) {
- BasicBlock *Entry = &F.front();
- ExnSlot = new AllocaInst(ExnTy, "exn", Entry->getTerminator());
- SelSlot = new AllocaInst(SelTy, "sel", Entry->getTerminator());
- FnToLPadSlotMap[&F] = std::make_pair(ExnSlot, SelSlot);
- } else {
- ExnSlot = FnToLPadSlotMap[&F].first;
- SelSlot = FnToLPadSlotMap[&F].second;
- }
-
- // We're in an unwind block. Try to find the eh.exception and eh.selector
- // calls.
- IRBuilder<> Builder(Context);
- Builder.SetInsertPoint(UnwindDest, UnwindDest->getFirstNonPHI());
+ if (UnwindDest->isLandingPad()) continue; // Already converted.
SmallPtrSet<BasicBlock*, 8> Visited;
CallInst *Exn = 0;
CallInst *Sel = 0;
FindExnAndSelIntrinsics(UnwindDest, Exn, Sel, Visited);
assert(Exn && Sel && "Cannot find eh.exception and eh.selector calls!");
+ InvokeToIntrinsicsMap[Inst] = std::make_pair(Exn, Sel);
+ }
+ }
+
+ // This map stores the slots where the exception object and selector value are
+ // stored within a function.
+ DenseMap<Function*, std::pair<Value*, Value*> > FnToLPadSlotMap;
+
+ // This maps the old intrinsic calls (eh.exception & eh.selector) to the new
+ // landingpad instruction(s).
+ DenseMap<std::pair<CallInst*, CallInst*>,
+ SmallVector<std::pair<Value*, Value*>, 8> > OldExnToNewExnMap;
+
+ SmallPtrSet<Instruction*, 32> DeadInsts;
+ for (DenseMap<InvokeInst*, std::pair<Value*, Value*> >::iterator
+ I = InvokeToIntrinsicsMap.begin(), E = InvokeToIntrinsicsMap.end();
+ I != E; ++I) {
+ InvokeInst *Invoke = I->first;
+ BasicBlock *UnwindDest = Invoke->getUnwindDest();
+ Function *F = UnwindDest->getParent();
+ std::pair<Value*, Value*> EHIntrinsics = I->second;
+ CallInst *Exn = cast<CallInst>(EHIntrinsics.first);
+ CallInst *Sel = cast<CallInst>(EHIntrinsics.second);
+
+ // Store the exception object and selector value in the entry block.
+ Value *ExnSlot = 0;
+ Value *SelSlot = 0;
+ if (!FnToLPadSlotMap[F].first) {
+ BasicBlock *Entry = &F->front();
+ ExnSlot = new AllocaInst(ExnTy, "exn", Entry->getTerminator());
+ SelSlot = new AllocaInst(SelTy, "sel", Entry->getTerminator());
+ FnToLPadSlotMap[F] = std::make_pair(ExnSlot, SelSlot);
+ } else {
+ ExnSlot = FnToLPadSlotMap[F].first;
+ SelSlot = FnToLPadSlotMap[F].second;
+ }
- Value *PersFn = Sel->getArgOperand(1);
- LandingPadInst *LPI = Builder.CreateLandingPad(LPadSlotTy, PersFn, 0);
- Value *LPExn = Builder.CreateExtractValue(LPI, 0);
- Value *LPSel = Builder.CreateExtractValue(LPI, 1);
- Builder.CreateStore(LPExn, ExnSlot);
- Builder.CreateStore(LPSel, SelSlot);
+ if (!UnwindDest->getSinglePredecessor()) {
+ // The unwind destination doesn't have a single predecessor. Create an
+ // unwind destination which has only one predecessor.
+ BasicBlock *NewBB = BasicBlock::Create(Context, "new.lpad",
+ UnwindDest->getParent());
+ BranchInst::Create(UnwindDest, NewBB);
+ Invoke->setUnwindDest(NewBB);
+
+ // Fix up any PHIs in the original unwind destination block.
+ for (BasicBlock::iterator
+ II = UnwindDest->begin(); isa<PHINode>(II); ++II) {
+ PHINode *PN = cast<PHINode>(II);
+ int Idx = PN->getBasicBlockIndex(Invoke->getParent());
+ if (Idx == -1) continue;
+ PN->setIncomingBlock(Idx, NewBB);
+ }
- TransferClausesToLandingPadInst(LPI, Sel);
+ UnwindDest = NewBB;
+ }
- Exn->replaceAllUsesWith(LPExn);
- Sel->replaceAllUsesWith(LPSel);
+ IRBuilder<> Builder(Context);
+ Builder.SetInsertPoint(UnwindDest, UnwindDest->getFirstInsertionPt());
- DeadInsts.insert(Exn);
- DeadInsts.insert(Sel);
+ Value *PersFn = Sel->getArgOperand(1);
+ LandingPadInst *LPI = Builder.CreateLandingPad(LPadSlotTy, PersFn, 0);
+ Value *LPExn = Builder.CreateExtractValue(LPI, 0);
+ Value *LPSel = Builder.CreateExtractValue(LPI, 1);
+ Builder.CreateStore(LPExn, ExnSlot);
+ Builder.CreateStore(LPSel, SelSlot);
+
+ TransferClausesToLandingPadInst(LPI, Sel);
+
+ OldExnToNewExnMap[std::make_pair(Exn, Sel)].
+ push_back(std::make_pair(LPExn, LPSel));
+
+ DeadInsts.insert(Exn);
+ DeadInsts.insert(Sel);
+ }
+
+ // Replace the old intrinsic calls with the new (possibly PHI'ed) values.
+ for (DenseMap<std::pair<CallInst*, CallInst*>,
+ SmallVector<std::pair<Value*, Value*>, 8> >::iterator
+ I = OldExnToNewExnMap.begin(), E = OldExnToNewExnMap.end();
+ I != E; ++I) {
+ std::pair<CallInst*, CallInst*> OldExnSel = I->first;
+ CallInst *Exn = OldExnSel.first;
+ CallInst *Sel = OldExnSel.second;
+ SmallVector<std::pair<Value*, Value*>, 8> &LPExnSel = I->second;
+ unsigned Size = LPExnSel.size();
+ Value *LPExn = LPExnSel[0].first;
+ Value *LPSel = LPExnSel[0].second;
+
+ if (Size != 1) {
+ BasicBlock *Parent = Exn->getParent();
+ IRBuilder<> Builder(Context);
+ Builder.SetInsertPoint(Parent, Parent->getFirstInsertionPt());
+
+ PHINode *PN = Builder.CreatePHI(Exn->getType(), Size, "exn.phi");
+ for (SmallVector<std::pair<Value*, Value*>, 8>::iterator
+ II = LPExnSel.begin(), IE = LPExnSel.end(); II != IE; ++II)
+ PN->addIncoming(II->first, cast<Instruction>(II->first)->getParent());
+
+ LPExn = PN;
+
+ Parent = Sel->getParent();
+ Builder.SetInsertPoint(Parent, Parent->getFirstInsertionPt());
+
+ PN = Builder.CreatePHI(Sel->getType(), Size, "sel.phi");
+ for (SmallVector<std::pair<Value*, Value*>, 8>::iterator
+ II = LPExnSel.begin(), IE = LPExnSel.end(); II != IE; ++II)
+ PN->addIncoming(II->second, cast<Instruction>(II->second)->getParent());
+
+ LPSel = PN;
}
+
+ Exn->replaceAllUsesWith(LPExn);
+ Sel->replaceAllUsesWith(LPSel);
}
// Remove the dead instructions.