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