106f32e7eSjoerg //===- DwarfEHPrepare - Prepare exception handling for code generation ----===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This pass mulches exception handling code into a form adapted to code
1006f32e7eSjoerg // generation. Required if using dwarf exception handling.
1106f32e7eSjoerg //
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg 
1406f32e7eSjoerg #include "llvm/ADT/BitVector.h"
1506f32e7eSjoerg #include "llvm/ADT/SmallVector.h"
1606f32e7eSjoerg #include "llvm/ADT/Statistic.h"
1706f32e7eSjoerg #include "llvm/Analysis/CFG.h"
18*da58b97aSjoerg #include "llvm/Analysis/DomTreeUpdater.h"
1906f32e7eSjoerg #include "llvm/Analysis/EHPersonalities.h"
2006f32e7eSjoerg #include "llvm/Analysis/TargetTransformInfo.h"
2106f32e7eSjoerg #include "llvm/CodeGen/RuntimeLibcalls.h"
2206f32e7eSjoerg #include "llvm/CodeGen/TargetLowering.h"
2306f32e7eSjoerg #include "llvm/CodeGen/TargetPassConfig.h"
2406f32e7eSjoerg #include "llvm/CodeGen/TargetSubtargetInfo.h"
2506f32e7eSjoerg #include "llvm/IR/BasicBlock.h"
2606f32e7eSjoerg #include "llvm/IR/Constants.h"
2706f32e7eSjoerg #include "llvm/IR/DerivedTypes.h"
2806f32e7eSjoerg #include "llvm/IR/Dominators.h"
2906f32e7eSjoerg #include "llvm/IR/Function.h"
3006f32e7eSjoerg #include "llvm/IR/Instructions.h"
3106f32e7eSjoerg #include "llvm/IR/Module.h"
3206f32e7eSjoerg #include "llvm/IR/Type.h"
33*da58b97aSjoerg #include "llvm/InitializePasses.h"
3406f32e7eSjoerg #include "llvm/Pass.h"
3506f32e7eSjoerg #include "llvm/Support/Casting.h"
3606f32e7eSjoerg #include "llvm/Target/TargetMachine.h"
37*da58b97aSjoerg #include "llvm/Transforms/Utils/Local.h"
3806f32e7eSjoerg #include <cstddef>
3906f32e7eSjoerg 
4006f32e7eSjoerg using namespace llvm;
4106f32e7eSjoerg 
4206f32e7eSjoerg #define DEBUG_TYPE "dwarfehprepare"
4306f32e7eSjoerg 
4406f32e7eSjoerg STATISTIC(NumResumesLowered, "Number of resume calls lowered");
4506f32e7eSjoerg 
4606f32e7eSjoerg namespace {
4706f32e7eSjoerg 
48*da58b97aSjoerg class DwarfEHPrepare {
49*da58b97aSjoerg   CodeGenOpt::Level OptLevel;
50*da58b97aSjoerg 
5106f32e7eSjoerg   // RewindFunction - _Unwind_Resume or the target equivalent.
52*da58b97aSjoerg   FunctionCallee &RewindFunction;
5306f32e7eSjoerg 
54*da58b97aSjoerg   Function &F;
55*da58b97aSjoerg   const TargetLowering &TLI;
56*da58b97aSjoerg   DomTreeUpdater *DTU;
57*da58b97aSjoerg   const TargetTransformInfo *TTI;
5806f32e7eSjoerg 
59*da58b97aSjoerg   /// Return the exception object from the value passed into
6006f32e7eSjoerg   /// the 'resume' instruction (typically an aggregate). Clean up any dead
6106f32e7eSjoerg   /// instructions, including the 'resume' instruction.
62*da58b97aSjoerg   Value *GetExceptionObject(ResumeInst *RI);
63*da58b97aSjoerg 
64*da58b97aSjoerg   /// Replace resumes that are not reachable from a cleanup landing pad with
65*da58b97aSjoerg   /// unreachable and then simplify those blocks.
66*da58b97aSjoerg   size_t
67*da58b97aSjoerg   pruneUnreachableResumes(SmallVectorImpl<ResumeInst *> &Resumes,
68*da58b97aSjoerg                           SmallVectorImpl<LandingPadInst *> &CleanupLPads);
69*da58b97aSjoerg 
70*da58b97aSjoerg   /// Convert the ResumeInsts that are still present
71*da58b97aSjoerg   /// into calls to the appropriate _Unwind_Resume function.
72*da58b97aSjoerg   bool InsertUnwindResumeCalls();
73*da58b97aSjoerg 
74*da58b97aSjoerg public:
DwarfEHPrepare(CodeGenOpt::Level OptLevel_,FunctionCallee & RewindFunction_,Function & F_,const TargetLowering & TLI_,DomTreeUpdater * DTU_,const TargetTransformInfo * TTI_)75*da58b97aSjoerg   DwarfEHPrepare(CodeGenOpt::Level OptLevel_, FunctionCallee &RewindFunction_,
76*da58b97aSjoerg                  Function &F_, const TargetLowering &TLI_, DomTreeUpdater *DTU_,
77*da58b97aSjoerg                  const TargetTransformInfo *TTI_)
78*da58b97aSjoerg       : OptLevel(OptLevel_), RewindFunction(RewindFunction_), F(F_), TLI(TLI_),
79*da58b97aSjoerg         DTU(DTU_), TTI(TTI_) {}
80*da58b97aSjoerg 
81*da58b97aSjoerg   bool run();
82*da58b97aSjoerg };
83*da58b97aSjoerg 
84*da58b97aSjoerg } // namespace
85*da58b97aSjoerg 
GetExceptionObject(ResumeInst * RI)8606f32e7eSjoerg Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
8706f32e7eSjoerg   Value *V = RI->getOperand(0);
8806f32e7eSjoerg   Value *ExnObj = nullptr;
8906f32e7eSjoerg   InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
9006f32e7eSjoerg   LoadInst *SelLoad = nullptr;
9106f32e7eSjoerg   InsertValueInst *ExcIVI = nullptr;
9206f32e7eSjoerg   bool EraseIVIs = false;
9306f32e7eSjoerg 
9406f32e7eSjoerg   if (SelIVI) {
9506f32e7eSjoerg     if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
9606f32e7eSjoerg       ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
9706f32e7eSjoerg       if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
9806f32e7eSjoerg           ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
9906f32e7eSjoerg         ExnObj = ExcIVI->getOperand(1);
10006f32e7eSjoerg         SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
10106f32e7eSjoerg         EraseIVIs = true;
10206f32e7eSjoerg       }
10306f32e7eSjoerg     }
10406f32e7eSjoerg   }
10506f32e7eSjoerg 
10606f32e7eSjoerg   if (!ExnObj)
10706f32e7eSjoerg     ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
10806f32e7eSjoerg 
10906f32e7eSjoerg   RI->eraseFromParent();
11006f32e7eSjoerg 
11106f32e7eSjoerg   if (EraseIVIs) {
11206f32e7eSjoerg     if (SelIVI->use_empty())
11306f32e7eSjoerg       SelIVI->eraseFromParent();
11406f32e7eSjoerg     if (ExcIVI->use_empty())
11506f32e7eSjoerg       ExcIVI->eraseFromParent();
11606f32e7eSjoerg     if (SelLoad && SelLoad->use_empty())
11706f32e7eSjoerg       SelLoad->eraseFromParent();
11806f32e7eSjoerg   }
11906f32e7eSjoerg 
12006f32e7eSjoerg   return ExnObj;
12106f32e7eSjoerg }
12206f32e7eSjoerg 
pruneUnreachableResumes(SmallVectorImpl<ResumeInst * > & Resumes,SmallVectorImpl<LandingPadInst * > & CleanupLPads)12306f32e7eSjoerg size_t DwarfEHPrepare::pruneUnreachableResumes(
124*da58b97aSjoerg     SmallVectorImpl<ResumeInst *> &Resumes,
12506f32e7eSjoerg     SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
126*da58b97aSjoerg   assert(DTU && "Should have DomTreeUpdater here.");
127*da58b97aSjoerg 
12806f32e7eSjoerg   BitVector ResumeReachable(Resumes.size());
12906f32e7eSjoerg   size_t ResumeIndex = 0;
13006f32e7eSjoerg   for (auto *RI : Resumes) {
13106f32e7eSjoerg     for (auto *LP : CleanupLPads) {
132*da58b97aSjoerg       if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) {
13306f32e7eSjoerg         ResumeReachable.set(ResumeIndex);
13406f32e7eSjoerg         break;
13506f32e7eSjoerg       }
13606f32e7eSjoerg     }
13706f32e7eSjoerg     ++ResumeIndex;
13806f32e7eSjoerg   }
13906f32e7eSjoerg 
14006f32e7eSjoerg   // If everything is reachable, there is no change.
14106f32e7eSjoerg   if (ResumeReachable.all())
14206f32e7eSjoerg     return Resumes.size();
14306f32e7eSjoerg 
144*da58b97aSjoerg   LLVMContext &Ctx = F.getContext();
14506f32e7eSjoerg 
14606f32e7eSjoerg   // Otherwise, insert unreachable instructions and call simplifycfg.
14706f32e7eSjoerg   size_t ResumesLeft = 0;
14806f32e7eSjoerg   for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
14906f32e7eSjoerg     ResumeInst *RI = Resumes[I];
15006f32e7eSjoerg     if (ResumeReachable[I]) {
15106f32e7eSjoerg       Resumes[ResumesLeft++] = RI;
15206f32e7eSjoerg     } else {
15306f32e7eSjoerg       BasicBlock *BB = RI->getParent();
15406f32e7eSjoerg       new UnreachableInst(Ctx, RI);
15506f32e7eSjoerg       RI->eraseFromParent();
156*da58b97aSjoerg       simplifyCFG(BB, *TTI, DTU);
15706f32e7eSjoerg     }
15806f32e7eSjoerg   }
15906f32e7eSjoerg   Resumes.resize(ResumesLeft);
16006f32e7eSjoerg   return ResumesLeft;
16106f32e7eSjoerg }
16206f32e7eSjoerg 
InsertUnwindResumeCalls()163*da58b97aSjoerg bool DwarfEHPrepare::InsertUnwindResumeCalls() {
16406f32e7eSjoerg   SmallVector<ResumeInst *, 16> Resumes;
16506f32e7eSjoerg   SmallVector<LandingPadInst *, 16> CleanupLPads;
166*da58b97aSjoerg   for (BasicBlock &BB : F) {
16706f32e7eSjoerg     if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
16806f32e7eSjoerg       Resumes.push_back(RI);
16906f32e7eSjoerg     if (auto *LP = BB.getLandingPadInst())
17006f32e7eSjoerg       if (LP->isCleanup())
17106f32e7eSjoerg         CleanupLPads.push_back(LP);
17206f32e7eSjoerg   }
17306f32e7eSjoerg 
17406f32e7eSjoerg   if (Resumes.empty())
17506f32e7eSjoerg     return false;
17606f32e7eSjoerg 
17706f32e7eSjoerg   // Check the personality, don't do anything if it's scope-based.
178*da58b97aSjoerg   EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn());
17906f32e7eSjoerg   if (isScopedEHPersonality(Pers))
18006f32e7eSjoerg     return false;
18106f32e7eSjoerg 
182*da58b97aSjoerg   LLVMContext &Ctx = F.getContext();
18306f32e7eSjoerg 
184*da58b97aSjoerg   size_t ResumesLeft = Resumes.size();
185*da58b97aSjoerg   if (OptLevel != CodeGenOpt::None)
186*da58b97aSjoerg     ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads);
187*da58b97aSjoerg 
18806f32e7eSjoerg   if (ResumesLeft == 0)
18906f32e7eSjoerg     return true; // We pruned them all.
19006f32e7eSjoerg 
19106f32e7eSjoerg   // Find the rewind function if we didn't already.
19206f32e7eSjoerg   if (!RewindFunction) {
193*da58b97aSjoerg     FunctionType *FTy =
194*da58b97aSjoerg         FunctionType::get(Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), false);
195*da58b97aSjoerg     const char *RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
196*da58b97aSjoerg     RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy);
19706f32e7eSjoerg   }
19806f32e7eSjoerg 
19906f32e7eSjoerg   // Create the basic block where the _Unwind_Resume call will live.
20006f32e7eSjoerg   if (ResumesLeft == 1) {
20106f32e7eSjoerg     // Instead of creating a new BB and PHI node, just append the call to
20206f32e7eSjoerg     // _Unwind_Resume to the end of the single resume block.
20306f32e7eSjoerg     ResumeInst *RI = Resumes.front();
20406f32e7eSjoerg     BasicBlock *UnwindBB = RI->getParent();
20506f32e7eSjoerg     Value *ExnObj = GetExceptionObject(RI);
20606f32e7eSjoerg 
20706f32e7eSjoerg     // Call the _Unwind_Resume function.
20806f32e7eSjoerg     CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB);
209*da58b97aSjoerg     CI->setCallingConv(TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME));
21006f32e7eSjoerg 
21106f32e7eSjoerg     // We never expect _Unwind_Resume to return.
212*da58b97aSjoerg     CI->setDoesNotReturn();
21306f32e7eSjoerg     new UnreachableInst(Ctx, UnwindBB);
21406f32e7eSjoerg     return true;
21506f32e7eSjoerg   }
21606f32e7eSjoerg 
217*da58b97aSjoerg   std::vector<DominatorTree::UpdateType> Updates;
218*da58b97aSjoerg   Updates.reserve(Resumes.size());
219*da58b97aSjoerg 
220*da58b97aSjoerg   BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
221*da58b97aSjoerg   PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft, "exn.obj",
222*da58b97aSjoerg                                 UnwindBB);
22306f32e7eSjoerg 
22406f32e7eSjoerg   // Extract the exception object from the ResumeInst and add it to the PHI node
22506f32e7eSjoerg   // that feeds the _Unwind_Resume call.
22606f32e7eSjoerg   for (ResumeInst *RI : Resumes) {
22706f32e7eSjoerg     BasicBlock *Parent = RI->getParent();
22806f32e7eSjoerg     BranchInst::Create(UnwindBB, Parent);
229*da58b97aSjoerg     Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
23006f32e7eSjoerg 
23106f32e7eSjoerg     Value *ExnObj = GetExceptionObject(RI);
23206f32e7eSjoerg     PN->addIncoming(ExnObj, Parent);
23306f32e7eSjoerg 
23406f32e7eSjoerg     ++NumResumesLowered;
23506f32e7eSjoerg   }
23606f32e7eSjoerg 
23706f32e7eSjoerg   // Call the function.
23806f32e7eSjoerg   CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB);
239*da58b97aSjoerg   CI->setCallingConv(TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME));
24006f32e7eSjoerg 
24106f32e7eSjoerg   // We never expect _Unwind_Resume to return.
242*da58b97aSjoerg   CI->setDoesNotReturn();
24306f32e7eSjoerg   new UnreachableInst(Ctx, UnwindBB);
244*da58b97aSjoerg 
245*da58b97aSjoerg   if (DTU)
246*da58b97aSjoerg     DTU->applyUpdates(Updates);
247*da58b97aSjoerg 
24806f32e7eSjoerg   return true;
24906f32e7eSjoerg }
25006f32e7eSjoerg 
run()251*da58b97aSjoerg bool DwarfEHPrepare::run() {
252*da58b97aSjoerg   bool Changed = InsertUnwindResumeCalls();
253*da58b97aSjoerg 
254*da58b97aSjoerg   return Changed;
255*da58b97aSjoerg }
256*da58b97aSjoerg 
prepareDwarfEH(CodeGenOpt::Level OptLevel,FunctionCallee & RewindFunction,Function & F,const TargetLowering & TLI,DominatorTree * DT,const TargetTransformInfo * TTI)257*da58b97aSjoerg static bool prepareDwarfEH(CodeGenOpt::Level OptLevel,
258*da58b97aSjoerg                            FunctionCallee &RewindFunction, Function &F,
259*da58b97aSjoerg                            const TargetLowering &TLI, DominatorTree *DT,
260*da58b97aSjoerg                            const TargetTransformInfo *TTI) {
261*da58b97aSjoerg   DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
262*da58b97aSjoerg 
263*da58b97aSjoerg   return DwarfEHPrepare(OptLevel, RewindFunction, F, TLI, DT ? &DTU : nullptr,
264*da58b97aSjoerg                         TTI)
265*da58b97aSjoerg       .run();
266*da58b97aSjoerg }
267*da58b97aSjoerg 
268*da58b97aSjoerg namespace {
269*da58b97aSjoerg 
270*da58b97aSjoerg class DwarfEHPrepareLegacyPass : public FunctionPass {
271*da58b97aSjoerg   // RewindFunction - _Unwind_Resume or the target equivalent.
272*da58b97aSjoerg   FunctionCallee RewindFunction = nullptr;
273*da58b97aSjoerg 
274*da58b97aSjoerg   CodeGenOpt::Level OptLevel;
275*da58b97aSjoerg 
276*da58b97aSjoerg public:
277*da58b97aSjoerg   static char ID; // Pass identification, replacement for typeid.
278*da58b97aSjoerg 
DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel=CodeGenOpt::Default)279*da58b97aSjoerg   DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel = CodeGenOpt::Default)
280*da58b97aSjoerg       : FunctionPass(ID), OptLevel(OptLevel) {}
281*da58b97aSjoerg 
runOnFunction(Function & F)282*da58b97aSjoerg   bool runOnFunction(Function &F) override {
28306f32e7eSjoerg     const TargetMachine &TM =
28406f32e7eSjoerg         getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
285*da58b97aSjoerg     const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
286*da58b97aSjoerg     DominatorTree *DT = nullptr;
287*da58b97aSjoerg     const TargetTransformInfo *TTI = nullptr;
288*da58b97aSjoerg     if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
289*da58b97aSjoerg       DT = &DTWP->getDomTree();
290*da58b97aSjoerg     if (OptLevel != CodeGenOpt::None) {
291*da58b97aSjoerg       if (!DT)
29206f32e7eSjoerg         DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
293*da58b97aSjoerg       TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
294*da58b97aSjoerg     }
295*da58b97aSjoerg     return prepareDwarfEH(OptLevel, RewindFunction, F, TLI, DT, TTI);
296*da58b97aSjoerg   }
297*da58b97aSjoerg 
getAnalysisUsage(AnalysisUsage & AU) const298*da58b97aSjoerg   void getAnalysisUsage(AnalysisUsage &AU) const override {
299*da58b97aSjoerg     AU.addRequired<TargetPassConfig>();
300*da58b97aSjoerg     AU.addRequired<TargetTransformInfoWrapperPass>();
301*da58b97aSjoerg     if (OptLevel != CodeGenOpt::None) {
302*da58b97aSjoerg       AU.addRequired<DominatorTreeWrapperPass>();
303*da58b97aSjoerg       AU.addRequired<TargetTransformInfoWrapperPass>();
304*da58b97aSjoerg     }
305*da58b97aSjoerg     AU.addPreserved<DominatorTreeWrapperPass>();
306*da58b97aSjoerg   }
307*da58b97aSjoerg 
getPassName() const308*da58b97aSjoerg   StringRef getPassName() const override {
309*da58b97aSjoerg     return "Exception handling preparation";
310*da58b97aSjoerg   }
311*da58b97aSjoerg };
312*da58b97aSjoerg 
313*da58b97aSjoerg } // end anonymous namespace
314*da58b97aSjoerg 
315*da58b97aSjoerg char DwarfEHPrepareLegacyPass::ID = 0;
316*da58b97aSjoerg 
317*da58b97aSjoerg INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
318*da58b97aSjoerg                       "Prepare DWARF exceptions", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)319*da58b97aSjoerg INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
320*da58b97aSjoerg INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
321*da58b97aSjoerg INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
322*da58b97aSjoerg INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
323*da58b97aSjoerg                     "Prepare DWARF exceptions", false, false)
324*da58b97aSjoerg 
325*da58b97aSjoerg FunctionPass *llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel) {
326*da58b97aSjoerg   return new DwarfEHPrepareLegacyPass(OptLevel);
32706f32e7eSjoerg }
328