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