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" 29 using namespace llvm; 30 31 STATISTIC(NumResumesLowered, "Number of resume calls lowered"); 32 33 namespace { 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 Instruction *GetExceptionObject(ResumeInst *RI); 43 44 public: 45 static char ID; // Pass identification, replacement for typeid. 46 DwarfEHPrepare(const TargetMachine *tm) : 47 FunctionPass(ID), TM(tm), TLI(TM->getTargetLowering()), 48 RewindFunction(0) { 49 initializeDominatorTreePass(*PassRegistry::getPassRegistry()); 50 } 51 52 virtual bool runOnFunction(Function &Fn); 53 54 virtual void getAnalysisUsage(AnalysisUsage &AU) const { } 55 56 const char *getPassName() const { 57 return "Exception handling preparation"; 58 } 59 }; 60 } // end anonymous namespace 61 62 char DwarfEHPrepare::ID = 0; 63 64 FunctionPass *llvm::createDwarfEHPass(const TargetMachine *tm) { 65 return new DwarfEHPrepare(tm); 66 } 67 68 /// GetExceptionObject - Return the exception object from the value passed into 69 /// the 'resume' instruction (typically an aggregate). Clean up any dead 70 /// instructions, including the 'resume' instruction. 71 Instruction *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) { 72 Value *V = RI->getOperand(0); 73 Instruction *ExnObj = 0; 74 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V); 75 LoadInst *SelLoad = 0; 76 InsertValueInst *ExcIVI = 0; 77 bool EraseIVIs = false; 78 79 if (SelIVI) { 80 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) { 81 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0)); 82 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) && 83 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) { 84 ExnObj = cast<Instruction>(ExcIVI->getOperand(1)); 85 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1)); 86 EraseIVIs = true; 87 } 88 } 89 } 90 91 if (!ExnObj) 92 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI); 93 94 RI->eraseFromParent(); 95 96 if (EraseIVIs) { 97 if (SelIVI->getNumUses() == 0) 98 SelIVI->eraseFromParent(); 99 if (ExcIVI->getNumUses() == 0) 100 ExcIVI->eraseFromParent(); 101 if (SelLoad && SelLoad->getNumUses() == 0) 102 SelLoad->eraseFromParent(); 103 } 104 105 return ExnObj; 106 } 107 108 /// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present 109 /// into calls to the appropriate _Unwind_Resume function. 110 bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) { 111 bool UsesNewEH = false; 112 SmallVector<ResumeInst*, 16> Resumes; 113 for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) { 114 TerminatorInst *TI = I->getTerminator(); 115 if (ResumeInst *RI = dyn_cast<ResumeInst>(TI)) 116 Resumes.push_back(RI); 117 else if (InvokeInst *II = dyn_cast<InvokeInst>(TI)) 118 UsesNewEH = II->getUnwindDest()->isLandingPad(); 119 } 120 121 if (Resumes.empty()) 122 return UsesNewEH; 123 124 // Find the rewind function if we didn't already. 125 if (!RewindFunction) { 126 LLVMContext &Ctx = Resumes[0]->getContext(); 127 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), 128 Type::getInt8PtrTy(Ctx), false); 129 const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME); 130 RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy); 131 } 132 133 // Create the basic block where the _Unwind_Resume call will live. 134 LLVMContext &Ctx = Fn.getContext(); 135 unsigned ResumesSize = Resumes.size(); 136 137 if (ResumesSize == 1) { 138 // Instead of creating a new BB and PHI node, just append the call to 139 // _Unwind_Resume to the end of the single resume block. 140 ResumeInst *RI = Resumes.front(); 141 BasicBlock *UnwindBB = RI->getParent(); 142 Instruction *ExnObj = GetExceptionObject(RI); 143 144 // Call the _Unwind_Resume function. 145 CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB); 146 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 147 148 // We never expect _Unwind_Resume to return. 149 new UnreachableInst(Ctx, UnwindBB); 150 return true; 151 } 152 153 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn); 154 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesSize, 155 "exn.obj", UnwindBB); 156 157 // Extract the exception object from the ResumeInst and add it to the PHI node 158 // that feeds the _Unwind_Resume call. 159 for (SmallVectorImpl<ResumeInst*>::iterator 160 I = Resumes.begin(), E = Resumes.end(); I != E; ++I) { 161 ResumeInst *RI = *I; 162 BasicBlock *Parent = RI->getParent(); 163 BranchInst::Create(UnwindBB, Parent); 164 165 Instruction *ExnObj = GetExceptionObject(RI); 166 PN->addIncoming(ExnObj, Parent); 167 168 ++NumResumesLowered; 169 } 170 171 // Call the function. 172 CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB); 173 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 174 175 // We never expect _Unwind_Resume to return. 176 new UnreachableInst(Ctx, UnwindBB); 177 return true; 178 } 179 180 bool DwarfEHPrepare::runOnFunction(Function &Fn) { 181 bool Changed = InsertUnwindResumeCalls(Fn); 182 return Changed; 183 } 184