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