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
145f757f3fSDimitry Andric #include "llvm/CodeGen/DwarfEHPrepare.h"
150b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
160b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
170b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
180b57cec5SDimitry Andric #include "llvm/Analysis/CFG.h"
19e8d8bef9SDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h"
200b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
210fca6ea1SDimitry Andric #include "llvm/CodeGen/RuntimeLibcallUtil.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
250b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
260b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
276246ae0bSDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
280b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
290b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
3006c3fb27SDimitry Andric #include "llvm/IR/EHPersonalities.h"
310b57cec5SDimitry Andric #include "llvm/IR/Function.h"
320b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
330b57cec5SDimitry Andric #include "llvm/IR/Module.h"
340b57cec5SDimitry Andric #include "llvm/IR/Type.h"
35480093f4SDimitry Andric #include "llvm/InitializePasses.h"
360b57cec5SDimitry Andric #include "llvm/Pass.h"
370b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
380b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
3906c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
40480093f4SDimitry Andric #include "llvm/Transforms/Utils/Local.h"
410b57cec5SDimitry Andric #include <cstddef>
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric using namespace llvm;
440b57cec5SDimitry Andric
455f757f3fSDimitry Andric #define DEBUG_TYPE "dwarf-eh-prepare"
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric STATISTIC(NumResumesLowered, "Number of resume calls lowered");
48fe6060f1SDimitry Andric STATISTIC(NumCleanupLandingPadsUnreachable,
49fe6060f1SDimitry Andric "Number of cleanup landing pads found unreachable");
50fe6060f1SDimitry Andric STATISTIC(NumCleanupLandingPadsRemaining,
51fe6060f1SDimitry Andric "Number of cleanup landing pads remaining");
52fe6060f1SDimitry Andric STATISTIC(NumNoUnwind, "Number of functions with nounwind");
53fe6060f1SDimitry Andric STATISTIC(NumUnwind, "Number of functions with unwind");
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric namespace {
560b57cec5SDimitry Andric
57e8d8bef9SDimitry Andric class DwarfEHPrepare {
585f757f3fSDimitry Andric CodeGenOptLevel OptLevel;
590b57cec5SDimitry Andric
60e8d8bef9SDimitry Andric Function &F;
61e8d8bef9SDimitry Andric const TargetLowering &TLI;
62e8d8bef9SDimitry Andric DomTreeUpdater *DTU;
63e8d8bef9SDimitry Andric const TargetTransformInfo *TTI;
64349cc55cSDimitry Andric const Triple &TargetTriple;
650b57cec5SDimitry Andric
66e8d8bef9SDimitry Andric /// Return the exception object from the value passed into
670b57cec5SDimitry Andric /// the 'resume' instruction (typically an aggregate). Clean up any dead
680b57cec5SDimitry Andric /// instructions, including the 'resume' instruction.
69e8d8bef9SDimitry Andric Value *GetExceptionObject(ResumeInst *RI);
70e8d8bef9SDimitry Andric
71e8d8bef9SDimitry Andric /// Replace resumes that are not reachable from a cleanup landing pad with
72e8d8bef9SDimitry Andric /// unreachable and then simplify those blocks.
73e8d8bef9SDimitry Andric size_t
74e8d8bef9SDimitry Andric pruneUnreachableResumes(SmallVectorImpl<ResumeInst *> &Resumes,
75e8d8bef9SDimitry Andric SmallVectorImpl<LandingPadInst *> &CleanupLPads);
76e8d8bef9SDimitry Andric
77e8d8bef9SDimitry Andric /// Convert the ResumeInsts that are still present
78e8d8bef9SDimitry Andric /// into calls to the appropriate _Unwind_Resume function.
79e8d8bef9SDimitry Andric bool InsertUnwindResumeCalls();
80e8d8bef9SDimitry Andric
81e8d8bef9SDimitry Andric public:
DwarfEHPrepare(CodeGenOptLevel OptLevel_,Function & F_,const TargetLowering & TLI_,DomTreeUpdater * DTU_,const TargetTransformInfo * TTI_,const Triple & TargetTriple_)825f757f3fSDimitry Andric DwarfEHPrepare(CodeGenOptLevel OptLevel_, Function &F_,
83349cc55cSDimitry Andric const TargetLowering &TLI_, DomTreeUpdater *DTU_,
84349cc55cSDimitry Andric const TargetTransformInfo *TTI_, const Triple &TargetTriple_)
85349cc55cSDimitry Andric : OptLevel(OptLevel_), F(F_), TLI(TLI_), DTU(DTU_), TTI(TTI_),
86349cc55cSDimitry Andric TargetTriple(TargetTriple_) {}
87e8d8bef9SDimitry Andric
88e8d8bef9SDimitry Andric bool run();
89e8d8bef9SDimitry Andric };
90e8d8bef9SDimitry Andric
91e8d8bef9SDimitry Andric } // namespace
92e8d8bef9SDimitry Andric
GetExceptionObject(ResumeInst * RI)930b57cec5SDimitry Andric Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
940b57cec5SDimitry Andric Value *V = RI->getOperand(0);
950b57cec5SDimitry Andric Value *ExnObj = nullptr;
960b57cec5SDimitry Andric InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
970b57cec5SDimitry Andric LoadInst *SelLoad = nullptr;
980b57cec5SDimitry Andric InsertValueInst *ExcIVI = nullptr;
990b57cec5SDimitry Andric bool EraseIVIs = false;
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric if (SelIVI) {
1020b57cec5SDimitry Andric if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
1030b57cec5SDimitry Andric ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
1040b57cec5SDimitry Andric if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
1050b57cec5SDimitry Andric ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
1060b57cec5SDimitry Andric ExnObj = ExcIVI->getOperand(1);
1070b57cec5SDimitry Andric SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
1080b57cec5SDimitry Andric EraseIVIs = true;
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric if (!ExnObj)
1140fca6ea1SDimitry Andric ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj",
1150fca6ea1SDimitry Andric RI->getIterator());
1160b57cec5SDimitry Andric
1170b57cec5SDimitry Andric RI->eraseFromParent();
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric if (EraseIVIs) {
1200b57cec5SDimitry Andric if (SelIVI->use_empty())
1210b57cec5SDimitry Andric SelIVI->eraseFromParent();
1220b57cec5SDimitry Andric if (ExcIVI->use_empty())
1230b57cec5SDimitry Andric ExcIVI->eraseFromParent();
1240b57cec5SDimitry Andric if (SelLoad && SelLoad->use_empty())
1250b57cec5SDimitry Andric SelLoad->eraseFromParent();
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric return ExnObj;
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
pruneUnreachableResumes(SmallVectorImpl<ResumeInst * > & Resumes,SmallVectorImpl<LandingPadInst * > & CleanupLPads)1310b57cec5SDimitry Andric size_t DwarfEHPrepare::pruneUnreachableResumes(
132e8d8bef9SDimitry Andric SmallVectorImpl<ResumeInst *> &Resumes,
1330b57cec5SDimitry Andric SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
134e8d8bef9SDimitry Andric assert(DTU && "Should have DomTreeUpdater here.");
135e8d8bef9SDimitry Andric
1360b57cec5SDimitry Andric BitVector ResumeReachable(Resumes.size());
1370b57cec5SDimitry Andric size_t ResumeIndex = 0;
1380b57cec5SDimitry Andric for (auto *RI : Resumes) {
1390b57cec5SDimitry Andric for (auto *LP : CleanupLPads) {
140e8d8bef9SDimitry Andric if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) {
1410b57cec5SDimitry Andric ResumeReachable.set(ResumeIndex);
1420b57cec5SDimitry Andric break;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric ++ResumeIndex;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andric // If everything is reachable, there is no change.
1490b57cec5SDimitry Andric if (ResumeReachable.all())
1500b57cec5SDimitry Andric return Resumes.size();
1510b57cec5SDimitry Andric
152e8d8bef9SDimitry Andric LLVMContext &Ctx = F.getContext();
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric // Otherwise, insert unreachable instructions and call simplifycfg.
1550b57cec5SDimitry Andric size_t ResumesLeft = 0;
1560b57cec5SDimitry Andric for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
1570b57cec5SDimitry Andric ResumeInst *RI = Resumes[I];
1580b57cec5SDimitry Andric if (ResumeReachable[I]) {
1590b57cec5SDimitry Andric Resumes[ResumesLeft++] = RI;
1600b57cec5SDimitry Andric } else {
1610b57cec5SDimitry Andric BasicBlock *BB = RI->getParent();
1620fca6ea1SDimitry Andric new UnreachableInst(Ctx, RI->getIterator());
1630b57cec5SDimitry Andric RI->eraseFromParent();
164fe6060f1SDimitry Andric simplifyCFG(BB, *TTI, DTU);
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric Resumes.resize(ResumesLeft);
1680b57cec5SDimitry Andric return ResumesLeft;
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric
InsertUnwindResumeCalls()171e8d8bef9SDimitry Andric bool DwarfEHPrepare::InsertUnwindResumeCalls() {
1720b57cec5SDimitry Andric SmallVector<ResumeInst *, 16> Resumes;
1730b57cec5SDimitry Andric SmallVector<LandingPadInst *, 16> CleanupLPads;
174fe6060f1SDimitry Andric if (F.doesNotThrow())
175fe6060f1SDimitry Andric NumNoUnwind++;
176fe6060f1SDimitry Andric else
177fe6060f1SDimitry Andric NumUnwind++;
178e8d8bef9SDimitry Andric for (BasicBlock &BB : F) {
1790b57cec5SDimitry Andric if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
1800b57cec5SDimitry Andric Resumes.push_back(RI);
1810b57cec5SDimitry Andric if (auto *LP = BB.getLandingPadInst())
1820b57cec5SDimitry Andric if (LP->isCleanup())
1830b57cec5SDimitry Andric CleanupLPads.push_back(LP);
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric
186fe6060f1SDimitry Andric NumCleanupLandingPadsRemaining += CleanupLPads.size();
187fe6060f1SDimitry Andric
1880b57cec5SDimitry Andric if (Resumes.empty())
1890b57cec5SDimitry Andric return false;
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric // Check the personality, don't do anything if it's scope-based.
192e8d8bef9SDimitry Andric EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn());
1930b57cec5SDimitry Andric if (isScopedEHPersonality(Pers))
1940b57cec5SDimitry Andric return false;
1950b57cec5SDimitry Andric
196e8d8bef9SDimitry Andric LLVMContext &Ctx = F.getContext();
1970b57cec5SDimitry Andric
1985ffd83dbSDimitry Andric size_t ResumesLeft = Resumes.size();
1995f757f3fSDimitry Andric if (OptLevel != CodeGenOptLevel::None) {
200e8d8bef9SDimitry Andric ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads);
201fe6060f1SDimitry Andric #if LLVM_ENABLE_STATS
202fe6060f1SDimitry Andric unsigned NumRemainingLPs = 0;
203fe6060f1SDimitry Andric for (BasicBlock &BB : F) {
204fe6060f1SDimitry Andric if (auto *LP = BB.getLandingPadInst())
205fe6060f1SDimitry Andric if (LP->isCleanup())
206fe6060f1SDimitry Andric NumRemainingLPs++;
207fe6060f1SDimitry Andric }
208fe6060f1SDimitry Andric NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs;
209fe6060f1SDimitry Andric NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs;
210fe6060f1SDimitry Andric #endif
211fe6060f1SDimitry Andric }
2125ffd83dbSDimitry Andric
2130b57cec5SDimitry Andric if (ResumesLeft == 0)
2140b57cec5SDimitry Andric return true; // We pruned them all.
2150b57cec5SDimitry Andric
216349cc55cSDimitry Andric // RewindFunction - _Unwind_Resume or the target equivalent.
217349cc55cSDimitry Andric FunctionCallee RewindFunction;
218349cc55cSDimitry Andric CallingConv::ID RewindFunctionCallingConv;
219349cc55cSDimitry Andric FunctionType *FTy;
220349cc55cSDimitry Andric const char *RewindName;
221349cc55cSDimitry Andric bool DoesRewindFunctionNeedExceptionObject;
222349cc55cSDimitry Andric
223349cc55cSDimitry Andric if ((Pers == EHPersonality::GNU_CXX || Pers == EHPersonality::GNU_CXX_SjLj) &&
224349cc55cSDimitry Andric TargetTriple.isTargetEHABICompatible()) {
225349cc55cSDimitry Andric RewindName = TLI.getLibcallName(RTLIB::CXA_END_CLEANUP);
226349cc55cSDimitry Andric FTy = FunctionType::get(Type::getVoidTy(Ctx), false);
227349cc55cSDimitry Andric RewindFunctionCallingConv =
228349cc55cSDimitry Andric TLI.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP);
229349cc55cSDimitry Andric DoesRewindFunctionNeedExceptionObject = false;
230349cc55cSDimitry Andric } else {
231349cc55cSDimitry Andric RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
2325f757f3fSDimitry Andric FTy = FunctionType::get(Type::getVoidTy(Ctx), PointerType::getUnqual(Ctx),
2335f757f3fSDimitry Andric false);
234349cc55cSDimitry Andric RewindFunctionCallingConv = TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME);
235349cc55cSDimitry Andric DoesRewindFunctionNeedExceptionObject = true;
2360b57cec5SDimitry Andric }
237349cc55cSDimitry Andric RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy);
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric // Create the basic block where the _Unwind_Resume call will live.
2400b57cec5SDimitry Andric if (ResumesLeft == 1) {
2410b57cec5SDimitry Andric // Instead of creating a new BB and PHI node, just append the call to
2420b57cec5SDimitry Andric // _Unwind_Resume to the end of the single resume block.
2430b57cec5SDimitry Andric ResumeInst *RI = Resumes.front();
2440b57cec5SDimitry Andric BasicBlock *UnwindBB = RI->getParent();
2450b57cec5SDimitry Andric Value *ExnObj = GetExceptionObject(RI);
246349cc55cSDimitry Andric llvm::SmallVector<Value *, 1> RewindFunctionArgs;
247349cc55cSDimitry Andric if (DoesRewindFunctionNeedExceptionObject)
248349cc55cSDimitry Andric RewindFunctionArgs.push_back(ExnObj);
2490b57cec5SDimitry Andric
250349cc55cSDimitry Andric // Call the rewind function.
251349cc55cSDimitry Andric CallInst *CI =
252349cc55cSDimitry Andric CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
2536246ae0bSDimitry Andric // The verifier requires that all calls of debug-info-bearing functions
2546246ae0bSDimitry Andric // from debug-info-bearing functions have a debug location (for inlining
2556246ae0bSDimitry Andric // purposes). Assign a dummy location to satisfy the constraint.
2566246ae0bSDimitry Andric Function *RewindFn = dyn_cast<Function>(RewindFunction.getCallee());
2576246ae0bSDimitry Andric if (RewindFn && RewindFn->getSubprogram())
2586246ae0bSDimitry Andric if (DISubprogram *SP = F.getSubprogram())
2596246ae0bSDimitry Andric CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, SP));
260349cc55cSDimitry Andric CI->setCallingConv(RewindFunctionCallingConv);
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric // We never expect _Unwind_Resume to return.
263e8d8bef9SDimitry Andric CI->setDoesNotReturn();
2640b57cec5SDimitry Andric new UnreachableInst(Ctx, UnwindBB);
2650b57cec5SDimitry Andric return true;
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric
268e8d8bef9SDimitry Andric std::vector<DominatorTree::UpdateType> Updates;
269e8d8bef9SDimitry Andric Updates.reserve(Resumes.size());
270e8d8bef9SDimitry Andric
271349cc55cSDimitry Andric llvm::SmallVector<Value *, 1> RewindFunctionArgs;
272349cc55cSDimitry Andric
273e8d8bef9SDimitry Andric BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
2745f757f3fSDimitry Andric PHINode *PN = PHINode::Create(PointerType::getUnqual(Ctx), ResumesLeft,
2755f757f3fSDimitry Andric "exn.obj", UnwindBB);
2760b57cec5SDimitry Andric
2770b57cec5SDimitry Andric // Extract the exception object from the ResumeInst and add it to the PHI node
2780b57cec5SDimitry Andric // that feeds the _Unwind_Resume call.
2790b57cec5SDimitry Andric for (ResumeInst *RI : Resumes) {
2800b57cec5SDimitry Andric BasicBlock *Parent = RI->getParent();
2810b57cec5SDimitry Andric BranchInst::Create(UnwindBB, Parent);
282e8d8bef9SDimitry Andric Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
2830b57cec5SDimitry Andric
2840b57cec5SDimitry Andric Value *ExnObj = GetExceptionObject(RI);
2850b57cec5SDimitry Andric PN->addIncoming(ExnObj, Parent);
2860b57cec5SDimitry Andric
2870b57cec5SDimitry Andric ++NumResumesLowered;
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric
290349cc55cSDimitry Andric if (DoesRewindFunctionNeedExceptionObject)
291349cc55cSDimitry Andric RewindFunctionArgs.push_back(PN);
292349cc55cSDimitry Andric
2930b57cec5SDimitry Andric // Call the function.
294349cc55cSDimitry Andric CallInst *CI =
295349cc55cSDimitry Andric CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
296*6c4b055cSDimitry Andric // The verifier requires that all calls of debug-info-bearing functions
297*6c4b055cSDimitry Andric // from debug-info-bearing functions have a debug location (for inlining
298*6c4b055cSDimitry Andric // purposes). Assign a dummy location to satisfy the constraint.
299*6c4b055cSDimitry Andric Function *RewindFn = dyn_cast<Function>(RewindFunction.getCallee());
300*6c4b055cSDimitry Andric if (RewindFn && RewindFn->getSubprogram())
301*6c4b055cSDimitry Andric if (DISubprogram *SP = F.getSubprogram())
302*6c4b055cSDimitry Andric CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, SP));
303349cc55cSDimitry Andric CI->setCallingConv(RewindFunctionCallingConv);
3040b57cec5SDimitry Andric
3050b57cec5SDimitry Andric // We never expect _Unwind_Resume to return.
306e8d8bef9SDimitry Andric CI->setDoesNotReturn();
3070b57cec5SDimitry Andric new UnreachableInst(Ctx, UnwindBB);
308e8d8bef9SDimitry Andric
309fe6060f1SDimitry Andric if (DTU)
310e8d8bef9SDimitry Andric DTU->applyUpdates(Updates);
311e8d8bef9SDimitry Andric
3120b57cec5SDimitry Andric return true;
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric
run()315e8d8bef9SDimitry Andric bool DwarfEHPrepare::run() {
316e8d8bef9SDimitry Andric bool Changed = InsertUnwindResumeCalls();
317e8d8bef9SDimitry Andric
318e8d8bef9SDimitry Andric return Changed;
319e8d8bef9SDimitry Andric }
320e8d8bef9SDimitry Andric
prepareDwarfEH(CodeGenOptLevel OptLevel,Function & F,const TargetLowering & TLI,DominatorTree * DT,const TargetTransformInfo * TTI,const Triple & TargetTriple)3215f757f3fSDimitry Andric static bool prepareDwarfEH(CodeGenOptLevel OptLevel, Function &F,
322e8d8bef9SDimitry Andric const TargetLowering &TLI, DominatorTree *DT,
323349cc55cSDimitry Andric const TargetTransformInfo *TTI,
324349cc55cSDimitry Andric const Triple &TargetTriple) {
325fe6060f1SDimitry Andric DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
326e8d8bef9SDimitry Andric
327349cc55cSDimitry Andric return DwarfEHPrepare(OptLevel, F, TLI, DT ? &DTU : nullptr, TTI,
328349cc55cSDimitry Andric TargetTriple)
329e8d8bef9SDimitry Andric .run();
330e8d8bef9SDimitry Andric }
331e8d8bef9SDimitry Andric
332e8d8bef9SDimitry Andric namespace {
333e8d8bef9SDimitry Andric
334e8d8bef9SDimitry Andric class DwarfEHPrepareLegacyPass : public FunctionPass {
335e8d8bef9SDimitry Andric
3365f757f3fSDimitry Andric CodeGenOptLevel OptLevel;
337e8d8bef9SDimitry Andric
338e8d8bef9SDimitry Andric public:
339e8d8bef9SDimitry Andric static char ID; // Pass identification, replacement for typeid.
340e8d8bef9SDimitry Andric
DwarfEHPrepareLegacyPass(CodeGenOptLevel OptLevel=CodeGenOptLevel::Default)3415f757f3fSDimitry Andric DwarfEHPrepareLegacyPass(CodeGenOptLevel OptLevel = CodeGenOptLevel::Default)
342e8d8bef9SDimitry Andric : FunctionPass(ID), OptLevel(OptLevel) {}
343e8d8bef9SDimitry Andric
runOnFunction(Function & F)344e8d8bef9SDimitry Andric bool runOnFunction(Function &F) override {
3450b57cec5SDimitry Andric const TargetMachine &TM =
3460b57cec5SDimitry Andric getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
347e8d8bef9SDimitry Andric const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
348e8d8bef9SDimitry Andric DominatorTree *DT = nullptr;
349e8d8bef9SDimitry Andric const TargetTransformInfo *TTI = nullptr;
350fe6060f1SDimitry Andric if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
351fe6060f1SDimitry Andric DT = &DTWP->getDomTree();
3525f757f3fSDimitry Andric if (OptLevel != CodeGenOptLevel::None) {
353fe6060f1SDimitry Andric if (!DT)
354e8d8bef9SDimitry Andric DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
355e8d8bef9SDimitry Andric TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
356e8d8bef9SDimitry Andric }
357349cc55cSDimitry Andric return prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM.getTargetTriple());
358e8d8bef9SDimitry Andric }
359e8d8bef9SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const360e8d8bef9SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
361e8d8bef9SDimitry Andric AU.addRequired<TargetPassConfig>();
362e8d8bef9SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>();
3635f757f3fSDimitry Andric if (OptLevel != CodeGenOptLevel::None) {
364e8d8bef9SDimitry Andric AU.addRequired<DominatorTreeWrapperPass>();
365e8d8bef9SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>();
366e8d8bef9SDimitry Andric }
367fe6060f1SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>();
368e8d8bef9SDimitry Andric }
369e8d8bef9SDimitry Andric
getPassName() const370e8d8bef9SDimitry Andric StringRef getPassName() const override {
371e8d8bef9SDimitry Andric return "Exception handling preparation";
372e8d8bef9SDimitry Andric }
373e8d8bef9SDimitry Andric };
374e8d8bef9SDimitry Andric
375e8d8bef9SDimitry Andric } // end anonymous namespace
376e8d8bef9SDimitry Andric
run(Function & F,FunctionAnalysisManager & FAM)3775f757f3fSDimitry Andric PreservedAnalyses DwarfEHPreparePass::run(Function &F,
3785f757f3fSDimitry Andric FunctionAnalysisManager &FAM) {
3795f757f3fSDimitry Andric const auto &TLI = *TM->getSubtargetImpl(F)->getTargetLowering();
3805f757f3fSDimitry Andric auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
3815f757f3fSDimitry Andric const TargetTransformInfo *TTI = nullptr;
3825f757f3fSDimitry Andric auto OptLevel = TM->getOptLevel();
3835f757f3fSDimitry Andric if (OptLevel != CodeGenOptLevel::None) {
3845f757f3fSDimitry Andric if (!DT)
3855f757f3fSDimitry Andric DT = &FAM.getResult<DominatorTreeAnalysis>(F);
3865f757f3fSDimitry Andric TTI = &FAM.getResult<TargetIRAnalysis>(F);
3875f757f3fSDimitry Andric }
3885f757f3fSDimitry Andric bool Changed =
3895f757f3fSDimitry Andric prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM->getTargetTriple());
3905f757f3fSDimitry Andric
3915f757f3fSDimitry Andric if (!Changed)
3925f757f3fSDimitry Andric return PreservedAnalyses::all();
3935f757f3fSDimitry Andric PreservedAnalyses PA;
3945f757f3fSDimitry Andric PA.preserve<DominatorTreeAnalysis>();
3955f757f3fSDimitry Andric return PA;
3965f757f3fSDimitry Andric }
3975f757f3fSDimitry Andric
398e8d8bef9SDimitry Andric char DwarfEHPrepareLegacyPass::ID = 0;
399e8d8bef9SDimitry Andric
400e8d8bef9SDimitry Andric INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
401e8d8bef9SDimitry Andric "Prepare DWARF exceptions", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)402e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
403e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
404e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
405e8d8bef9SDimitry Andric INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
406e8d8bef9SDimitry Andric "Prepare DWARF exceptions", false, false)
407e8d8bef9SDimitry Andric
4085f757f3fSDimitry Andric FunctionPass *llvm::createDwarfEHPass(CodeGenOptLevel OptLevel) {
409e8d8bef9SDimitry Andric return new DwarfEHPrepareLegacyPass(OptLevel);
4100b57cec5SDimitry Andric }
411