1 //===- DwarfEHPrepare - Prepare exception handling for code generation ----===//
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
7 //===----------------------------------------------------------------------===//
9 // This pass mulches exception handling code into a form adapted to code
10 // generation. Required if using dwarf exception handling.
12 //===----------------------------------------------------------------------===//
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/RuntimeLibcalls.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"
45 #define DEBUG_TYPE "dwarf-eh-prepare"
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");
57 class DwarfEHPrepare
{
58 CodeGenOptLevel OptLevel
;
61 const TargetLowering
&TLI
;
63 const TargetTransformInfo
*TTI
;
64 const Triple
&TargetTriple
;
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
);
71 /// Replace resumes that are not reachable from a cleanup landing pad with
72 /// unreachable and then simplify those blocks.
74 pruneUnreachableResumes(SmallVectorImpl
<ResumeInst
*> &Resumes
,
75 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
);
77 /// Convert the ResumeInsts that are still present
78 /// into calls to the appropriate _Unwind_Resume function.
79 bool InsertUnwindResumeCalls();
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_
) {}
93 Value
*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;
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));
114 ExnObj
= ExtractValueInst::Create(RI
->getOperand(0), 0, "exn.obj", RI
);
116 RI
->eraseFromParent();
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();
130 size_t DwarfEHPrepare::pruneUnreachableResumes(
131 SmallVectorImpl
<ResumeInst
*> &Resumes
,
132 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
) {
133 assert(DTU
&& "Should have DomTreeUpdater here.");
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
);
147 // If everything is reachable, there is no change.
148 if (ResumeReachable
.all())
149 return Resumes
.size();
151 LLVMContext
&Ctx
= F
.getContext();
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
;
160 BasicBlock
*BB
= RI
->getParent();
161 new UnreachableInst(Ctx
, RI
);
162 RI
->eraseFromParent();
163 simplifyCFG(BB
, *TTI
, DTU
);
166 Resumes
.resize(ResumesLeft
);
170 bool DwarfEHPrepare::InsertUnwindResumeCalls() {
171 SmallVector
<ResumeInst
*, 16> Resumes
;
172 SmallVector
<LandingPadInst
*, 16> CleanupLPads
;
173 if (F
.doesNotThrow())
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())
182 CleanupLPads
.push_back(LP
);
185 NumCleanupLandingPadsRemaining
+= CleanupLPads
.size();
190 // Check the personality, don't do anything if it's scope-based.
191 EHPersonality Pers
= classifyEHPersonality(F
.getPersonalityFn());
192 if (isScopedEHPersonality(Pers
))
195 LLVMContext
&Ctx
= F
.getContext();
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())
207 NumCleanupLandingPadsUnreachable
+= CleanupLPads
.size() - NumRemainingLPs
;
208 NumCleanupLandingPadsRemaining
-= CleanupLPads
.size() - NumRemainingLPs
;
212 if (ResumesLeft
== 0)
213 return true; // We pruned them all.
215 // RewindFunction - _Unwind_Resume or the target equivalent.
216 FunctionCallee RewindFunction
;
217 CallingConv::ID RewindFunctionCallingConv
;
219 const char *RewindName
;
220 bool DoesRewindFunctionNeedExceptionObject
;
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;
230 RewindName
= TLI
.getLibcallName(RTLIB::UNWIND_RESUME
);
231 FTy
= FunctionType::get(Type::getVoidTy(Ctx
), PointerType::getUnqual(Ctx
),
233 RewindFunctionCallingConv
= TLI
.getLibcallCallingConv(RTLIB::UNWIND_RESUME
);
234 DoesRewindFunctionNeedExceptionObject
= true;
236 RewindFunction
= F
.getParent()->getOrInsertFunction(RewindName
, FTy
);
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
);
249 // Call the rewind function.
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
);
261 // We never expect _Unwind_Resume to return.
262 CI
->setDoesNotReturn();
263 new UnreachableInst(Ctx
, UnwindBB
);
267 std::vector
<DominatorTree::UpdateType
> Updates
;
268 Updates
.reserve(Resumes
.size());
270 llvm::SmallVector
<Value
*, 1> RewindFunctionArgs
;
272 BasicBlock
*UnwindBB
= BasicBlock::Create(Ctx
, "unwind_resume", &F
);
273 PHINode
*PN
= PHINode::Create(PointerType::getUnqual(Ctx
), ResumesLeft
,
274 "exn.obj", UnwindBB
);
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
});
283 Value
*ExnObj
= GetExceptionObject(RI
);
284 PN
->addIncoming(ExnObj
, Parent
);
289 if (DoesRewindFunctionNeedExceptionObject
)
290 RewindFunctionArgs
.push_back(PN
);
292 // Call the function.
294 CallInst::Create(RewindFunction
, RewindFunctionArgs
, "", UnwindBB
);
295 CI
->setCallingConv(RewindFunctionCallingConv
);
297 // We never expect _Unwind_Resume to return.
298 CI
->setDoesNotReturn();
299 new UnreachableInst(Ctx
, UnwindBB
);
302 DTU
->applyUpdates(Updates
);
307 bool DwarfEHPrepare::run() {
308 bool Changed
= InsertUnwindResumeCalls();
313 static bool prepareDwarfEH(CodeGenOptLevel OptLevel
, Function
&F
,
314 const TargetLowering
&TLI
, DominatorTree
*DT
,
315 const TargetTransformInfo
*TTI
,
316 const Triple
&TargetTriple
) {
317 DomTreeUpdater
DTU(DT
, DomTreeUpdater::UpdateStrategy::Lazy
);
319 return DwarfEHPrepare(OptLevel
, F
, TLI
, DT
? &DTU
: nullptr, TTI
,
326 class DwarfEHPrepareLegacyPass
: public FunctionPass
{
328 CodeGenOptLevel OptLevel
;
331 static char ID
; // Pass identification, replacement for typeid.
333 DwarfEHPrepareLegacyPass(CodeGenOptLevel OptLevel
= CodeGenOptLevel::Default
)
334 : FunctionPass(ID
), OptLevel(OptLevel
) {}
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
) {
346 DT
= &getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
347 TTI
= &getAnalysis
<TargetTransformInfoWrapperPass
>().getTTI(F
);
349 return prepareDwarfEH(OptLevel
, F
, TLI
, DT
, TTI
, TM
.getTargetTriple());
352 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
353 AU
.addRequired
<TargetPassConfig
>();
354 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
355 if (OptLevel
!= CodeGenOptLevel::None
) {
356 AU
.addRequired
<DominatorTreeWrapperPass
>();
357 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
359 AU
.addPreserved
<DominatorTreeWrapperPass
>();
362 StringRef
getPassName() const override
{
363 return "Exception handling preparation";
367 } // end anonymous namespace
369 PreservedAnalyses
DwarfEHPreparePass::run(Function
&F
,
370 FunctionAnalysisManager
&FAM
) {
371 const auto &TLI
= *TM
->getSubtargetImpl(F
)->getTargetLowering();
372 auto *DT
= FAM
.getCachedResult
<DominatorTreeAnalysis
>(F
);
373 const TargetTransformInfo
*TTI
= nullptr;
374 auto OptLevel
= TM
->getOptLevel();
375 if (OptLevel
!= CodeGenOptLevel::None
) {
377 DT
= &FAM
.getResult
<DominatorTreeAnalysis
>(F
);
378 TTI
= &FAM
.getResult
<TargetIRAnalysis
>(F
);
381 prepareDwarfEH(OptLevel
, F
, TLI
, DT
, TTI
, TM
->getTargetTriple());
384 return PreservedAnalyses::all();
385 PreservedAnalyses PA
;
386 PA
.preserve
<DominatorTreeAnalysis
>();
390 char DwarfEHPrepareLegacyPass::ID
= 0;
392 INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass
, DEBUG_TYPE
,
393 "Prepare DWARF exceptions", false, false)
394 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
)
395 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig
)
396 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass
)
397 INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass
, DEBUG_TYPE
,
398 "Prepare DWARF exceptions", false, false)
400 FunctionPass
*llvm::createDwarfEHPass(CodeGenOptLevel OptLevel
) {
401 return new DwarfEHPrepareLegacyPass(OptLevel
);