LLVM 19.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", RI);
115
116 RI->eraseFromParent();
117
118 if (EraseIVIs) {
119 if (SelIVI->use_empty())
120 SelIVI->eraseFromParent();
121 if (ExcIVI->use_empty())
122 ExcIVI->eraseFromParent();
123 if (SelLoad && SelLoad->use_empty())
124 SelLoad->eraseFromParent();
125 }
126
127 return ExnObj;
128}
129
130size_t DwarfEHPrepare::pruneUnreachableResumes(
132 SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
133 assert(DTU && "Should have DomTreeUpdater here.");
134
135 BitVector ResumeReachable(Resumes.size());
136 size_t ResumeIndex = 0;
137 for (auto *RI : Resumes) {
138 for (auto *LP : CleanupLPads) {
139 if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) {
140 ResumeReachable.set(ResumeIndex);
141 break;
142 }
143 }
144 ++ResumeIndex;
145 }
146
147 // If everything is reachable, there is no change.
148 if (ResumeReachable.all())
149 return Resumes.size();
150
151 LLVMContext &Ctx = F.getContext();
152
153 // Otherwise, insert unreachable instructions and call simplifycfg.
154 size_t ResumesLeft = 0;
155 for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
156 ResumeInst *RI = Resumes[I];
157 if (ResumeReachable[I]) {
158 Resumes[ResumesLeft++] = RI;
159 } else {
160 BasicBlock *BB = RI->getParent();
161 new UnreachableInst(Ctx, RI);
162 RI->eraseFromParent();
163 simplifyCFG(BB, *TTI, DTU);
164 }
165 }
166 Resumes.resize(ResumesLeft);
167 return ResumesLeft;
168}
169
170bool DwarfEHPrepare::InsertUnwindResumeCalls() {
173 if (F.doesNotThrow())
174 NumNoUnwind++;
175 else
176 NumUnwind++;
177 for (BasicBlock &BB : F) {
178 if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
179 Resumes.push_back(RI);
180 if (auto *LP = BB.getLandingPadInst())
181 if (LP->isCleanup())
182 CleanupLPads.push_back(LP);
183 }
184
185 NumCleanupLandingPadsRemaining += CleanupLPads.size();
186
187 if (Resumes.empty())
188 return false;
189
190 // Check the personality, don't do anything if it's scope-based.
191 EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn());
192 if (isScopedEHPersonality(Pers))
193 return false;
194
195 LLVMContext &Ctx = F.getContext();
196
197 size_t ResumesLeft = Resumes.size();
198 if (OptLevel != CodeGenOptLevel::None) {
199 ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads);
200#if LLVM_ENABLE_STATS
201 unsigned NumRemainingLPs = 0;
202 for (BasicBlock &BB : F) {
203 if (auto *LP = BB.getLandingPadInst())
204 if (LP->isCleanup())
205 NumRemainingLPs++;
206 }
207 NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs;
208 NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs;
209#endif
210 }
211
212 if (ResumesLeft == 0)
213 return true; // We pruned them all.
214
215 // RewindFunction - _Unwind_Resume or the target equivalent.
216 FunctionCallee RewindFunction;
217 CallingConv::ID RewindFunctionCallingConv;
218 FunctionType *FTy;
219 const char *RewindName;
220 bool DoesRewindFunctionNeedExceptionObject;
221
222 if ((Pers == EHPersonality::GNU_CXX || Pers == EHPersonality::GNU_CXX_SjLj) &&
223 TargetTriple.isTargetEHABICompatible()) {
224 RewindName = TLI.getLibcallName(RTLIB::CXA_END_CLEANUP);
225 FTy = FunctionType::get(Type::getVoidTy(Ctx), false);
226 RewindFunctionCallingConv =
227 TLI.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP);
228 DoesRewindFunctionNeedExceptionObject = false;
229 } else {
230 RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
231 FTy = FunctionType::get(Type::getVoidTy(Ctx), PointerType::getUnqual(Ctx),
232 false);
233 RewindFunctionCallingConv = TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME);
234 DoesRewindFunctionNeedExceptionObject = true;
235 }
236 RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy);
237
238 // Create the basic block where the _Unwind_Resume call will live.
239 if (ResumesLeft == 1) {
240 // Instead of creating a new BB and PHI node, just append the call to
241 // _Unwind_Resume to the end of the single resume block.
242 ResumeInst *RI = Resumes.front();
243 BasicBlock *UnwindBB = RI->getParent();
244 Value *ExnObj = GetExceptionObject(RI);
245 llvm::SmallVector<Value *, 1> RewindFunctionArgs;
246 if (DoesRewindFunctionNeedExceptionObject)
247 RewindFunctionArgs.push_back(ExnObj);
248
249 // Call the rewind function.
250 CallInst *CI =
251 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
252 // The verifier requires that all calls of debug-info-bearing functions
253 // from debug-info-bearing functions have a debug location (for inlining
254 // purposes). Assign a dummy location to satisfy the constraint.
255 Function *RewindFn = dyn_cast<Function>(RewindFunction.getCallee());
256 if (RewindFn && RewindFn->getSubprogram())
257 if (DISubprogram *SP = F.getSubprogram())
258 CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, SP));
259 CI->setCallingConv(RewindFunctionCallingConv);
260
261 // We never expect _Unwind_Resume to return.
262 CI->setDoesNotReturn();
263 new UnreachableInst(Ctx, UnwindBB);
264 return true;
265 }
266
267 std::vector<DominatorTree::UpdateType> Updates;
268 Updates.reserve(Resumes.size());
269
270 llvm::SmallVector<Value *, 1> RewindFunctionArgs;
271
272 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
273 PHINode *PN = PHINode::Create(PointerType::getUnqual(Ctx), ResumesLeft,
274 "exn.obj", UnwindBB);
275
276 // Extract the exception object from the ResumeInst and add it to the PHI node
277 // that feeds the _Unwind_Resume call.
278 for (ResumeInst *RI : Resumes) {
279 BasicBlock *Parent = RI->getParent();
280 BranchInst::Create(UnwindBB, Parent);
281 Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
282
283 Value *ExnObj = GetExceptionObject(RI);
284 PN->addIncoming(ExnObj, Parent);
285
286 ++NumResumesLowered;
287 }
288
289 if (DoesRewindFunctionNeedExceptionObject)
290 RewindFunctionArgs.push_back(PN);
291
292 // Call the function.
293 CallInst *CI =
294 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
295 CI->setCallingConv(RewindFunctionCallingConv);
296
297 // We never expect _Unwind_Resume to return.
298 CI->setDoesNotReturn();
299 new UnreachableInst(Ctx, UnwindBB);
300
301 if (DTU)
302 DTU->applyUpdates(Updates);
303
304 return true;
305}
306
307bool DwarfEHPrepare::run() {
308 bool Changed = InsertUnwindResumeCalls();
309
310 return Changed;
311}
312
314 const TargetLowering &TLI, DominatorTree *DT,
316 const Triple &TargetTriple) {
317 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
318
319 return DwarfEHPrepare(OptLevel, F, TLI, DT ? &DTU : nullptr, TTI,
320 TargetTriple)
321 .run();
322}
323
324namespace {
325
326class DwarfEHPrepareLegacyPass : public FunctionPass {
327
328 CodeGenOptLevel OptLevel;
329
330public:
331 static char ID; // Pass identification, replacement for typeid.
332
333 DwarfEHPrepareLegacyPass(CodeGenOptLevel OptLevel = CodeGenOptLevel::Default)
334 : FunctionPass(ID), OptLevel(OptLevel) {}
335
336 bool runOnFunction(Function &F) override {
337 const TargetMachine &TM =
338 getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
339 const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
340 DominatorTree *DT = nullptr;
341 const TargetTransformInfo *TTI = nullptr;
342 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
343 DT = &DTWP->getDomTree();
344 if (OptLevel != CodeGenOptLevel::None) {
345 if (!DT)
346 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
347 TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
348 }
349 return prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM.getTargetTriple());
350 }
351
352 void getAnalysisUsage(AnalysisUsage &AU) const override {
355 if (OptLevel != CodeGenOptLevel::None) {
358 }
360 }
361
362 StringRef getPassName() const override {
363 return "Exception handling preparation";
364 }
365};
366
367} // end anonymous namespace
368
371 const auto &TLI = *TM->getSubtargetImpl(F)->getTargetLowering();
373 const TargetTransformInfo *TTI = nullptr;
374 auto OptLevel = TM->getOptLevel();
375 if (OptLevel != CodeGenOptLevel::None) {
376 if (!DT)
379 }
380 bool Changed =
381 prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM->getTargetTriple());
382
383 if (!Changed)
384 return PreservedAnalyses::all();
387 return PA;
388}
389
390char DwarfEHPrepareLegacyPass::ID = 0;
391
392INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
393 "Prepare DWARF exceptions", false, false)
397INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
398 "Prepare DWARF exceptions", false, false)
399
401 return new DwarfEHPrepareLegacyPass(OptLevel);
402}
This file implements the BitVector class.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition: PassSupport.h:55
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:59
#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:167
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:348
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
Definition: PassManager.h:519
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:500
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:60
const LandingPadInst * getLandingPadInst() const
Return the landingpad instruction associated with the landing pad.
Definition: BasicBlock.cpp:721
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:207
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:229
static BranchInst * Create(BasicBlock *IfTrue, BasicBlock::iterator InsertBefore)
void setCallingConv(CallingConv::ID CC)
Definition: InstrTypes.h:1758
void setDoesNotReturn()
Definition: InstrTypes.h:2204
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr, BasicBlock::iterator InsertBefore)
Subprogram description.
Analysis pass which computes a DominatorTree.
Definition: Dominators.h:275
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:313
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, BasicBlock::iterator InsertBefore)
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:311
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:1828
This instruction inserts a struct field of array element value into an aggregate value.
unsigned getNumIndices() const
idx_iterator idx_begin() const
const BasicBlock * getParent() const
Definition: Instruction.h:150
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
Definition: Instruction.h:449
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:184
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, BasicBlock::iterator InsertBefore)
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:109
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:115
void preserve()
Mark an analysis as preserved.
Definition: Analysis.h:129
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:76
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
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:231