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