xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/DwarfEHPrepare.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- DwarfEHPrepare - Prepare exception handling for code generation ----===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This pass mulches exception handling code into a form adapted to code
10*0b57cec5SDimitry Andric // generation. Required if using dwarf exception handling.
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
15*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
16*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
17*0b57cec5SDimitry Andric #include "llvm/Analysis/CFG.h"
18*0b57cec5SDimitry Andric #include "llvm/Analysis/EHPersonalities.h"
19*0b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
20*0b57cec5SDimitry Andric #include "llvm/Transforms/Utils/Local.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.h"
22*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
23*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
24*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
25*0b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
26*0b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
27*0b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
28*0b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
29*0b57cec5SDimitry Andric #include "llvm/IR/Function.h"
30*0b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
31*0b57cec5SDimitry Andric #include "llvm/IR/Module.h"
32*0b57cec5SDimitry Andric #include "llvm/IR/Type.h"
33*0b57cec5SDimitry Andric #include "llvm/Pass.h"
34*0b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
35*0b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
36*0b57cec5SDimitry Andric #include <cstddef>
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric using namespace llvm;
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric #define DEBUG_TYPE "dwarfehprepare"
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric STATISTIC(NumResumesLowered, "Number of resume calls lowered");
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric namespace {
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric   class DwarfEHPrepare : public FunctionPass {
47*0b57cec5SDimitry Andric     // RewindFunction - _Unwind_Resume or the target equivalent.
48*0b57cec5SDimitry Andric     FunctionCallee RewindFunction = nullptr;
49*0b57cec5SDimitry Andric 
50*0b57cec5SDimitry Andric     DominatorTree *DT = nullptr;
51*0b57cec5SDimitry Andric     const TargetLowering *TLI = nullptr;
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric     bool InsertUnwindResumeCalls(Function &Fn);
54*0b57cec5SDimitry Andric     Value *GetExceptionObject(ResumeInst *RI);
55*0b57cec5SDimitry Andric     size_t
56*0b57cec5SDimitry Andric     pruneUnreachableResumes(Function &Fn,
57*0b57cec5SDimitry Andric                             SmallVectorImpl<ResumeInst *> &Resumes,
58*0b57cec5SDimitry Andric                             SmallVectorImpl<LandingPadInst *> &CleanupLPads);
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric   public:
61*0b57cec5SDimitry Andric     static char ID; // Pass identification, replacement for typeid.
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric     DwarfEHPrepare() : FunctionPass(ID) {}
64*0b57cec5SDimitry Andric 
65*0b57cec5SDimitry Andric     bool runOnFunction(Function &Fn) override;
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric     bool doFinalization(Module &M) override {
68*0b57cec5SDimitry Andric       RewindFunction = nullptr;
69*0b57cec5SDimitry Andric       return false;
70*0b57cec5SDimitry Andric     }
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override;
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric     StringRef getPassName() const override {
75*0b57cec5SDimitry Andric       return "Exception handling preparation";
76*0b57cec5SDimitry Andric     }
77*0b57cec5SDimitry Andric   };
78*0b57cec5SDimitry Andric 
79*0b57cec5SDimitry Andric } // end anonymous namespace
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric char DwarfEHPrepare::ID = 0;
82*0b57cec5SDimitry Andric 
83*0b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(DwarfEHPrepare, DEBUG_TYPE,
84*0b57cec5SDimitry Andric                       "Prepare DWARF exceptions", false, false)
85*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
86*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
87*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
88*0b57cec5SDimitry Andric INITIALIZE_PASS_END(DwarfEHPrepare, DEBUG_TYPE,
89*0b57cec5SDimitry Andric                     "Prepare DWARF exceptions", false, false)
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric FunctionPass *llvm::createDwarfEHPass() { return new DwarfEHPrepare(); }
92*0b57cec5SDimitry Andric 
93*0b57cec5SDimitry Andric void DwarfEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
94*0b57cec5SDimitry Andric   AU.addRequired<TargetPassConfig>();
95*0b57cec5SDimitry Andric   AU.addRequired<TargetTransformInfoWrapperPass>();
96*0b57cec5SDimitry Andric   AU.addRequired<DominatorTreeWrapperPass>();
97*0b57cec5SDimitry Andric }
98*0b57cec5SDimitry Andric 
99*0b57cec5SDimitry Andric /// GetExceptionObject - Return the exception object from the value passed into
100*0b57cec5SDimitry Andric /// the 'resume' instruction (typically an aggregate). Clean up any dead
101*0b57cec5SDimitry Andric /// instructions, including the 'resume' instruction.
102*0b57cec5SDimitry Andric Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
103*0b57cec5SDimitry Andric   Value *V = RI->getOperand(0);
104*0b57cec5SDimitry Andric   Value *ExnObj = nullptr;
105*0b57cec5SDimitry Andric   InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
106*0b57cec5SDimitry Andric   LoadInst *SelLoad = nullptr;
107*0b57cec5SDimitry Andric   InsertValueInst *ExcIVI = nullptr;
108*0b57cec5SDimitry Andric   bool EraseIVIs = false;
109*0b57cec5SDimitry Andric 
110*0b57cec5SDimitry Andric   if (SelIVI) {
111*0b57cec5SDimitry Andric     if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
112*0b57cec5SDimitry Andric       ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
113*0b57cec5SDimitry Andric       if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
114*0b57cec5SDimitry Andric           ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
115*0b57cec5SDimitry Andric         ExnObj = ExcIVI->getOperand(1);
116*0b57cec5SDimitry Andric         SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
117*0b57cec5SDimitry Andric         EraseIVIs = true;
118*0b57cec5SDimitry Andric       }
119*0b57cec5SDimitry Andric     }
120*0b57cec5SDimitry Andric   }
121*0b57cec5SDimitry Andric 
122*0b57cec5SDimitry Andric   if (!ExnObj)
123*0b57cec5SDimitry Andric     ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric   RI->eraseFromParent();
126*0b57cec5SDimitry Andric 
127*0b57cec5SDimitry Andric   if (EraseIVIs) {
128*0b57cec5SDimitry Andric     if (SelIVI->use_empty())
129*0b57cec5SDimitry Andric       SelIVI->eraseFromParent();
130*0b57cec5SDimitry Andric     if (ExcIVI->use_empty())
131*0b57cec5SDimitry Andric       ExcIVI->eraseFromParent();
132*0b57cec5SDimitry Andric     if (SelLoad && SelLoad->use_empty())
133*0b57cec5SDimitry Andric       SelLoad->eraseFromParent();
134*0b57cec5SDimitry Andric   }
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric   return ExnObj;
137*0b57cec5SDimitry Andric }
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric /// Replace resumes that are not reachable from a cleanup landing pad with
140*0b57cec5SDimitry Andric /// unreachable and then simplify those blocks.
141*0b57cec5SDimitry Andric size_t DwarfEHPrepare::pruneUnreachableResumes(
142*0b57cec5SDimitry Andric     Function &Fn, SmallVectorImpl<ResumeInst *> &Resumes,
143*0b57cec5SDimitry Andric     SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
144*0b57cec5SDimitry Andric   BitVector ResumeReachable(Resumes.size());
145*0b57cec5SDimitry Andric   size_t ResumeIndex = 0;
146*0b57cec5SDimitry Andric   for (auto *RI : Resumes) {
147*0b57cec5SDimitry Andric     for (auto *LP : CleanupLPads) {
148*0b57cec5SDimitry Andric       if (isPotentiallyReachable(LP, RI, nullptr, DT)) {
149*0b57cec5SDimitry Andric         ResumeReachable.set(ResumeIndex);
150*0b57cec5SDimitry Andric         break;
151*0b57cec5SDimitry Andric       }
152*0b57cec5SDimitry Andric     }
153*0b57cec5SDimitry Andric     ++ResumeIndex;
154*0b57cec5SDimitry Andric   }
155*0b57cec5SDimitry Andric 
156*0b57cec5SDimitry Andric   // If everything is reachable, there is no change.
157*0b57cec5SDimitry Andric   if (ResumeReachable.all())
158*0b57cec5SDimitry Andric     return Resumes.size();
159*0b57cec5SDimitry Andric 
160*0b57cec5SDimitry Andric   const TargetTransformInfo &TTI =
161*0b57cec5SDimitry Andric       getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn);
162*0b57cec5SDimitry Andric   LLVMContext &Ctx = Fn.getContext();
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric   // Otherwise, insert unreachable instructions and call simplifycfg.
165*0b57cec5SDimitry Andric   size_t ResumesLeft = 0;
166*0b57cec5SDimitry Andric   for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
167*0b57cec5SDimitry Andric     ResumeInst *RI = Resumes[I];
168*0b57cec5SDimitry Andric     if (ResumeReachable[I]) {
169*0b57cec5SDimitry Andric       Resumes[ResumesLeft++] = RI;
170*0b57cec5SDimitry Andric     } else {
171*0b57cec5SDimitry Andric       BasicBlock *BB = RI->getParent();
172*0b57cec5SDimitry Andric       new UnreachableInst(Ctx, RI);
173*0b57cec5SDimitry Andric       RI->eraseFromParent();
174*0b57cec5SDimitry Andric       simplifyCFG(BB, TTI);
175*0b57cec5SDimitry Andric     }
176*0b57cec5SDimitry Andric   }
177*0b57cec5SDimitry Andric   Resumes.resize(ResumesLeft);
178*0b57cec5SDimitry Andric   return ResumesLeft;
179*0b57cec5SDimitry Andric }
180*0b57cec5SDimitry Andric 
181*0b57cec5SDimitry Andric /// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present
182*0b57cec5SDimitry Andric /// into calls to the appropriate _Unwind_Resume function.
183*0b57cec5SDimitry Andric bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) {
184*0b57cec5SDimitry Andric   SmallVector<ResumeInst*, 16> Resumes;
185*0b57cec5SDimitry Andric   SmallVector<LandingPadInst*, 16> CleanupLPads;
186*0b57cec5SDimitry Andric   for (BasicBlock &BB : Fn) {
187*0b57cec5SDimitry Andric     if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
188*0b57cec5SDimitry Andric       Resumes.push_back(RI);
189*0b57cec5SDimitry Andric     if (auto *LP = BB.getLandingPadInst())
190*0b57cec5SDimitry Andric       if (LP->isCleanup())
191*0b57cec5SDimitry Andric         CleanupLPads.push_back(LP);
192*0b57cec5SDimitry Andric   }
193*0b57cec5SDimitry Andric 
194*0b57cec5SDimitry Andric   if (Resumes.empty())
195*0b57cec5SDimitry Andric     return false;
196*0b57cec5SDimitry Andric 
197*0b57cec5SDimitry Andric   // Check the personality, don't do anything if it's scope-based.
198*0b57cec5SDimitry Andric   EHPersonality Pers = classifyEHPersonality(Fn.getPersonalityFn());
199*0b57cec5SDimitry Andric   if (isScopedEHPersonality(Pers))
200*0b57cec5SDimitry Andric     return false;
201*0b57cec5SDimitry Andric 
202*0b57cec5SDimitry Andric   LLVMContext &Ctx = Fn.getContext();
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric   size_t ResumesLeft = pruneUnreachableResumes(Fn, Resumes, CleanupLPads);
205*0b57cec5SDimitry Andric   if (ResumesLeft == 0)
206*0b57cec5SDimitry Andric     return true; // We pruned them all.
207*0b57cec5SDimitry Andric 
208*0b57cec5SDimitry Andric   // Find the rewind function if we didn't already.
209*0b57cec5SDimitry Andric   if (!RewindFunction) {
210*0b57cec5SDimitry Andric     FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx),
211*0b57cec5SDimitry Andric                                           Type::getInt8PtrTy(Ctx), false);
212*0b57cec5SDimitry Andric     const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME);
213*0b57cec5SDimitry Andric     RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy);
214*0b57cec5SDimitry Andric   }
215*0b57cec5SDimitry Andric 
216*0b57cec5SDimitry Andric   // Create the basic block where the _Unwind_Resume call will live.
217*0b57cec5SDimitry Andric   if (ResumesLeft == 1) {
218*0b57cec5SDimitry Andric     // Instead of creating a new BB and PHI node, just append the call to
219*0b57cec5SDimitry Andric     // _Unwind_Resume to the end of the single resume block.
220*0b57cec5SDimitry Andric     ResumeInst *RI = Resumes.front();
221*0b57cec5SDimitry Andric     BasicBlock *UnwindBB = RI->getParent();
222*0b57cec5SDimitry Andric     Value *ExnObj = GetExceptionObject(RI);
223*0b57cec5SDimitry Andric 
224*0b57cec5SDimitry Andric     // Call the _Unwind_Resume function.
225*0b57cec5SDimitry Andric     CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB);
226*0b57cec5SDimitry Andric     CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
227*0b57cec5SDimitry Andric 
228*0b57cec5SDimitry Andric     // We never expect _Unwind_Resume to return.
229*0b57cec5SDimitry Andric     new UnreachableInst(Ctx, UnwindBB);
230*0b57cec5SDimitry Andric     return true;
231*0b57cec5SDimitry Andric   }
232*0b57cec5SDimitry Andric 
233*0b57cec5SDimitry Andric   BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn);
234*0b57cec5SDimitry Andric   PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft,
235*0b57cec5SDimitry Andric                                 "exn.obj", UnwindBB);
236*0b57cec5SDimitry Andric 
237*0b57cec5SDimitry Andric   // Extract the exception object from the ResumeInst and add it to the PHI node
238*0b57cec5SDimitry Andric   // that feeds the _Unwind_Resume call.
239*0b57cec5SDimitry Andric   for (ResumeInst *RI : Resumes) {
240*0b57cec5SDimitry Andric     BasicBlock *Parent = RI->getParent();
241*0b57cec5SDimitry Andric     BranchInst::Create(UnwindBB, Parent);
242*0b57cec5SDimitry Andric 
243*0b57cec5SDimitry Andric     Value *ExnObj = GetExceptionObject(RI);
244*0b57cec5SDimitry Andric     PN->addIncoming(ExnObj, Parent);
245*0b57cec5SDimitry Andric 
246*0b57cec5SDimitry Andric     ++NumResumesLowered;
247*0b57cec5SDimitry Andric   }
248*0b57cec5SDimitry Andric 
249*0b57cec5SDimitry Andric   // Call the function.
250*0b57cec5SDimitry Andric   CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB);
251*0b57cec5SDimitry Andric   CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
252*0b57cec5SDimitry Andric 
253*0b57cec5SDimitry Andric   // We never expect _Unwind_Resume to return.
254*0b57cec5SDimitry Andric   new UnreachableInst(Ctx, UnwindBB);
255*0b57cec5SDimitry Andric   return true;
256*0b57cec5SDimitry Andric }
257*0b57cec5SDimitry Andric 
258*0b57cec5SDimitry Andric bool DwarfEHPrepare::runOnFunction(Function &Fn) {
259*0b57cec5SDimitry Andric   const TargetMachine &TM =
260*0b57cec5SDimitry Andric       getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
261*0b57cec5SDimitry Andric   DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
262*0b57cec5SDimitry Andric   TLI = TM.getSubtargetImpl(Fn)->getTargetLowering();
263*0b57cec5SDimitry Andric   bool Changed = InsertUnwindResumeCalls(Fn);
264*0b57cec5SDimitry Andric   DT = nullptr;
265*0b57cec5SDimitry Andric   TLI = nullptr;
266*0b57cec5SDimitry Andric   return Changed;
267*0b57cec5SDimitry Andric }
268