DwarfEHPrepare.cpp revision afcb5b5ee854474a50dc4642a6e6ecc15acfe8cc
1//===-- DwarfEHPrepare - Prepare exception handling for code generation ---===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This pass mulches exception handling code into a form adapted to code 11// generation. Required if using dwarf exception handling. 12// 13//===----------------------------------------------------------------------===// 14 15#define DEBUG_TYPE "dwarfehprepare" 16#include "llvm/Function.h" 17#include "llvm/Instructions.h" 18#include "llvm/IntrinsicInst.h" 19#include "llvm/Module.h" 20#include "llvm/Pass.h" 21#include "llvm/ADT/Statistic.h" 22#include "llvm/Analysis/Dominators.h" 23#include "llvm/CodeGen/Passes.h" 24#include "llvm/MC/MCAsmInfo.h" 25#include "llvm/Support/CallSite.h" 26#include "llvm/Target/TargetLowering.h" 27#include "llvm/Transforms/Utils/BasicBlockUtils.h" 28#include "llvm/Transforms/Utils/SSAUpdater.h" 29using namespace llvm; 30 31STATISTIC(NumResumesLowered, "Number of resume calls lowered"); 32 33namespace { 34 class DwarfEHPrepare : public FunctionPass { 35 const TargetMachine *TM; 36 const TargetLowering *TLI; 37 38 // RewindFunction - _Unwind_Resume or the target equivalent. 39 Constant *RewindFunction; 40 41 bool InsertUnwindResumeCalls(Function &Fn); 42 43 public: 44 static char ID; // Pass identification, replacement for typeid. 45 DwarfEHPrepare(const TargetMachine *tm) : 46 FunctionPass(ID), TM(tm), TLI(TM->getTargetLowering()), 47 RewindFunction(0) { 48 initializeDominatorTreePass(*PassRegistry::getPassRegistry()); 49 } 50 51 virtual bool runOnFunction(Function &Fn); 52 53 virtual void getAnalysisUsage(AnalysisUsage &AU) const { } 54 55 const char *getPassName() const { 56 return "Exception handling preparation"; 57 } 58 }; 59} // end anonymous namespace 60 61char DwarfEHPrepare::ID = 0; 62 63FunctionPass *llvm::createDwarfEHPass(const TargetMachine *tm) { 64 return new DwarfEHPrepare(tm); 65} 66 67/// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present 68/// into calls to the appropriate _Unwind_Resume function. 69bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) { 70 bool UsesNewEH = false; 71 SmallVector<ResumeInst*, 16> Resumes; 72 for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) { 73 TerminatorInst *TI = I->getTerminator(); 74 if (ResumeInst *RI = dyn_cast<ResumeInst>(TI)) 75 Resumes.push_back(RI); 76 else if (InvokeInst *II = dyn_cast<InvokeInst>(TI)) 77 UsesNewEH = II->getUnwindDest()->isLandingPad(); 78 } 79 80 if (Resumes.empty()) 81 return UsesNewEH; 82 83 // Find the rewind function if we didn't already. 84 if (!RewindFunction) { 85 LLVMContext &Ctx = Resumes[0]->getContext(); 86 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), 87 Type::getInt8PtrTy(Ctx), false); 88 const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME); 89 RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy); 90 } 91 92 // Create the basic block where the _Unwind_Resume call will live. 93 LLVMContext &Ctx = Fn.getContext(); 94 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn); 95 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), Resumes.size(), 96 "exn.obj", UnwindBB); 97 98 // Extract the exception object from the ResumeInst and add it to the PHI node 99 // that feeds the _Unwind_Resume call. 100 for (SmallVectorImpl<ResumeInst*>::iterator 101 I = Resumes.begin(), E = Resumes.end(); I != E; ++I) { 102 ResumeInst *RI = *I; 103 BranchInst::Create(UnwindBB, RI->getParent()); 104 105 Value *V = RI->getOperand(0); 106 Instruction *ExnObj = 0; 107 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V); 108 LoadInst *SelLoad = 0; 109 InsertValueInst *ExcIVI = 0; 110 bool EraseIVIs = false; 111 if (SelIVI) { 112 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) { 113 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0)); 114 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) && 115 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) { 116 ExnObj = cast<Instruction>(ExcIVI->getOperand(1)); 117 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1)); 118 EraseIVIs = true; 119 } 120 } 121 } 122 123 if (!ExnObj) 124 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI); 125 126 PN->addIncoming(ExnObj, RI->getParent()); 127 RI->eraseFromParent(); 128 129 if (EraseIVIs) { 130 if (SelIVI->getNumUses() == 0) 131 SelIVI->eraseFromParent(); 132 if (ExcIVI->getNumUses() == 0) 133 ExcIVI->eraseFromParent(); 134 if (SelLoad && SelLoad->getNumUses() == 0) 135 SelLoad->eraseFromParent(); 136 } 137 138 ++NumResumesLowered; 139 } 140 141 // Call the function. 142 CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB); 143 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 144 145 // We never expect _Unwind_Resume to return. 146 new UnreachableInst(Ctx, UnwindBB); 147 return true; 148} 149 150bool DwarfEHPrepare::runOnFunction(Function &Fn) { 151 bool Changed = InsertUnwindResumeCalls(Fn); 152 return Changed; 153} 154