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