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/CodeGen/DwarfEHPrepare.h" 15 #include "llvm/ADT/BitVector.h" 16 #include "llvm/ADT/SmallVector.h" 17 #include "llvm/ADT/Statistic.h" 18 #include "llvm/Analysis/CFG.h" 19 #include "llvm/Analysis/DomTreeUpdater.h" 20 #include "llvm/Analysis/TargetTransformInfo.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/DebugInfoMetadata.h" 27 #include "llvm/IR/DerivedTypes.h" 28 #include "llvm/IR/Dominators.h" 29 #include "llvm/IR/EHPersonalities.h" 30 #include "llvm/IR/Function.h" 31 #include "llvm/IR/Instructions.h" 32 #include "llvm/IR/Module.h" 33 #include "llvm/IR/Type.h" 34 #include "llvm/InitializePasses.h" 35 #include "llvm/Pass.h" 36 #include "llvm/Support/Casting.h" 37 #include "llvm/Target/TargetMachine.h" 38 #include "llvm/TargetParser/Triple.h" 39 #include "llvm/Transforms/Utils/Local.h" 40 #include <cstddef> 41 42 using namespace llvm; 43 44 #define DEBUG_TYPE "dwarf-eh-prepare" 45 46 STATISTIC(NumResumesLowered, "Number of resume calls lowered"); 47 STATISTIC(NumCleanupLandingPadsUnreachable, 48 "Number of cleanup landing pads found unreachable"); 49 STATISTIC(NumCleanupLandingPadsRemaining, 50 "Number of cleanup landing pads remaining"); 51 STATISTIC(NumNoUnwind, "Number of functions with nounwind"); 52 STATISTIC(NumUnwind, "Number of functions with unwind"); 53 54 namespace { 55 56 class DwarfEHPrepare { 57 CodeGenOptLevel OptLevel; 58 59 Function &F; 60 const TargetLowering &TLI; 61 DomTreeUpdater *DTU; 62 const TargetTransformInfo *TTI; 63 const Triple &TargetTriple; 64 65 /// Return the exception object from the value passed into 66 /// the 'resume' instruction (typically an aggregate). Clean up any dead 67 /// instructions, including the 'resume' instruction. 68 Value *GetExceptionObject(ResumeInst *RI); 69 70 /// Replace resumes that are not reachable from a cleanup landing pad with 71 /// unreachable and then simplify those blocks. 72 size_t 73 pruneUnreachableResumes(SmallVectorImpl<ResumeInst *> &Resumes, 74 SmallVectorImpl<LandingPadInst *> &CleanupLPads); 75 76 /// Convert the ResumeInsts that are still present 77 /// into calls to the appropriate _Unwind_Resume function. 78 bool InsertUnwindResumeCalls(); 79 80 public: 81 DwarfEHPrepare(CodeGenOptLevel OptLevel_, Function &F_, 82 const TargetLowering &TLI_, DomTreeUpdater *DTU_, 83 const TargetTransformInfo *TTI_, const Triple &TargetTriple_) 84 : OptLevel(OptLevel_), F(F_), TLI(TLI_), DTU(DTU_), TTI(TTI_), 85 TargetTriple(TargetTriple_) {} 86 87 bool run(); 88 }; 89 90 } // namespace 91 92 Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) { 93 Value *V = RI->getOperand(0); 94 Value *ExnObj = nullptr; 95 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V); 96 LoadInst *SelLoad = nullptr; 97 InsertValueInst *ExcIVI = nullptr; 98 bool EraseIVIs = false; 99 100 if (SelIVI) { 101 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) { 102 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0)); 103 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) && 104 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) { 105 ExnObj = ExcIVI->getOperand(1); 106 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1)); 107 EraseIVIs = true; 108 } 109 } 110 } 111 112 if (!ExnObj) 113 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", 114 RI->getIterator()); 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 size_t DwarfEHPrepare::pruneUnreachableResumes( 131 SmallVectorImpl<ResumeInst *> &Resumes, 132 SmallVectorImpl<LandingPadInst *> &CleanupLPads) { 133 assert(DTU && "Should have DomTreeUpdater here."); 134 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, nullptr, &DTU->getDomTree())) { 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 LLVMContext &Ctx = F.getContext(); 152 153 // Otherwise, insert unreachable instructions and call simplifycfg. 154 size_t ResumesLeft = 0; 155 for (size_t I = 0, E = Resumes.size(); I < E; ++I) { 156 ResumeInst *RI = Resumes[I]; 157 if (ResumeReachable[I]) { 158 Resumes[ResumesLeft++] = RI; 159 } else { 160 BasicBlock *BB = RI->getParent(); 161 new UnreachableInst(Ctx, RI->getIterator()); 162 RI->eraseFromParent(); 163 simplifyCFG(BB, *TTI, DTU); 164 } 165 } 166 Resumes.resize(ResumesLeft); 167 return ResumesLeft; 168 } 169 170 bool DwarfEHPrepare::InsertUnwindResumeCalls() { 171 SmallVector<ResumeInst *, 16> Resumes; 172 SmallVector<LandingPadInst *, 16> CleanupLPads; 173 if (F.doesNotThrow()) 174 NumNoUnwind++; 175 else 176 NumUnwind++; 177 for (BasicBlock &BB : F) { 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 NumCleanupLandingPadsRemaining += CleanupLPads.size(); 186 187 if (Resumes.empty()) 188 return false; 189 190 // Check the personality, don't do anything if it's scope-based. 191 EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn()); 192 if (isScopedEHPersonality(Pers)) 193 return false; 194 195 LLVMContext &Ctx = F.getContext(); 196 197 size_t ResumesLeft = Resumes.size(); 198 if (OptLevel != CodeGenOptLevel::None) { 199 ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads); 200 #if LLVM_ENABLE_STATS 201 unsigned NumRemainingLPs = 0; 202 for (BasicBlock &BB : F) { 203 if (auto *LP = BB.getLandingPadInst()) 204 if (LP->isCleanup()) 205 NumRemainingLPs++; 206 } 207 NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs; 208 NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs; 209 #endif 210 } 211 212 if (ResumesLeft == 0) 213 return true; // We pruned them all. 214 215 // RewindFunction - _Unwind_Resume or the target equivalent. 216 FunctionCallee RewindFunction; 217 CallingConv::ID RewindFunctionCallingConv; 218 FunctionType *FTy; 219 const char *RewindName; 220 bool DoesRewindFunctionNeedExceptionObject; 221 222 if ((Pers == EHPersonality::GNU_CXX || Pers == EHPersonality::GNU_CXX_SjLj) && 223 TargetTriple.isTargetEHABICompatible()) { 224 RewindName = TLI.getLibcallName(RTLIB::CXA_END_CLEANUP); 225 FTy = FunctionType::get(Type::getVoidTy(Ctx), false); 226 RewindFunctionCallingConv = 227 TLI.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP); 228 DoesRewindFunctionNeedExceptionObject = false; 229 } else { 230 RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME); 231 FTy = FunctionType::get(Type::getVoidTy(Ctx), PointerType::getUnqual(Ctx), 232 false); 233 RewindFunctionCallingConv = TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME); 234 DoesRewindFunctionNeedExceptionObject = true; 235 } 236 RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy); 237 238 // Create the basic block where the _Unwind_Resume call will live. 239 if (ResumesLeft == 1) { 240 // Instead of creating a new BB and PHI node, just append the call to 241 // _Unwind_Resume to the end of the single resume block. 242 ResumeInst *RI = Resumes.front(); 243 BasicBlock *UnwindBB = RI->getParent(); 244 Value *ExnObj = GetExceptionObject(RI); 245 llvm::SmallVector<Value *, 1> RewindFunctionArgs; 246 if (DoesRewindFunctionNeedExceptionObject) 247 RewindFunctionArgs.push_back(ExnObj); 248 249 // Call the rewind function. 250 CallInst *CI = 251 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB); 252 // The verifier requires that all calls of debug-info-bearing functions 253 // from debug-info-bearing functions have a debug location (for inlining 254 // purposes). Assign a dummy location to satisfy the constraint. 255 Function *RewindFn = dyn_cast<Function>(RewindFunction.getCallee()); 256 if (RewindFn && RewindFn->getSubprogram()) 257 if (DISubprogram *SP = F.getSubprogram()) 258 CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, SP)); 259 CI->setCallingConv(RewindFunctionCallingConv); 260 261 // We never expect _Unwind_Resume to return. 262 CI->setDoesNotReturn(); 263 new UnreachableInst(Ctx, UnwindBB); 264 return true; 265 } 266 267 std::vector<DominatorTree::UpdateType> Updates; 268 Updates.reserve(Resumes.size()); 269 270 llvm::SmallVector<Value *, 1> RewindFunctionArgs; 271 272 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F); 273 PHINode *PN = PHINode::Create(PointerType::getUnqual(Ctx), ResumesLeft, 274 "exn.obj", UnwindBB); 275 276 // Extract the exception object from the ResumeInst and add it to the PHI node 277 // that feeds the _Unwind_Resume call. 278 for (ResumeInst *RI : Resumes) { 279 BasicBlock *Parent = RI->getParent(); 280 BranchInst::Create(UnwindBB, Parent); 281 Updates.push_back({DominatorTree::Insert, Parent, UnwindBB}); 282 283 Value *ExnObj = GetExceptionObject(RI); 284 PN->addIncoming(ExnObj, Parent); 285 286 ++NumResumesLowered; 287 } 288 289 if (DoesRewindFunctionNeedExceptionObject) 290 RewindFunctionArgs.push_back(PN); 291 292 // Call the function. 293 CallInst *CI = 294 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB); 295 // The verifier requires that all calls of debug-info-bearing functions 296 // from debug-info-bearing functions have a debug location (for inlining 297 // purposes). Assign a dummy location to satisfy the constraint. 298 Function *RewindFn = dyn_cast<Function>(RewindFunction.getCallee()); 299 if (RewindFn && RewindFn->getSubprogram()) 300 if (DISubprogram *SP = F.getSubprogram()) 301 CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, SP)); 302 CI->setCallingConv(RewindFunctionCallingConv); 303 304 // We never expect _Unwind_Resume to return. 305 CI->setDoesNotReturn(); 306 new UnreachableInst(Ctx, UnwindBB); 307 308 if (DTU) 309 DTU->applyUpdates(Updates); 310 311 return true; 312 } 313 314 bool DwarfEHPrepare::run() { 315 bool Changed = InsertUnwindResumeCalls(); 316 317 return Changed; 318 } 319 320 static bool prepareDwarfEH(CodeGenOptLevel OptLevel, Function &F, 321 const TargetLowering &TLI, DominatorTree *DT, 322 const TargetTransformInfo *TTI, 323 const Triple &TargetTriple) { 324 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); 325 326 return DwarfEHPrepare(OptLevel, F, TLI, DT ? &DTU : nullptr, TTI, 327 TargetTriple) 328 .run(); 329 } 330 331 namespace { 332 333 class DwarfEHPrepareLegacyPass : public FunctionPass { 334 335 CodeGenOptLevel OptLevel; 336 337 public: 338 static char ID; // Pass identification, replacement for typeid. 339 340 DwarfEHPrepareLegacyPass(CodeGenOptLevel OptLevel = CodeGenOptLevel::Default) 341 : FunctionPass(ID), OptLevel(OptLevel) {} 342 343 bool runOnFunction(Function &F) override { 344 const TargetMachine &TM = 345 getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 346 const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering(); 347 DominatorTree *DT = nullptr; 348 const TargetTransformInfo *TTI = nullptr; 349 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) 350 DT = &DTWP->getDomTree(); 351 if (OptLevel != CodeGenOptLevel::None) { 352 if (!DT) 353 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 354 TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); 355 } 356 return prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM.getTargetTriple()); 357 } 358 359 void getAnalysisUsage(AnalysisUsage &AU) const override { 360 AU.addRequired<TargetPassConfig>(); 361 AU.addRequired<TargetTransformInfoWrapperPass>(); 362 if (OptLevel != CodeGenOptLevel::None) { 363 AU.addRequired<DominatorTreeWrapperPass>(); 364 AU.addRequired<TargetTransformInfoWrapperPass>(); 365 } 366 AU.addPreserved<DominatorTreeWrapperPass>(); 367 } 368 369 StringRef getPassName() const override { 370 return "Exception handling preparation"; 371 } 372 }; 373 374 } // end anonymous namespace 375 376 PreservedAnalyses DwarfEHPreparePass::run(Function &F, 377 FunctionAnalysisManager &FAM) { 378 const auto &TLI = *TM->getSubtargetImpl(F)->getTargetLowering(); 379 auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F); 380 const TargetTransformInfo *TTI = nullptr; 381 auto OptLevel = TM->getOptLevel(); 382 if (OptLevel != CodeGenOptLevel::None) { 383 if (!DT) 384 DT = &FAM.getResult<DominatorTreeAnalysis>(F); 385 TTI = &FAM.getResult<TargetIRAnalysis>(F); 386 } 387 bool Changed = 388 prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM->getTargetTriple()); 389 390 if (!Changed) 391 return PreservedAnalyses::all(); 392 PreservedAnalyses PA; 393 PA.preserve<DominatorTreeAnalysis>(); 394 return PA; 395 } 396 397 char DwarfEHPrepareLegacyPass::ID = 0; 398 399 INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE, 400 "Prepare DWARF exceptions", false, false) 401 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 402 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 403 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 404 INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE, 405 "Prepare DWARF exceptions", false, false) 406 407 FunctionPass *llvm::createDwarfEHPass(CodeGenOptLevel OptLevel) { 408 return new DwarfEHPrepareLegacyPass(OptLevel); 409 } 410