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