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/ADT/BitVector.h" 16 #include "llvm/ADT/Statistic.h" 17 #include "llvm/Analysis/CFG.h" 18 #include "llvm/Analysis/EHPersonalities.h" 19 #include "llvm/Analysis/TargetTransformInfo.h" 20 #include "llvm/CodeGen/Passes.h" 21 #include "llvm/CodeGen/TargetPassConfig.h" 22 #include "llvm/IR/Dominators.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/IR/Instructions.h" 25 #include "llvm/IR/Module.h" 26 #include "llvm/Pass.h" 27 #include "llvm/Target/TargetLowering.h" 28 #include "llvm/Target/TargetSubtargetInfo.h" 29 #include "llvm/Transforms/Utils/Local.h" 30 using namespace llvm; 31 32 #define DEBUG_TYPE "dwarfehprepare" 33 34 STATISTIC(NumResumesLowered, "Number of resume calls lowered"); 35 36 namespace { 37 class DwarfEHPrepare : public FunctionPass { 38 // RewindFunction - _Unwind_Resume or the target equivalent. 39 Constant *RewindFunction; 40 41 DominatorTree *DT; 42 const TargetLowering *TLI; 43 44 bool InsertUnwindResumeCalls(Function &Fn); 45 Value *GetExceptionObject(ResumeInst *RI); 46 size_t 47 pruneUnreachableResumes(Function &Fn, 48 SmallVectorImpl<ResumeInst *> &Resumes, 49 SmallVectorImpl<LandingPadInst *> &CleanupLPads); 50 51 public: 52 static char ID; // Pass identification, replacement for typeid. 53 54 DwarfEHPrepare() 55 : FunctionPass(ID), RewindFunction(nullptr), DT(nullptr), TLI(nullptr) { 56 } 57 58 bool runOnFunction(Function &Fn) override; 59 60 bool doFinalization(Module &M) override { 61 RewindFunction = nullptr; 62 return false; 63 } 64 65 void getAnalysisUsage(AnalysisUsage &AU) const override; 66 67 StringRef getPassName() const override { 68 return "Exception handling preparation"; 69 } 70 }; 71 } // end anonymous namespace 72 73 char DwarfEHPrepare::ID = 0; 74 INITIALIZE_PASS_BEGIN(DwarfEHPrepare, DEBUG_TYPE, 75 "Prepare DWARF exceptions", false, false) 76 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 77 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 78 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 79 INITIALIZE_PASS_END(DwarfEHPrepare, DEBUG_TYPE, 80 "Prepare DWARF exceptions", false, false) 81 82 FunctionPass *llvm::createDwarfEHPass() { return new DwarfEHPrepare(); } 83 84 void DwarfEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const { 85 AU.addRequired<TargetPassConfig>(); 86 AU.addRequired<TargetTransformInfoWrapperPass>(); 87 AU.addRequired<DominatorTreeWrapperPass>(); 88 } 89 90 /// GetExceptionObject - Return the exception object from the value passed into 91 /// the 'resume' instruction (typically an aggregate). Clean up any dead 92 /// instructions, including the 'resume' instruction. 93 Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) { 94 Value *V = RI->getOperand(0); 95 Value *ExnObj = nullptr; 96 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V); 97 LoadInst *SelLoad = nullptr; 98 InsertValueInst *ExcIVI = nullptr; 99 bool EraseIVIs = false; 100 101 if (SelIVI) { 102 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) { 103 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0)); 104 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) && 105 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) { 106 ExnObj = ExcIVI->getOperand(1); 107 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1)); 108 EraseIVIs = true; 109 } 110 } 111 } 112 113 if (!ExnObj) 114 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI); 115 116 RI->eraseFromParent(); 117 118 if (EraseIVIs) { 119 if (SelIVI->use_empty()) 120 SelIVI->eraseFromParent(); 121 if (ExcIVI->use_empty()) 122 ExcIVI->eraseFromParent(); 123 if (SelLoad && SelLoad->use_empty()) 124 SelLoad->eraseFromParent(); 125 } 126 127 return ExnObj; 128 } 129 130 /// Replace resumes that are not reachable from a cleanup landing pad with 131 /// unreachable and then simplify those blocks. 132 size_t DwarfEHPrepare::pruneUnreachableResumes( 133 Function &Fn, SmallVectorImpl<ResumeInst *> &Resumes, 134 SmallVectorImpl<LandingPadInst *> &CleanupLPads) { 135 BitVector ResumeReachable(Resumes.size()); 136 size_t ResumeIndex = 0; 137 for (auto *RI : Resumes) { 138 for (auto *LP : CleanupLPads) { 139 if (isPotentiallyReachable(LP, RI, DT)) { 140 ResumeReachable.set(ResumeIndex); 141 break; 142 } 143 } 144 ++ResumeIndex; 145 } 146 147 // If everything is reachable, there is no change. 148 if (ResumeReachable.all()) 149 return Resumes.size(); 150 151 const TargetTransformInfo &TTI = 152 getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn); 153 LLVMContext &Ctx = Fn.getContext(); 154 155 // Otherwise, insert unreachable instructions and call simplifycfg. 156 size_t ResumesLeft = 0; 157 for (size_t I = 0, E = Resumes.size(); I < E; ++I) { 158 ResumeInst *RI = Resumes[I]; 159 if (ResumeReachable[I]) { 160 Resumes[ResumesLeft++] = RI; 161 } else { 162 BasicBlock *BB = RI->getParent(); 163 new UnreachableInst(Ctx, RI); 164 RI->eraseFromParent(); 165 SimplifyCFG(BB, TTI, 1); 166 } 167 } 168 Resumes.resize(ResumesLeft); 169 return ResumesLeft; 170 } 171 172 /// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present 173 /// into calls to the appropriate _Unwind_Resume function. 174 bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) { 175 SmallVector<ResumeInst*, 16> Resumes; 176 SmallVector<LandingPadInst*, 16> CleanupLPads; 177 for (BasicBlock &BB : Fn) { 178 if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator())) 179 Resumes.push_back(RI); 180 if (auto *LP = BB.getLandingPadInst()) 181 if (LP->isCleanup()) 182 CleanupLPads.push_back(LP); 183 } 184 185 if (Resumes.empty()) 186 return false; 187 188 // Check the personality, don't do anything if it's funclet-based. 189 EHPersonality Pers = classifyEHPersonality(Fn.getPersonalityFn()); 190 if (isFuncletEHPersonality(Pers)) 191 return false; 192 193 LLVMContext &Ctx = Fn.getContext(); 194 195 size_t ResumesLeft = pruneUnreachableResumes(Fn, Resumes, CleanupLPads); 196 if (ResumesLeft == 0) 197 return true; // We pruned them all. 198 199 // Find the rewind function if we didn't already. 200 if (!RewindFunction) { 201 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), 202 Type::getInt8PtrTy(Ctx), false); 203 const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME); 204 RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy); 205 } 206 207 // Create the basic block where the _Unwind_Resume call will live. 208 if (ResumesLeft == 1) { 209 // Instead of creating a new BB and PHI node, just append the call to 210 // _Unwind_Resume to the end of the single resume block. 211 ResumeInst *RI = Resumes.front(); 212 BasicBlock *UnwindBB = RI->getParent(); 213 Value *ExnObj = GetExceptionObject(RI); 214 215 // Call the _Unwind_Resume function. 216 CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB); 217 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 218 219 // We never expect _Unwind_Resume to return. 220 new UnreachableInst(Ctx, UnwindBB); 221 return true; 222 } 223 224 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn); 225 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft, 226 "exn.obj", UnwindBB); 227 228 // Extract the exception object from the ResumeInst and add it to the PHI node 229 // that feeds the _Unwind_Resume call. 230 for (ResumeInst *RI : Resumes) { 231 BasicBlock *Parent = RI->getParent(); 232 BranchInst::Create(UnwindBB, Parent); 233 234 Value *ExnObj = GetExceptionObject(RI); 235 PN->addIncoming(ExnObj, Parent); 236 237 ++NumResumesLowered; 238 } 239 240 // Call the function. 241 CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB); 242 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 243 244 // We never expect _Unwind_Resume to return. 245 new UnreachableInst(Ctx, UnwindBB); 246 return true; 247 } 248 249 bool DwarfEHPrepare::runOnFunction(Function &Fn) { 250 const TargetMachine &TM = 251 getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 252 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 253 TLI = TM.getSubtargetImpl(Fn)->getTargetLowering(); 254 bool Changed = InsertUnwindResumeCalls(Fn); 255 DT = nullptr; 256 TLI = nullptr; 257 return Changed; 258 } 259