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/ADT/Triple.h"
18 #include "llvm/Analysis/CFG.h"
19 #include "llvm/Analysis/DomTreeUpdater.h"
20 #include "llvm/Analysis/EHPersonalities.h"
21 #include "llvm/Analysis/TargetTransformInfo.h"
22 #include "llvm/CodeGen/RuntimeLibcalls.h"
23 #include "llvm/CodeGen/TargetLowering.h"
24 #include "llvm/CodeGen/TargetPassConfig.h"
25 #include "llvm/CodeGen/TargetSubtargetInfo.h"
26 #include "llvm/IR/BasicBlock.h"
27 #include "llvm/IR/Constants.h"
28 #include "llvm/IR/DebugInfoMetadata.h"
29 #include "llvm/IR/DerivedTypes.h"
30 #include "llvm/IR/Dominators.h"
31 #include "llvm/IR/Function.h"
32 #include "llvm/IR/Instructions.h"
33 #include "llvm/IR/Module.h"
34 #include "llvm/IR/Type.h"
35 #include "llvm/InitializePasses.h"
36 #include "llvm/Pass.h"
37 #include "llvm/Support/Casting.h"
38 #include "llvm/Target/TargetMachine.h"
39 #include "llvm/Transforms/Utils/Local.h"
40 #include <cstddef>
41
42 using namespace llvm;
43
44 #define DEBUG_TYPE "dwarfehprepare"
45
46 STATISTIC(NumResumesLowered, "Number of resume calls lowered");
47 STATISTIC(NumCleanupLandingPadsUnreachable,
48 "Number of cleanup landing pads found unreachable");
49 STATISTIC(NumCleanupLandingPadsRemaining,
50 "Number of cleanup landing pads remaining");
51 STATISTIC(NumNoUnwind, "Number of functions with nounwind");
52 STATISTIC(NumUnwind, "Number of functions with unwind");
53
54 namespace {
55
56 class DwarfEHPrepare {
57 CodeGenOpt::Level OptLevel;
58
59 Function &F;
60 const TargetLowering &TLI;
61 DomTreeUpdater *DTU;
62 const TargetTransformInfo *TTI;
63 const Triple &TargetTriple;
64
65 /// Return the exception object from the value passed into
66 /// the 'resume' instruction (typically an aggregate). Clean up any dead
67 /// instructions, including the 'resume' instruction.
68 Value *GetExceptionObject(ResumeInst *RI);
69
70 /// Replace resumes that are not reachable from a cleanup landing pad with
71 /// unreachable and then simplify those blocks.
72 size_t
73 pruneUnreachableResumes(SmallVectorImpl<ResumeInst *> &Resumes,
74 SmallVectorImpl<LandingPadInst *> &CleanupLPads);
75
76 /// Convert the ResumeInsts that are still present
77 /// into calls to the appropriate _Unwind_Resume function.
78 bool InsertUnwindResumeCalls();
79
80 public:
DwarfEHPrepare(CodeGenOpt::Level OptLevel_,Function & F_,const TargetLowering & TLI_,DomTreeUpdater * DTU_,const TargetTransformInfo * TTI_,const Triple & TargetTriple_)81 DwarfEHPrepare(CodeGenOpt::Level OptLevel_, Function &F_,
82 const TargetLowering &TLI_, DomTreeUpdater *DTU_,
83 const TargetTransformInfo *TTI_, const Triple &TargetTriple_)
84 : OptLevel(OptLevel_), F(F_), TLI(TLI_), DTU(DTU_), TTI(TTI_),
85 TargetTriple(TargetTriple_) {}
86
87 bool run();
88 };
89
90 } // namespace
91
GetExceptionObject(ResumeInst * RI)92 Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
93 Value *V = RI->getOperand(0);
94 Value *ExnObj = nullptr;
95 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
96 LoadInst *SelLoad = nullptr;
97 InsertValueInst *ExcIVI = nullptr;
98 bool EraseIVIs = false;
99
100 if (SelIVI) {
101 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
102 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
103 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
104 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
105 ExnObj = ExcIVI->getOperand(1);
106 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
107 EraseIVIs = true;
108 }
109 }
110 }
111
112 if (!ExnObj)
113 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
114
115 RI->eraseFromParent();
116
117 if (EraseIVIs) {
118 if (SelIVI->use_empty())
119 SelIVI->eraseFromParent();
120 if (ExcIVI->use_empty())
121 ExcIVI->eraseFromParent();
122 if (SelLoad && SelLoad->use_empty())
123 SelLoad->eraseFromParent();
124 }
125
126 return ExnObj;
127 }
128
pruneUnreachableResumes(SmallVectorImpl<ResumeInst * > & Resumes,SmallVectorImpl<LandingPadInst * > & CleanupLPads)129 size_t DwarfEHPrepare::pruneUnreachableResumes(
130 SmallVectorImpl<ResumeInst *> &Resumes,
131 SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
132 assert(DTU && "Should have DomTreeUpdater here.");
133
134 BitVector ResumeReachable(Resumes.size());
135 size_t ResumeIndex = 0;
136 for (auto *RI : Resumes) {
137 for (auto *LP : CleanupLPads) {
138 if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) {
139 ResumeReachable.set(ResumeIndex);
140 break;
141 }
142 }
143 ++ResumeIndex;
144 }
145
146 // If everything is reachable, there is no change.
147 if (ResumeReachable.all())
148 return Resumes.size();
149
150 LLVMContext &Ctx = F.getContext();
151
152 // Otherwise, insert unreachable instructions and call simplifycfg.
153 size_t ResumesLeft = 0;
154 for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
155 ResumeInst *RI = Resumes[I];
156 if (ResumeReachable[I]) {
157 Resumes[ResumesLeft++] = RI;
158 } else {
159 BasicBlock *BB = RI->getParent();
160 new UnreachableInst(Ctx, RI);
161 RI->eraseFromParent();
162 simplifyCFG(BB, *TTI, DTU);
163 }
164 }
165 Resumes.resize(ResumesLeft);
166 return ResumesLeft;
167 }
168
InsertUnwindResumeCalls()169 bool DwarfEHPrepare::InsertUnwindResumeCalls() {
170 SmallVector<ResumeInst *, 16> Resumes;
171 SmallVector<LandingPadInst *, 16> CleanupLPads;
172 if (F.doesNotThrow())
173 NumNoUnwind++;
174 else
175 NumUnwind++;
176 for (BasicBlock &BB : F) {
177 if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
178 Resumes.push_back(RI);
179 if (auto *LP = BB.getLandingPadInst())
180 if (LP->isCleanup())
181 CleanupLPads.push_back(LP);
182 }
183
184 NumCleanupLandingPadsRemaining += CleanupLPads.size();
185
186 if (Resumes.empty())
187 return false;
188
189 // Check the personality, don't do anything if it's scope-based.
190 EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn());
191 if (isScopedEHPersonality(Pers))
192 return false;
193
194 LLVMContext &Ctx = F.getContext();
195
196 size_t ResumesLeft = Resumes.size();
197 if (OptLevel != CodeGenOpt::None) {
198 ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads);
199 #if LLVM_ENABLE_STATS
200 unsigned NumRemainingLPs = 0;
201 for (BasicBlock &BB : F) {
202 if (auto *LP = BB.getLandingPadInst())
203 if (LP->isCleanup())
204 NumRemainingLPs++;
205 }
206 NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs;
207 NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs;
208 #endif
209 }
210
211 if (ResumesLeft == 0)
212 return true; // We pruned them all.
213
214 // RewindFunction - _Unwind_Resume or the target equivalent.
215 FunctionCallee RewindFunction;
216 CallingConv::ID RewindFunctionCallingConv;
217 FunctionType *FTy;
218 const char *RewindName;
219 bool DoesRewindFunctionNeedExceptionObject;
220
221 if ((Pers == EHPersonality::GNU_CXX || Pers == EHPersonality::GNU_CXX_SjLj) &&
222 TargetTriple.isTargetEHABICompatible()) {
223 RewindName = TLI.getLibcallName(RTLIB::CXA_END_CLEANUP);
224 FTy = FunctionType::get(Type::getVoidTy(Ctx), false);
225 RewindFunctionCallingConv =
226 TLI.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP);
227 DoesRewindFunctionNeedExceptionObject = false;
228 } else {
229 RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
230 FTy =
231 FunctionType::get(Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), false);
232 RewindFunctionCallingConv = TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME);
233 DoesRewindFunctionNeedExceptionObject = true;
234 }
235 RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy);
236
237 // Create the basic block where the _Unwind_Resume call will live.
238 if (ResumesLeft == 1) {
239 // Instead of creating a new BB and PHI node, just append the call to
240 // _Unwind_Resume to the end of the single resume block.
241 ResumeInst *RI = Resumes.front();
242 BasicBlock *UnwindBB = RI->getParent();
243 Value *ExnObj = GetExceptionObject(RI);
244 llvm::SmallVector<Value *, 1> RewindFunctionArgs;
245 if (DoesRewindFunctionNeedExceptionObject)
246 RewindFunctionArgs.push_back(ExnObj);
247
248 // Call the rewind function.
249 CallInst *CI =
250 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
251 // The verifier requires that all calls of debug-info-bearing functions
252 // from debug-info-bearing functions have a debug location (for inlining
253 // purposes). Assign a dummy location to satisfy the constraint.
254 Function *RewindFn = dyn_cast<Function>(RewindFunction.getCallee());
255 if (RewindFn && RewindFn->getSubprogram())
256 if (DISubprogram *SP = F.getSubprogram())
257 CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, SP));
258 CI->setCallingConv(RewindFunctionCallingConv);
259
260 // We never expect _Unwind_Resume to return.
261 CI->setDoesNotReturn();
262 new UnreachableInst(Ctx, UnwindBB);
263 return true;
264 }
265
266 std::vector<DominatorTree::UpdateType> Updates;
267 Updates.reserve(Resumes.size());
268
269 llvm::SmallVector<Value *, 1> RewindFunctionArgs;
270
271 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
272 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft, "exn.obj",
273 UnwindBB);
274
275 // Extract the exception object from the ResumeInst and add it to the PHI node
276 // that feeds the _Unwind_Resume call.
277 for (ResumeInst *RI : Resumes) {
278 BasicBlock *Parent = RI->getParent();
279 BranchInst::Create(UnwindBB, Parent);
280 Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
281
282 Value *ExnObj = GetExceptionObject(RI);
283 PN->addIncoming(ExnObj, Parent);
284
285 ++NumResumesLowered;
286 }
287
288 if (DoesRewindFunctionNeedExceptionObject)
289 RewindFunctionArgs.push_back(PN);
290
291 // Call the function.
292 CallInst *CI =
293 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
294 CI->setCallingConv(RewindFunctionCallingConv);
295
296 // We never expect _Unwind_Resume to return.
297 CI->setDoesNotReturn();
298 new UnreachableInst(Ctx, UnwindBB);
299
300 if (DTU)
301 DTU->applyUpdates(Updates);
302
303 return true;
304 }
305
run()306 bool DwarfEHPrepare::run() {
307 bool Changed = InsertUnwindResumeCalls();
308
309 return Changed;
310 }
311
prepareDwarfEH(CodeGenOpt::Level OptLevel,Function & F,const TargetLowering & TLI,DominatorTree * DT,const TargetTransformInfo * TTI,const Triple & TargetTriple)312 static bool prepareDwarfEH(CodeGenOpt::Level OptLevel, Function &F,
313 const TargetLowering &TLI, DominatorTree *DT,
314 const TargetTransformInfo *TTI,
315 const Triple &TargetTriple) {
316 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
317
318 return DwarfEHPrepare(OptLevel, F, TLI, DT ? &DTU : nullptr, TTI,
319 TargetTriple)
320 .run();
321 }
322
323 namespace {
324
325 class DwarfEHPrepareLegacyPass : public FunctionPass {
326
327 CodeGenOpt::Level OptLevel;
328
329 public:
330 static char ID; // Pass identification, replacement for typeid.
331
DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel=CodeGenOpt::Default)332 DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel = CodeGenOpt::Default)
333 : FunctionPass(ID), OptLevel(OptLevel) {}
334
runOnFunction(Function & F)335 bool runOnFunction(Function &F) override {
336 const TargetMachine &TM =
337 getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
338 const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
339 DominatorTree *DT = nullptr;
340 const TargetTransformInfo *TTI = nullptr;
341 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
342 DT = &DTWP->getDomTree();
343 if (OptLevel != CodeGenOpt::None) {
344 if (!DT)
345 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
346 TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
347 }
348 return prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM.getTargetTriple());
349 }
350
getAnalysisUsage(AnalysisUsage & AU) const351 void getAnalysisUsage(AnalysisUsage &AU) const override {
352 AU.addRequired<TargetPassConfig>();
353 AU.addRequired<TargetTransformInfoWrapperPass>();
354 if (OptLevel != CodeGenOpt::None) {
355 AU.addRequired<DominatorTreeWrapperPass>();
356 AU.addRequired<TargetTransformInfoWrapperPass>();
357 }
358 AU.addPreserved<DominatorTreeWrapperPass>();
359 }
360
getPassName() const361 StringRef getPassName() const override {
362 return "Exception handling preparation";
363 }
364 };
365
366 } // end anonymous namespace
367
368 char DwarfEHPrepareLegacyPass::ID = 0;
369
370 INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
371 "Prepare DWARF exceptions", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)372 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
373 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
374 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
375 INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
376 "Prepare DWARF exceptions", false, false)
377
378 FunctionPass *llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel) {
379 return new DwarfEHPrepareLegacyPass(OptLevel);
380 }
381