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/DomTreeUpdater.h" 19 #include "llvm/Analysis/EHPersonalities.h" 20 #include "llvm/Analysis/TargetTransformInfo.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/InitializePasses.h" 34 #include "llvm/Pass.h" 35 #include "llvm/Support/Casting.h" 36 #include "llvm/Target/TargetMachine.h" 37 #include "llvm/Transforms/Utils/Local.h" 38 #include <cstddef> 39 40 using namespace llvm; 41 42 #define DEBUG_TYPE "dwarfehprepare" 43 44 STATISTIC(NumResumesLowered, "Number of resume calls lowered"); 45 STATISTIC(NumCleanupLandingPadsUnreachable, 46 "Number of cleanup landing pads found unreachable"); 47 STATISTIC(NumCleanupLandingPadsRemaining, 48 "Number of cleanup landing pads remaining"); 49 STATISTIC(NumNoUnwind, "Number of functions with nounwind"); 50 STATISTIC(NumUnwind, "Number of functions with unwind"); 51 52 namespace { 53 54 class DwarfEHPrepare { 55 CodeGenOpt::Level OptLevel; 56 57 // RewindFunction - _Unwind_Resume or the target equivalent. 58 FunctionCallee &RewindFunction; 59 60 Function &F; 61 const TargetLowering &TLI; 62 DomTreeUpdater *DTU; 63 const TargetTransformInfo *TTI; 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(CodeGenOpt::Level OptLevel_, FunctionCallee &RewindFunction_, 82 Function &F_, const TargetLowering &TLI_, DomTreeUpdater *DTU_, 83 const TargetTransformInfo *TTI_) 84 : OptLevel(OptLevel_), RewindFunction(RewindFunction_), F(F_), TLI(TLI_), 85 DTU(DTU_), TTI(TTI_) {} 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", RI); 114 115 RI->eraseFromParent(); 116 117 if (EraseIVIs) { 118 if (SelIVI->use_empty()) 119 SelIVI->eraseFromParent(); 120 if (ExcIVI->use_empty()) 121 ExcIVI->eraseFromParent(); 122 if (SelLoad && SelLoad->use_empty()) 123 SelLoad->eraseFromParent(); 124 } 125 126 return ExnObj; 127 } 128 129 size_t DwarfEHPrepare::pruneUnreachableResumes( 130 SmallVectorImpl<ResumeInst *> &Resumes, 131 SmallVectorImpl<LandingPadInst *> &CleanupLPads) { 132 assert(DTU && "Should have DomTreeUpdater here."); 133 134 BitVector ResumeReachable(Resumes.size()); 135 size_t ResumeIndex = 0; 136 for (auto *RI : Resumes) { 137 for (auto *LP : CleanupLPads) { 138 if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) { 139 ResumeReachable.set(ResumeIndex); 140 break; 141 } 142 } 143 ++ResumeIndex; 144 } 145 146 // If everything is reachable, there is no change. 147 if (ResumeReachable.all()) 148 return Resumes.size(); 149 150 LLVMContext &Ctx = F.getContext(); 151 152 // Otherwise, insert unreachable instructions and call simplifycfg. 153 size_t ResumesLeft = 0; 154 for (size_t I = 0, E = Resumes.size(); I < E; ++I) { 155 ResumeInst *RI = Resumes[I]; 156 if (ResumeReachable[I]) { 157 Resumes[ResumesLeft++] = RI; 158 } else { 159 BasicBlock *BB = RI->getParent(); 160 new UnreachableInst(Ctx, RI); 161 RI->eraseFromParent(); 162 simplifyCFG(BB, *TTI, DTU); 163 } 164 } 165 Resumes.resize(ResumesLeft); 166 return ResumesLeft; 167 } 168 169 bool DwarfEHPrepare::InsertUnwindResumeCalls() { 170 SmallVector<ResumeInst *, 16> Resumes; 171 SmallVector<LandingPadInst *, 16> CleanupLPads; 172 if (F.doesNotThrow()) 173 NumNoUnwind++; 174 else 175 NumUnwind++; 176 for (BasicBlock &BB : F) { 177 if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator())) 178 Resumes.push_back(RI); 179 if (auto *LP = BB.getLandingPadInst()) 180 if (LP->isCleanup()) 181 CleanupLPads.push_back(LP); 182 } 183 184 NumCleanupLandingPadsRemaining += CleanupLPads.size(); 185 186 if (Resumes.empty()) 187 return false; 188 189 // Check the personality, don't do anything if it's scope-based. 190 EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn()); 191 if (isScopedEHPersonality(Pers)) 192 return false; 193 194 LLVMContext &Ctx = F.getContext(); 195 196 size_t ResumesLeft = Resumes.size(); 197 if (OptLevel != CodeGenOpt::None) { 198 ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads); 199 #if LLVM_ENABLE_STATS 200 unsigned NumRemainingLPs = 0; 201 for (BasicBlock &BB : F) { 202 if (auto *LP = BB.getLandingPadInst()) 203 if (LP->isCleanup()) 204 NumRemainingLPs++; 205 } 206 NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs; 207 NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs; 208 #endif 209 } 210 211 if (ResumesLeft == 0) 212 return true; // We pruned them all. 213 214 // Find the rewind function if we didn't already. 215 if (!RewindFunction) { 216 FunctionType *FTy = 217 FunctionType::get(Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), false); 218 const char *RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME); 219 RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy); 220 } 221 222 // Create the basic block where the _Unwind_Resume call will live. 223 if (ResumesLeft == 1) { 224 // Instead of creating a new BB and PHI node, just append the call to 225 // _Unwind_Resume to the end of the single resume block. 226 ResumeInst *RI = Resumes.front(); 227 BasicBlock *UnwindBB = RI->getParent(); 228 Value *ExnObj = GetExceptionObject(RI); 229 230 // Call the _Unwind_Resume function. 231 CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB); 232 CI->setCallingConv(TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 233 234 // We never expect _Unwind_Resume to return. 235 CI->setDoesNotReturn(); 236 new UnreachableInst(Ctx, UnwindBB); 237 return true; 238 } 239 240 std::vector<DominatorTree::UpdateType> Updates; 241 Updates.reserve(Resumes.size()); 242 243 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F); 244 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft, "exn.obj", 245 UnwindBB); 246 247 // Extract the exception object from the ResumeInst and add it to the PHI node 248 // that feeds the _Unwind_Resume call. 249 for (ResumeInst *RI : Resumes) { 250 BasicBlock *Parent = RI->getParent(); 251 BranchInst::Create(UnwindBB, Parent); 252 Updates.push_back({DominatorTree::Insert, Parent, UnwindBB}); 253 254 Value *ExnObj = GetExceptionObject(RI); 255 PN->addIncoming(ExnObj, Parent); 256 257 ++NumResumesLowered; 258 } 259 260 // Call the function. 261 CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB); 262 CI->setCallingConv(TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 263 264 // We never expect _Unwind_Resume to return. 265 CI->setDoesNotReturn(); 266 new UnreachableInst(Ctx, UnwindBB); 267 268 if (DTU) 269 DTU->applyUpdates(Updates); 270 271 return true; 272 } 273 274 bool DwarfEHPrepare::run() { 275 bool Changed = InsertUnwindResumeCalls(); 276 277 return Changed; 278 } 279 280 static bool prepareDwarfEH(CodeGenOpt::Level OptLevel, 281 FunctionCallee &RewindFunction, Function &F, 282 const TargetLowering &TLI, DominatorTree *DT, 283 const TargetTransformInfo *TTI) { 284 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); 285 286 return DwarfEHPrepare(OptLevel, RewindFunction, F, TLI, DT ? &DTU : nullptr, 287 TTI) 288 .run(); 289 } 290 291 namespace { 292 293 class DwarfEHPrepareLegacyPass : public FunctionPass { 294 // RewindFunction - _Unwind_Resume or the target equivalent. 295 FunctionCallee RewindFunction = nullptr; 296 297 CodeGenOpt::Level OptLevel; 298 299 public: 300 static char ID; // Pass identification, replacement for typeid. 301 302 DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel = CodeGenOpt::Default) 303 : FunctionPass(ID), OptLevel(OptLevel) {} 304 305 bool runOnFunction(Function &F) override { 306 const TargetMachine &TM = 307 getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 308 const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering(); 309 DominatorTree *DT = nullptr; 310 const TargetTransformInfo *TTI = nullptr; 311 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) 312 DT = &DTWP->getDomTree(); 313 if (OptLevel != CodeGenOpt::None) { 314 if (!DT) 315 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 316 TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); 317 } 318 return prepareDwarfEH(OptLevel, RewindFunction, F, TLI, DT, TTI); 319 } 320 321 void getAnalysisUsage(AnalysisUsage &AU) const override { 322 AU.addRequired<TargetPassConfig>(); 323 AU.addRequired<TargetTransformInfoWrapperPass>(); 324 if (OptLevel != CodeGenOpt::None) { 325 AU.addRequired<DominatorTreeWrapperPass>(); 326 AU.addRequired<TargetTransformInfoWrapperPass>(); 327 } 328 AU.addPreserved<DominatorTreeWrapperPass>(); 329 } 330 331 StringRef getPassName() const override { 332 return "Exception handling preparation"; 333 } 334 }; 335 336 } // end anonymous namespace 337 338 char DwarfEHPrepareLegacyPass::ID = 0; 339 340 INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE, 341 "Prepare DWARF exceptions", false, false) 342 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 343 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 344 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 345 INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE, 346 "Prepare DWARF exceptions", false, false) 347 348 FunctionPass *llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel) { 349 return new DwarfEHPrepareLegacyPass(OptLevel); 350 } 351