xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/DwarfEHPrepare.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
14*5f757f3fSDimitry 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"
210b57cec5SDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.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 
45*5f757f3fSDimitry 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 {
58*5f757f3fSDimitry 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:
82*5f757f3fSDimitry 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 
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)
1140b57cec5SDimitry Andric     ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   RI->eraseFromParent();
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   if (EraseIVIs) {
1190b57cec5SDimitry Andric     if (SelIVI->use_empty())
1200b57cec5SDimitry Andric       SelIVI->eraseFromParent();
1210b57cec5SDimitry Andric     if (ExcIVI->use_empty())
1220b57cec5SDimitry Andric       ExcIVI->eraseFromParent();
1230b57cec5SDimitry Andric     if (SelLoad && SelLoad->use_empty())
1240b57cec5SDimitry Andric       SelLoad->eraseFromParent();
1250b57cec5SDimitry Andric   }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   return ExnObj;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric size_t DwarfEHPrepare::pruneUnreachableResumes(
131e8d8bef9SDimitry Andric     SmallVectorImpl<ResumeInst *> &Resumes,
1320b57cec5SDimitry Andric     SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
133e8d8bef9SDimitry Andric   assert(DTU && "Should have DomTreeUpdater here.");
134e8d8bef9SDimitry Andric 
1350b57cec5SDimitry Andric   BitVector ResumeReachable(Resumes.size());
1360b57cec5SDimitry Andric   size_t ResumeIndex = 0;
1370b57cec5SDimitry Andric   for (auto *RI : Resumes) {
1380b57cec5SDimitry Andric     for (auto *LP : CleanupLPads) {
139e8d8bef9SDimitry Andric       if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) {
1400b57cec5SDimitry Andric         ResumeReachable.set(ResumeIndex);
1410b57cec5SDimitry Andric         break;
1420b57cec5SDimitry Andric       }
1430b57cec5SDimitry Andric     }
1440b57cec5SDimitry Andric     ++ResumeIndex;
1450b57cec5SDimitry Andric   }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   // If everything is reachable, there is no change.
1480b57cec5SDimitry Andric   if (ResumeReachable.all())
1490b57cec5SDimitry Andric     return Resumes.size();
1500b57cec5SDimitry Andric 
151e8d8bef9SDimitry Andric   LLVMContext &Ctx = F.getContext();
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   // Otherwise, insert unreachable instructions and call simplifycfg.
1540b57cec5SDimitry Andric   size_t ResumesLeft = 0;
1550b57cec5SDimitry Andric   for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
1560b57cec5SDimitry Andric     ResumeInst *RI = Resumes[I];
1570b57cec5SDimitry Andric     if (ResumeReachable[I]) {
1580b57cec5SDimitry Andric       Resumes[ResumesLeft++] = RI;
1590b57cec5SDimitry Andric     } else {
1600b57cec5SDimitry Andric       BasicBlock *BB = RI->getParent();
1610b57cec5SDimitry Andric       new UnreachableInst(Ctx, RI);
1620b57cec5SDimitry Andric       RI->eraseFromParent();
163fe6060f1SDimitry Andric       simplifyCFG(BB, *TTI, DTU);
1640b57cec5SDimitry Andric     }
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric   Resumes.resize(ResumesLeft);
1670b57cec5SDimitry Andric   return ResumesLeft;
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
170e8d8bef9SDimitry Andric bool DwarfEHPrepare::InsertUnwindResumeCalls() {
1710b57cec5SDimitry Andric   SmallVector<ResumeInst *, 16> Resumes;
1720b57cec5SDimitry Andric   SmallVector<LandingPadInst *, 16> CleanupLPads;
173fe6060f1SDimitry Andric   if (F.doesNotThrow())
174fe6060f1SDimitry Andric     NumNoUnwind++;
175fe6060f1SDimitry Andric   else
176fe6060f1SDimitry Andric     NumUnwind++;
177e8d8bef9SDimitry Andric   for (BasicBlock &BB : F) {
1780b57cec5SDimitry Andric     if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
1790b57cec5SDimitry Andric       Resumes.push_back(RI);
1800b57cec5SDimitry Andric     if (auto *LP = BB.getLandingPadInst())
1810b57cec5SDimitry Andric       if (LP->isCleanup())
1820b57cec5SDimitry Andric         CleanupLPads.push_back(LP);
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
185fe6060f1SDimitry Andric   NumCleanupLandingPadsRemaining += CleanupLPads.size();
186fe6060f1SDimitry Andric 
1870b57cec5SDimitry Andric   if (Resumes.empty())
1880b57cec5SDimitry Andric     return false;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   // Check the personality, don't do anything if it's scope-based.
191e8d8bef9SDimitry Andric   EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn());
1920b57cec5SDimitry Andric   if (isScopedEHPersonality(Pers))
1930b57cec5SDimitry Andric     return false;
1940b57cec5SDimitry Andric 
195e8d8bef9SDimitry Andric   LLVMContext &Ctx = F.getContext();
1960b57cec5SDimitry Andric 
1975ffd83dbSDimitry Andric   size_t ResumesLeft = Resumes.size();
198*5f757f3fSDimitry Andric   if (OptLevel != CodeGenOptLevel::None) {
199e8d8bef9SDimitry Andric     ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads);
200fe6060f1SDimitry Andric #if LLVM_ENABLE_STATS
201fe6060f1SDimitry Andric     unsigned NumRemainingLPs = 0;
202fe6060f1SDimitry Andric     for (BasicBlock &BB : F) {
203fe6060f1SDimitry Andric       if (auto *LP = BB.getLandingPadInst())
204fe6060f1SDimitry Andric         if (LP->isCleanup())
205fe6060f1SDimitry Andric           NumRemainingLPs++;
206fe6060f1SDimitry Andric     }
207fe6060f1SDimitry Andric     NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs;
208fe6060f1SDimitry Andric     NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs;
209fe6060f1SDimitry Andric #endif
210fe6060f1SDimitry Andric   }
2115ffd83dbSDimitry Andric 
2120b57cec5SDimitry Andric   if (ResumesLeft == 0)
2130b57cec5SDimitry Andric     return true; // We pruned them all.
2140b57cec5SDimitry Andric 
215349cc55cSDimitry Andric   // RewindFunction - _Unwind_Resume or the target equivalent.
216349cc55cSDimitry Andric   FunctionCallee RewindFunction;
217349cc55cSDimitry Andric   CallingConv::ID RewindFunctionCallingConv;
218349cc55cSDimitry Andric   FunctionType *FTy;
219349cc55cSDimitry Andric   const char *RewindName;
220349cc55cSDimitry Andric   bool DoesRewindFunctionNeedExceptionObject;
221349cc55cSDimitry Andric 
222349cc55cSDimitry Andric   if ((Pers == EHPersonality::GNU_CXX || Pers == EHPersonality::GNU_CXX_SjLj) &&
223349cc55cSDimitry Andric       TargetTriple.isTargetEHABICompatible()) {
224349cc55cSDimitry Andric     RewindName = TLI.getLibcallName(RTLIB::CXA_END_CLEANUP);
225349cc55cSDimitry Andric     FTy = FunctionType::get(Type::getVoidTy(Ctx), false);
226349cc55cSDimitry Andric     RewindFunctionCallingConv =
227349cc55cSDimitry Andric         TLI.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP);
228349cc55cSDimitry Andric     DoesRewindFunctionNeedExceptionObject = false;
229349cc55cSDimitry Andric   } else {
230349cc55cSDimitry Andric     RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
231*5f757f3fSDimitry Andric     FTy = FunctionType::get(Type::getVoidTy(Ctx), PointerType::getUnqual(Ctx),
232*5f757f3fSDimitry Andric                             false);
233349cc55cSDimitry Andric     RewindFunctionCallingConv = TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME);
234349cc55cSDimitry Andric     DoesRewindFunctionNeedExceptionObject = true;
2350b57cec5SDimitry Andric   }
236349cc55cSDimitry Andric   RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy);
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   // Create the basic block where the _Unwind_Resume call will live.
2390b57cec5SDimitry Andric   if (ResumesLeft == 1) {
2400b57cec5SDimitry Andric     // Instead of creating a new BB and PHI node, just append the call to
2410b57cec5SDimitry Andric     // _Unwind_Resume to the end of the single resume block.
2420b57cec5SDimitry Andric     ResumeInst *RI = Resumes.front();
2430b57cec5SDimitry Andric     BasicBlock *UnwindBB = RI->getParent();
2440b57cec5SDimitry Andric     Value *ExnObj = GetExceptionObject(RI);
245349cc55cSDimitry Andric     llvm::SmallVector<Value *, 1> RewindFunctionArgs;
246349cc55cSDimitry Andric     if (DoesRewindFunctionNeedExceptionObject)
247349cc55cSDimitry Andric       RewindFunctionArgs.push_back(ExnObj);
2480b57cec5SDimitry Andric 
249349cc55cSDimitry Andric     // Call the rewind function.
250349cc55cSDimitry Andric     CallInst *CI =
251349cc55cSDimitry Andric         CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
2526246ae0bSDimitry Andric     // The verifier requires that all calls of debug-info-bearing functions
2536246ae0bSDimitry Andric     // from debug-info-bearing functions have a debug location (for inlining
2546246ae0bSDimitry Andric     // purposes). Assign a dummy location to satisfy the constraint.
2556246ae0bSDimitry Andric     Function *RewindFn = dyn_cast<Function>(RewindFunction.getCallee());
2566246ae0bSDimitry Andric     if (RewindFn && RewindFn->getSubprogram())
2576246ae0bSDimitry Andric       if (DISubprogram *SP = F.getSubprogram())
2586246ae0bSDimitry Andric         CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, SP));
259349cc55cSDimitry Andric     CI->setCallingConv(RewindFunctionCallingConv);
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric     // We never expect _Unwind_Resume to return.
262e8d8bef9SDimitry Andric     CI->setDoesNotReturn();
2630b57cec5SDimitry Andric     new UnreachableInst(Ctx, UnwindBB);
2640b57cec5SDimitry Andric     return true;
2650b57cec5SDimitry Andric   }
2660b57cec5SDimitry Andric 
267e8d8bef9SDimitry Andric   std::vector<DominatorTree::UpdateType> Updates;
268e8d8bef9SDimitry Andric   Updates.reserve(Resumes.size());
269e8d8bef9SDimitry Andric 
270349cc55cSDimitry Andric   llvm::SmallVector<Value *, 1> RewindFunctionArgs;
271349cc55cSDimitry Andric 
272e8d8bef9SDimitry Andric   BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
273*5f757f3fSDimitry Andric   PHINode *PN = PHINode::Create(PointerType::getUnqual(Ctx), ResumesLeft,
274*5f757f3fSDimitry Andric                                 "exn.obj", UnwindBB);
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   // Extract the exception object from the ResumeInst and add it to the PHI node
2770b57cec5SDimitry Andric   // that feeds the _Unwind_Resume call.
2780b57cec5SDimitry Andric   for (ResumeInst *RI : Resumes) {
2790b57cec5SDimitry Andric     BasicBlock *Parent = RI->getParent();
2800b57cec5SDimitry Andric     BranchInst::Create(UnwindBB, Parent);
281e8d8bef9SDimitry Andric     Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric     Value *ExnObj = GetExceptionObject(RI);
2840b57cec5SDimitry Andric     PN->addIncoming(ExnObj, Parent);
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric     ++NumResumesLowered;
2870b57cec5SDimitry Andric   }
2880b57cec5SDimitry Andric 
289349cc55cSDimitry Andric   if (DoesRewindFunctionNeedExceptionObject)
290349cc55cSDimitry Andric     RewindFunctionArgs.push_back(PN);
291349cc55cSDimitry Andric 
2920b57cec5SDimitry Andric   // Call the function.
293349cc55cSDimitry Andric   CallInst *CI =
294349cc55cSDimitry Andric       CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
295349cc55cSDimitry Andric   CI->setCallingConv(RewindFunctionCallingConv);
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   // We never expect _Unwind_Resume to return.
298e8d8bef9SDimitry Andric   CI->setDoesNotReturn();
2990b57cec5SDimitry Andric   new UnreachableInst(Ctx, UnwindBB);
300e8d8bef9SDimitry Andric 
301fe6060f1SDimitry Andric   if (DTU)
302e8d8bef9SDimitry Andric     DTU->applyUpdates(Updates);
303e8d8bef9SDimitry Andric 
3040b57cec5SDimitry Andric   return true;
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric 
307e8d8bef9SDimitry Andric bool DwarfEHPrepare::run() {
308e8d8bef9SDimitry Andric   bool Changed = InsertUnwindResumeCalls();
309e8d8bef9SDimitry Andric 
310e8d8bef9SDimitry Andric   return Changed;
311e8d8bef9SDimitry Andric }
312e8d8bef9SDimitry Andric 
313*5f757f3fSDimitry Andric static bool prepareDwarfEH(CodeGenOptLevel OptLevel, Function &F,
314e8d8bef9SDimitry Andric                            const TargetLowering &TLI, DominatorTree *DT,
315349cc55cSDimitry Andric                            const TargetTransformInfo *TTI,
316349cc55cSDimitry Andric                            const Triple &TargetTriple) {
317fe6060f1SDimitry Andric   DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
318e8d8bef9SDimitry Andric 
319349cc55cSDimitry Andric   return DwarfEHPrepare(OptLevel, F, TLI, DT ? &DTU : nullptr, TTI,
320349cc55cSDimitry Andric                         TargetTriple)
321e8d8bef9SDimitry Andric       .run();
322e8d8bef9SDimitry Andric }
323e8d8bef9SDimitry Andric 
324e8d8bef9SDimitry Andric namespace {
325e8d8bef9SDimitry Andric 
326e8d8bef9SDimitry Andric class DwarfEHPrepareLegacyPass : public FunctionPass {
327e8d8bef9SDimitry Andric 
328*5f757f3fSDimitry Andric   CodeGenOptLevel OptLevel;
329e8d8bef9SDimitry Andric 
330e8d8bef9SDimitry Andric public:
331e8d8bef9SDimitry Andric   static char ID; // Pass identification, replacement for typeid.
332e8d8bef9SDimitry Andric 
333*5f757f3fSDimitry Andric   DwarfEHPrepareLegacyPass(CodeGenOptLevel OptLevel = CodeGenOptLevel::Default)
334e8d8bef9SDimitry Andric       : FunctionPass(ID), OptLevel(OptLevel) {}
335e8d8bef9SDimitry Andric 
336e8d8bef9SDimitry Andric   bool runOnFunction(Function &F) override {
3370b57cec5SDimitry Andric     const TargetMachine &TM =
3380b57cec5SDimitry Andric         getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
339e8d8bef9SDimitry Andric     const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
340e8d8bef9SDimitry Andric     DominatorTree *DT = nullptr;
341e8d8bef9SDimitry Andric     const TargetTransformInfo *TTI = nullptr;
342fe6060f1SDimitry Andric     if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
343fe6060f1SDimitry Andric       DT = &DTWP->getDomTree();
344*5f757f3fSDimitry Andric     if (OptLevel != CodeGenOptLevel::None) {
345fe6060f1SDimitry Andric       if (!DT)
346e8d8bef9SDimitry Andric         DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
347e8d8bef9SDimitry Andric       TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
348e8d8bef9SDimitry Andric     }
349349cc55cSDimitry Andric     return prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM.getTargetTriple());
350e8d8bef9SDimitry Andric   }
351e8d8bef9SDimitry Andric 
352e8d8bef9SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
353e8d8bef9SDimitry Andric     AU.addRequired<TargetPassConfig>();
354e8d8bef9SDimitry Andric     AU.addRequired<TargetTransformInfoWrapperPass>();
355*5f757f3fSDimitry Andric     if (OptLevel != CodeGenOptLevel::None) {
356e8d8bef9SDimitry Andric       AU.addRequired<DominatorTreeWrapperPass>();
357e8d8bef9SDimitry Andric       AU.addRequired<TargetTransformInfoWrapperPass>();
358e8d8bef9SDimitry Andric     }
359fe6060f1SDimitry Andric     AU.addPreserved<DominatorTreeWrapperPass>();
360e8d8bef9SDimitry Andric   }
361e8d8bef9SDimitry Andric 
362e8d8bef9SDimitry Andric   StringRef getPassName() const override {
363e8d8bef9SDimitry Andric     return "Exception handling preparation";
364e8d8bef9SDimitry Andric   }
365e8d8bef9SDimitry Andric };
366e8d8bef9SDimitry Andric 
367e8d8bef9SDimitry Andric } // end anonymous namespace
368e8d8bef9SDimitry Andric 
369*5f757f3fSDimitry Andric PreservedAnalyses DwarfEHPreparePass::run(Function &F,
370*5f757f3fSDimitry Andric                                           FunctionAnalysisManager &FAM) {
371*5f757f3fSDimitry Andric   const auto &TLI = *TM->getSubtargetImpl(F)->getTargetLowering();
372*5f757f3fSDimitry Andric   auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
373*5f757f3fSDimitry Andric   const TargetTransformInfo *TTI = nullptr;
374*5f757f3fSDimitry Andric   auto OptLevel = TM->getOptLevel();
375*5f757f3fSDimitry Andric   if (OptLevel != CodeGenOptLevel::None) {
376*5f757f3fSDimitry Andric     if (!DT)
377*5f757f3fSDimitry Andric       DT = &FAM.getResult<DominatorTreeAnalysis>(F);
378*5f757f3fSDimitry Andric     TTI = &FAM.getResult<TargetIRAnalysis>(F);
379*5f757f3fSDimitry Andric   }
380*5f757f3fSDimitry Andric   bool Changed =
381*5f757f3fSDimitry Andric       prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM->getTargetTriple());
382*5f757f3fSDimitry Andric 
383*5f757f3fSDimitry Andric   if (!Changed)
384*5f757f3fSDimitry Andric     return PreservedAnalyses::all();
385*5f757f3fSDimitry Andric   PreservedAnalyses PA;
386*5f757f3fSDimitry Andric   PA.preserve<DominatorTreeAnalysis>();
387*5f757f3fSDimitry Andric   return PA;
388*5f757f3fSDimitry Andric }
389*5f757f3fSDimitry Andric 
390e8d8bef9SDimitry Andric char DwarfEHPrepareLegacyPass::ID = 0;
391e8d8bef9SDimitry Andric 
392e8d8bef9SDimitry Andric INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
393e8d8bef9SDimitry Andric                       "Prepare DWARF exceptions", false, false)
394e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
395e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
396e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
397e8d8bef9SDimitry Andric INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
398e8d8bef9SDimitry Andric                     "Prepare DWARF exceptions", false, false)
399e8d8bef9SDimitry Andric 
400*5f757f3fSDimitry Andric FunctionPass *llvm::createDwarfEHPass(CodeGenOptLevel OptLevel) {
401e8d8bef9SDimitry Andric   return new DwarfEHPrepareLegacyPass(OptLevel);
4020b57cec5SDimitry Andric }
403