LLVM 20.0.0git
DwarfEHPrepare.cpp
Go to the documentation of this file.
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
15#include "llvm/ADT/BitVector.h"
17#include "llvm/ADT/Statistic.h"
18#include "llvm/Analysis/CFG.h"
25#include "llvm/IR/BasicBlock.h"
26#include "llvm/IR/Constants.h"
29#include "llvm/IR/Dominators.h"
31#include "llvm/IR/Function.h"
33#include "llvm/IR/Module.h"
34#include "llvm/IR/Type.h"
36#include "llvm/Pass.h"
41#include <cstddef>
42
43using namespace llvm;
44
45#define DEBUG_TYPE "dwarf-eh-prepare"
46
47STATISTIC(NumResumesLowered, "Number of resume calls lowered");
48STATISTIC(NumCleanupLandingPadsUnreachable,
49 "Number of cleanup landing pads found unreachable");
50STATISTIC(NumCleanupLandingPadsRemaining,
51 "Number of cleanup landing pads remaining");
52STATISTIC(NumNoUnwind, "Number of functions with nounwind");
53STATISTIC(NumUnwind, "Number of functions with unwind");
54
55namespace {
56
57class DwarfEHPrepare {
58 CodeGenOptLevel OptLevel;
59
60 Function &F;
61 const TargetLowering &TLI;
62 DomTreeUpdater *DTU;
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,
76
77 /// Convert the ResumeInsts that are still present
78 /// into calls to the appropriate _Unwind_Resume function.
79 bool InsertUnwindResumeCalls();
80
81public:
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
93Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
94 Value *V = RI->getOperand(0);
95 Value *ExnObj = nullptr;
96 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(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>(SelIVI->getOperand(0));
104 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
105 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
106 ExnObj = ExcIVI->getOperand(1);
107 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
108 EraseIVIs = true;
109 }
110 }
111 }
112
113 if (!ExnObj)
114 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj",
115 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
131size_t DwarfEHPrepare::pruneUnreachableResumes(
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(LP, RI, nullptr, &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, DTU);
165 }
166 }
167 Resumes.resize(ResumesLeft);
168 return ResumesLeft;
169}
170
171bool DwarfEHPrepare::InsertUnwindResumeCalls() {
174 if (F.doesNotThrow())
175 NumNoUnwind++;
176 else
177 NumUnwind++;
178 for (BasicBlock &BB : F) {
179 if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
180 Resumes.push_back(RI);
181 if (auto *LP = BB.getLandingPadInst())
182 if (LP->isCleanup())
183 CleanupLPads.push_back(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(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(RTLIB::CXA_END_CLEANUP);
226 FTy = FunctionType::get(Type::getVoidTy(Ctx), false);
227 RewindFunctionCallingConv =
228 TLI.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP);
229 DoesRewindFunctionNeedExceptionObject = false;
230 } else {
231 RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
232 FTy = FunctionType::get(Type::getVoidTy(Ctx), PointerType::getUnqual(Ctx),
233 false);
234 RewindFunctionCallingConv = TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME);
235 DoesRewindFunctionNeedExceptionObject = true;
236 }
237 RewindFunction = F.getParent()->getOrInsertFunction(RewindName, 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(ExnObj);
249
250 // Call the rewind function.
251 CallInst *CI =
252 CallInst::Create(RewindFunction, RewindFunctionArgs, "", 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>(RewindFunction.getCallee());
257 if (RewindFn && RewindFn->getSubprogram())
258 if (DISubprogram *SP = F.getSubprogram())
259 CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, 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(Resumes.size());
270
271 llvm::SmallVector<Value *, 1> RewindFunctionArgs;
272
273 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
274 PHINode *PN = PHINode::Create(PointerType::getUnqual(Ctx), ResumesLeft,
275 "exn.obj", 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(UnwindBB, Parent);
282 Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
283
284 Value *ExnObj = GetExceptionObject(RI);
285 PN->addIncoming(ExnObj, Parent);
286
287 ++NumResumesLowered;
288 }
289
290 if (DoesRewindFunctionNeedExceptionObject)
291 RewindFunctionArgs.push_back(PN);
292
293 // Call the function.
294 CallInst *CI =
295 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
296 CI->setCallingConv(RewindFunctionCallingConv);
297
298 // We never expect _Unwind_Resume to return.
299 CI->setDoesNotReturn();
300 new UnreachableInst(Ctx, UnwindBB);
301
302 if (DTU)
303 DTU->applyUpdates(Updates);
304
305 return true;
306}
307
308bool DwarfEHPrepare::run() {
309 bool Changed = InsertUnwindResumeCalls();
310
311 return Changed;
312}
313
315 const TargetLowering &TLI, DominatorTree *DT,
317 const Triple &TargetTriple) {
318 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
319
320 return DwarfEHPrepare(OptLevel, F, TLI, DT ? &DTU : nullptr, TTI,
321 TargetTriple)
322 .run();
323}
324
325namespace {
326
327class DwarfEHPrepareLegacyPass : public FunctionPass {
328
329 CodeGenOptLevel OptLevel;
330
331public:
332 static char ID; // Pass identification, replacement for typeid.
333
334 DwarfEHPrepareLegacyPass(CodeGenOptLevel OptLevel = CodeGenOptLevel::Default)
335 : FunctionPass(ID), OptLevel(OptLevel) {}
336
337 bool runOnFunction(Function &F) override {
338 const TargetMachine &TM =
339 getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
340 const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
341 DominatorTree *DT = nullptr;
342 const TargetTransformInfo *TTI = nullptr;
343 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
344 DT = &DTWP->getDomTree();
345 if (OptLevel != CodeGenOptLevel::None) {
346 if (!DT)
347 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
348 TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
349 }
350 return prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM.getTargetTriple());
351 }
352
353 void getAnalysisUsage(AnalysisUsage &AU) const override {
356 if (OptLevel != CodeGenOptLevel::None) {
359 }
361 }
362
363 StringRef getPassName() const override {
364 return "Exception handling preparation";
365 }
366};
367
368} // end anonymous namespace
369
372 const auto &TLI = *TM->getSubtargetImpl(F)->getTargetLowering();
374 const TargetTransformInfo *TTI = nullptr;
375 auto OptLevel = TM->getOptLevel();
376 if (OptLevel != CodeGenOptLevel::None) {
377 if (!DT)
380 }
381 bool Changed =
382 prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM->getTargetTriple());
383
384 if (!Changed)
385 return PreservedAnalyses::all();
388 return PA;
389}
390
391char DwarfEHPrepareLegacyPass::ID = 0;
392
393INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
394 "Prepare DWARF exceptions", false, false)
398INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
399 "Prepare DWARF exceptions", false, false)
400
402 return new DwarfEHPrepareLegacyPass(OptLevel);
403}
This file implements the BitVector class.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Prepare DWARF exceptions
static bool prepareDwarfEH(CodeGenOptLevel OptLevel, Function &F, const TargetLowering &TLI, DominatorTree *DT, const TargetTransformInfo *TTI, const Triple &TargetTriple)
#define DEBUG_TYPE
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Module.h This file contains the declarations for the Module class.
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition: PassSupport.h:55
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:57
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:52
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition: Statistic.h:166
This file describes how to lower LLVM code to machine code.
Target-Independent Code Generator Pass Configuration Options pass.
This pass exposes codegen information to IR-level passes.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:253
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
Definition: PassManager.h:424
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:405
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
const LandingPadInst * getLandingPadInst() const
Return the landingpad instruction associated with the landing pad.
Definition: BasicBlock.cpp:681
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:212
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Definition: BasicBlock.h:239
static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)
void setCallingConv(CallingConv::ID CC)
Definition: InstrTypes.h:1527
void setDoesNotReturn()
Definition: InstrTypes.h:2009
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Subprogram description.
Analysis pass which computes a DominatorTree.
Definition: Dominators.h:279
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:317
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition: Dominators.h:162
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
static ExtractValueInst * Create(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:168
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
DISubprogram * getSubprogram() const
Get the attached subprogram.
Definition: Metadata.cpp:1837
This instruction inserts a struct field of array element value into an aggregate value.
unsigned getNumIndices() const
idx_iterator idx_begin() const
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:92
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
Definition: Instruction.h:463
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
An instruction for reading from memory.
Definition: Instructions.h:174
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:98
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:111
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:117
void preserve()
Mark an analysis as preserved.
Definition: Analysis.h:131
Resume the propagation of an exception.
bool empty() const
Definition: SmallVector.h:94
size_t size() const
Definition: SmallVector.h:91
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Analysis pass providing the TargetTransformInfo.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:77
Target-Independent Code Generator Pass Configuration Options.
Wrapper pass for TargetTransformInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
static Type * getVoidTy(LLVMContext &C)
This function has undefined behavior.
Value * getOperand(unsigned i) const
Definition: User.h:169
LLVM Value Representation.
Definition: Value.h:74
bool use_empty() const
Definition: Value.h:344
const ParentTy * getParent() const
Definition: ilist_node.h:32
self_iterator getIterator()
Definition: ilist_node.h:132
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool isScopedEHPersonality(EHPersonality Pers)
Returns true if this personality uses scope-style EH IR instructions: catchswitch,...
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
FunctionPass * createDwarfEHPass(CodeGenOptLevel OptLevel)
createDwarfEHPass - This pass mulches exception handling code into a form adapted to code generation.
CodeGenOptLevel
Code generation optimization level.
Definition: CodeGen.h:54
bool simplifyCFG(BasicBlock *BB, const TargetTransformInfo &TTI, DomTreeUpdater *DTU=nullptr, const SimplifyCFGOptions &Options={}, ArrayRef< WeakVH > LoopHeaders={})
bool isPotentiallyReachable(const Instruction *From, const Instruction *To, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet=nullptr, const DominatorTree *DT=nullptr, const LoopInfo *LI=nullptr)
Determine whether instruction 'To' is reachable from 'From', without passing through any blocks in Ex...
Definition: CFG.cpp:281