10b57cec5SDimitry Andric //===- DwarfEHPrepare - Prepare exception handling for code generation ----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass mulches exception handling code into a form adapted to code 100b57cec5SDimitry Andric // generation. Required if using dwarf exception handling. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 150b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 160b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 170b57cec5SDimitry Andric #include "llvm/Analysis/CFG.h" 180b57cec5SDimitry Andric #include "llvm/Analysis/EHPersonalities.h" 190b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 240b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h" 250b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 260b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 270b57cec5SDimitry Andric #include "llvm/IR/Dominators.h" 280b57cec5SDimitry Andric #include "llvm/IR/Function.h" 290b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 300b57cec5SDimitry Andric #include "llvm/IR/Module.h" 310b57cec5SDimitry Andric #include "llvm/IR/Type.h" 32480093f4SDimitry Andric #include "llvm/InitializePasses.h" 330b57cec5SDimitry Andric #include "llvm/Pass.h" 340b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 350b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 36480093f4SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 370b57cec5SDimitry Andric #include <cstddef> 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric using namespace llvm; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric #define DEBUG_TYPE "dwarfehprepare" 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric STATISTIC(NumResumesLowered, "Number of resume calls lowered"); 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric namespace { 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric class DwarfEHPrepare : public FunctionPass { 480b57cec5SDimitry Andric // RewindFunction - _Unwind_Resume or the target equivalent. 490b57cec5SDimitry Andric FunctionCallee RewindFunction = nullptr; 500b57cec5SDimitry Andric 51*5ffd83dbSDimitry Andric CodeGenOpt::Level OptLevel; 520b57cec5SDimitry Andric DominatorTree *DT = nullptr; 530b57cec5SDimitry Andric const TargetLowering *TLI = nullptr; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric bool InsertUnwindResumeCalls(Function &Fn); 560b57cec5SDimitry Andric Value *GetExceptionObject(ResumeInst *RI); 570b57cec5SDimitry Andric size_t 580b57cec5SDimitry Andric pruneUnreachableResumes(Function &Fn, 590b57cec5SDimitry Andric SmallVectorImpl<ResumeInst *> &Resumes, 600b57cec5SDimitry Andric SmallVectorImpl<LandingPadInst *> &CleanupLPads); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric public: 630b57cec5SDimitry Andric static char ID; // Pass identification, replacement for typeid. 640b57cec5SDimitry Andric 65*5ffd83dbSDimitry Andric DwarfEHPrepare(CodeGenOpt::Level OptLevel = CodeGenOpt::Default) 66*5ffd83dbSDimitry Andric : FunctionPass(ID), OptLevel(OptLevel) {} 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric bool runOnFunction(Function &Fn) override; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric bool doFinalization(Module &M) override { 710b57cec5SDimitry Andric RewindFunction = nullptr; 720b57cec5SDimitry Andric return false; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric StringRef getPassName() const override { 780b57cec5SDimitry Andric return "Exception handling preparation"; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric }; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric } // end anonymous namespace 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric char DwarfEHPrepare::ID = 0; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(DwarfEHPrepare, DEBUG_TYPE, 870b57cec5SDimitry Andric "Prepare DWARF exceptions", false, false) 880b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 890b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 900b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 910b57cec5SDimitry Andric INITIALIZE_PASS_END(DwarfEHPrepare, DEBUG_TYPE, 920b57cec5SDimitry Andric "Prepare DWARF exceptions", false, false) 930b57cec5SDimitry Andric 94*5ffd83dbSDimitry Andric FunctionPass *llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel) { 95*5ffd83dbSDimitry Andric return new DwarfEHPrepare(OptLevel); 96*5ffd83dbSDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric void DwarfEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const { 990b57cec5SDimitry Andric AU.addRequired<TargetPassConfig>(); 1000b57cec5SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>(); 101*5ffd83dbSDimitry Andric if (OptLevel != CodeGenOpt::None) 1020b57cec5SDimitry Andric AU.addRequired<DominatorTreeWrapperPass>(); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric /// GetExceptionObject - Return the exception object from the value passed into 1060b57cec5SDimitry Andric /// the 'resume' instruction (typically an aggregate). Clean up any dead 1070b57cec5SDimitry Andric /// instructions, including the 'resume' instruction. 1080b57cec5SDimitry Andric Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) { 1090b57cec5SDimitry Andric Value *V = RI->getOperand(0); 1100b57cec5SDimitry Andric Value *ExnObj = nullptr; 1110b57cec5SDimitry Andric InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V); 1120b57cec5SDimitry Andric LoadInst *SelLoad = nullptr; 1130b57cec5SDimitry Andric InsertValueInst *ExcIVI = nullptr; 1140b57cec5SDimitry Andric bool EraseIVIs = false; 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric if (SelIVI) { 1170b57cec5SDimitry Andric if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) { 1180b57cec5SDimitry Andric ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0)); 1190b57cec5SDimitry Andric if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) && 1200b57cec5SDimitry Andric ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) { 1210b57cec5SDimitry Andric ExnObj = ExcIVI->getOperand(1); 1220b57cec5SDimitry Andric SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1)); 1230b57cec5SDimitry Andric EraseIVIs = true; 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric if (!ExnObj) 1290b57cec5SDimitry Andric ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI); 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric RI->eraseFromParent(); 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric if (EraseIVIs) { 1340b57cec5SDimitry Andric if (SelIVI->use_empty()) 1350b57cec5SDimitry Andric SelIVI->eraseFromParent(); 1360b57cec5SDimitry Andric if (ExcIVI->use_empty()) 1370b57cec5SDimitry Andric ExcIVI->eraseFromParent(); 1380b57cec5SDimitry Andric if (SelLoad && SelLoad->use_empty()) 1390b57cec5SDimitry Andric SelLoad->eraseFromParent(); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric return ExnObj; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric /// Replace resumes that are not reachable from a cleanup landing pad with 1460b57cec5SDimitry Andric /// unreachable and then simplify those blocks. 1470b57cec5SDimitry Andric size_t DwarfEHPrepare::pruneUnreachableResumes( 1480b57cec5SDimitry Andric Function &Fn, SmallVectorImpl<ResumeInst *> &Resumes, 1490b57cec5SDimitry Andric SmallVectorImpl<LandingPadInst *> &CleanupLPads) { 1500b57cec5SDimitry Andric BitVector ResumeReachable(Resumes.size()); 1510b57cec5SDimitry Andric size_t ResumeIndex = 0; 1520b57cec5SDimitry Andric for (auto *RI : Resumes) { 1530b57cec5SDimitry Andric for (auto *LP : CleanupLPads) { 1540b57cec5SDimitry Andric if (isPotentiallyReachable(LP, RI, nullptr, DT)) { 1550b57cec5SDimitry Andric ResumeReachable.set(ResumeIndex); 1560b57cec5SDimitry Andric break; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric ++ResumeIndex; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric // If everything is reachable, there is no change. 1630b57cec5SDimitry Andric if (ResumeReachable.all()) 1640b57cec5SDimitry Andric return Resumes.size(); 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric const TargetTransformInfo &TTI = 1670b57cec5SDimitry Andric getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn); 1680b57cec5SDimitry Andric LLVMContext &Ctx = Fn.getContext(); 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric // Otherwise, insert unreachable instructions and call simplifycfg. 1710b57cec5SDimitry Andric size_t ResumesLeft = 0; 1720b57cec5SDimitry Andric for (size_t I = 0, E = Resumes.size(); I < E; ++I) { 1730b57cec5SDimitry Andric ResumeInst *RI = Resumes[I]; 1740b57cec5SDimitry Andric if (ResumeReachable[I]) { 1750b57cec5SDimitry Andric Resumes[ResumesLeft++] = RI; 1760b57cec5SDimitry Andric } else { 1770b57cec5SDimitry Andric BasicBlock *BB = RI->getParent(); 1780b57cec5SDimitry Andric new UnreachableInst(Ctx, RI); 1790b57cec5SDimitry Andric RI->eraseFromParent(); 1800b57cec5SDimitry Andric simplifyCFG(BB, TTI); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric Resumes.resize(ResumesLeft); 1840b57cec5SDimitry Andric return ResumesLeft; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric /// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present 1880b57cec5SDimitry Andric /// into calls to the appropriate _Unwind_Resume function. 1890b57cec5SDimitry Andric bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) { 1900b57cec5SDimitry Andric SmallVector<ResumeInst*, 16> Resumes; 1910b57cec5SDimitry Andric SmallVector<LandingPadInst*, 16> CleanupLPads; 1920b57cec5SDimitry Andric for (BasicBlock &BB : Fn) { 1930b57cec5SDimitry Andric if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator())) 1940b57cec5SDimitry Andric Resumes.push_back(RI); 1950b57cec5SDimitry Andric if (auto *LP = BB.getLandingPadInst()) 1960b57cec5SDimitry Andric if (LP->isCleanup()) 1970b57cec5SDimitry Andric CleanupLPads.push_back(LP); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric if (Resumes.empty()) 2010b57cec5SDimitry Andric return false; 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric // Check the personality, don't do anything if it's scope-based. 2040b57cec5SDimitry Andric EHPersonality Pers = classifyEHPersonality(Fn.getPersonalityFn()); 2050b57cec5SDimitry Andric if (isScopedEHPersonality(Pers)) 2060b57cec5SDimitry Andric return false; 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric LLVMContext &Ctx = Fn.getContext(); 2090b57cec5SDimitry Andric 210*5ffd83dbSDimitry Andric size_t ResumesLeft = Resumes.size(); 211*5ffd83dbSDimitry Andric if (OptLevel != CodeGenOpt::None) 212*5ffd83dbSDimitry Andric ResumesLeft = pruneUnreachableResumes(Fn, Resumes, CleanupLPads); 213*5ffd83dbSDimitry Andric 2140b57cec5SDimitry Andric if (ResumesLeft == 0) 2150b57cec5SDimitry Andric return true; // We pruned them all. 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric // Find the rewind function if we didn't already. 2180b57cec5SDimitry Andric if (!RewindFunction) { 2190b57cec5SDimitry Andric FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), 2200b57cec5SDimitry Andric Type::getInt8PtrTy(Ctx), false); 2210b57cec5SDimitry Andric const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME); 2220b57cec5SDimitry Andric RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy); 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric // Create the basic block where the _Unwind_Resume call will live. 2260b57cec5SDimitry Andric if (ResumesLeft == 1) { 2270b57cec5SDimitry Andric // Instead of creating a new BB and PHI node, just append the call to 2280b57cec5SDimitry Andric // _Unwind_Resume to the end of the single resume block. 2290b57cec5SDimitry Andric ResumeInst *RI = Resumes.front(); 2300b57cec5SDimitry Andric BasicBlock *UnwindBB = RI->getParent(); 2310b57cec5SDimitry Andric Value *ExnObj = GetExceptionObject(RI); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric // Call the _Unwind_Resume function. 2340b57cec5SDimitry Andric CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB); 2350b57cec5SDimitry Andric CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric // We never expect _Unwind_Resume to return. 2380b57cec5SDimitry Andric new UnreachableInst(Ctx, UnwindBB); 2390b57cec5SDimitry Andric return true; 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn); 2430b57cec5SDimitry Andric PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft, 2440b57cec5SDimitry Andric "exn.obj", UnwindBB); 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric // Extract the exception object from the ResumeInst and add it to the PHI node 2470b57cec5SDimitry Andric // that feeds the _Unwind_Resume call. 2480b57cec5SDimitry Andric for (ResumeInst *RI : Resumes) { 2490b57cec5SDimitry Andric BasicBlock *Parent = RI->getParent(); 2500b57cec5SDimitry Andric BranchInst::Create(UnwindBB, Parent); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric Value *ExnObj = GetExceptionObject(RI); 2530b57cec5SDimitry Andric PN->addIncoming(ExnObj, Parent); 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric ++NumResumesLowered; 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric // Call the function. 2590b57cec5SDimitry Andric CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB); 2600b57cec5SDimitry Andric CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric // We never expect _Unwind_Resume to return. 2630b57cec5SDimitry Andric new UnreachableInst(Ctx, UnwindBB); 2640b57cec5SDimitry Andric return true; 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric bool DwarfEHPrepare::runOnFunction(Function &Fn) { 2680b57cec5SDimitry Andric const TargetMachine &TM = 2690b57cec5SDimitry Andric getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 270*5ffd83dbSDimitry Andric DT = OptLevel != CodeGenOpt::None 271*5ffd83dbSDimitry Andric ? &getAnalysis<DominatorTreeWrapperPass>().getDomTree() : nullptr; 2720b57cec5SDimitry Andric TLI = TM.getSubtargetImpl(Fn)->getTargetLowering(); 2730b57cec5SDimitry Andric bool Changed = InsertUnwindResumeCalls(Fn); 2740b57cec5SDimitry Andric DT = nullptr; 2750b57cec5SDimitry Andric TLI = nullptr; 2760b57cec5SDimitry Andric return Changed; 2770b57cec5SDimitry Andric } 278