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