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