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