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