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/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"
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",
117 RI
->eraseFromParent();
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();
131 size_t DwarfEHPrepare::pruneUnreachableResumes(
132 SmallVectorImpl
<ResumeInst
*> &Resumes
,
133 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
) {
134 assert(DTU
&& "Should have DomTreeUpdater here.");
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
);
148 // If everything is reachable, there is no change.
149 if (ResumeReachable
.all())
150 return Resumes
.size();
152 LLVMContext
&Ctx
= F
.getContext();
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
;
161 BasicBlock
*BB
= RI
->getParent();
162 new UnreachableInst(Ctx
, RI
->getIterator());
163 RI
->eraseFromParent();
164 simplifyCFG(BB
, *TTI
, DTU
);
167 Resumes
.resize(ResumesLeft
);
171 bool DwarfEHPrepare::InsertUnwindResumeCalls() {
172 SmallVector
<ResumeInst
*, 16> Resumes
;
173 SmallVector
<LandingPadInst
*, 16> CleanupLPads
;
174 if (F
.doesNotThrow())
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())
183 CleanupLPads
.push_back(LP
);
186 NumCleanupLandingPadsRemaining
+= CleanupLPads
.size();
191 // Check the personality, don't do anything if it's scope-based.
192 EHPersonality Pers
= classifyEHPersonality(F
.getPersonalityFn());
193 if (isScopedEHPersonality(Pers
))
196 LLVMContext
&Ctx
= F
.getContext();
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())
208 NumCleanupLandingPadsUnreachable
+= CleanupLPads
.size() - NumRemainingLPs
;
209 NumCleanupLandingPadsRemaining
-= CleanupLPads
.size() - NumRemainingLPs
;
213 if (ResumesLeft
== 0)
214 return true; // We pruned them all.
216 // RewindFunction - _Unwind_Resume or the target equivalent.
217 FunctionCallee RewindFunction
;
218 CallingConv::ID RewindFunctionCallingConv
;
220 const char *RewindName
;
221 bool DoesRewindFunctionNeedExceptionObject
;
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;
231 RewindName
= TLI
.getLibcallName(RTLIB::UNWIND_RESUME
);
232 FTy
= FunctionType::get(Type::getVoidTy(Ctx
), PointerType::getUnqual(Ctx
),
234 RewindFunctionCallingConv
= TLI
.getLibcallCallingConv(RTLIB::UNWIND_RESUME
);
235 DoesRewindFunctionNeedExceptionObject
= true;
237 RewindFunction
= F
.getParent()->getOrInsertFunction(RewindName
, FTy
);
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
);
250 // Call the rewind function.
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
);
262 // We never expect _Unwind_Resume to return.
263 CI
->setDoesNotReturn();
264 new UnreachableInst(Ctx
, UnwindBB
);
268 std::vector
<DominatorTree::UpdateType
> Updates
;
269 Updates
.reserve(Resumes
.size());
271 llvm::SmallVector
<Value
*, 1> RewindFunctionArgs
;
273 BasicBlock
*UnwindBB
= BasicBlock::Create(Ctx
, "unwind_resume", &F
);
274 PHINode
*PN
= PHINode::Create(PointerType::getUnqual(Ctx
), ResumesLeft
,
275 "exn.obj", UnwindBB
);
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
});
284 Value
*ExnObj
= GetExceptionObject(RI
);
285 PN
->addIncoming(ExnObj
, Parent
);
290 if (DoesRewindFunctionNeedExceptionObject
)
291 RewindFunctionArgs
.push_back(PN
);
293 // Call the function.
295 CallInst::Create(RewindFunction
, RewindFunctionArgs
, "", 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
>(RewindFunction
.getCallee());
300 if (RewindFn
&& RewindFn
->getSubprogram())
301 if (DISubprogram
*SP
= F
.getSubprogram())
302 CI
->setDebugLoc(DILocation::get(SP
->getContext(), 0, 0, SP
));
303 CI
->setCallingConv(RewindFunctionCallingConv
);
305 // We never expect _Unwind_Resume to return.
306 CI
->setDoesNotReturn();
307 new UnreachableInst(Ctx
, UnwindBB
);
310 DTU
->applyUpdates(Updates
);
315 bool DwarfEHPrepare::run() {
316 bool Changed
= InsertUnwindResumeCalls();
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
);
327 return DwarfEHPrepare(OptLevel
, F
, TLI
, DT
? &DTU
: nullptr, TTI
,
334 class DwarfEHPrepareLegacyPass
: public FunctionPass
{
336 CodeGenOptLevel OptLevel
;
339 static char ID
; // Pass identification, replacement for typeid.
341 DwarfEHPrepareLegacyPass(CodeGenOptLevel OptLevel
= CodeGenOptLevel::Default
)
342 : FunctionPass(ID
), OptLevel(OptLevel
) {}
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
) {
354 DT
= &getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
355 TTI
= &getAnalysis
<TargetTransformInfoWrapperPass
>().getTTI(F
);
357 return prepareDwarfEH(OptLevel
, F
, TLI
, DT
, TTI
, TM
.getTargetTriple());
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
>();
367 AU
.addPreserved
<DominatorTreeWrapperPass
>();
370 StringRef
getPassName() const override
{
371 return "Exception handling preparation";
375 } // end anonymous namespace
377 PreservedAnalyses
DwarfEHPreparePass::run(Function
&F
,
378 FunctionAnalysisManager
&FAM
) {
379 const auto &TLI
= *TM
->getSubtargetImpl(F
)->getTargetLowering();
380 auto *DT
= FAM
.getCachedResult
<DominatorTreeAnalysis
>(F
);
381 const TargetTransformInfo
*TTI
= nullptr;
382 auto OptLevel
= TM
->getOptLevel();
383 if (OptLevel
!= CodeGenOptLevel::None
) {
385 DT
= &FAM
.getResult
<DominatorTreeAnalysis
>(F
);
386 TTI
= &FAM
.getResult
<TargetIRAnalysis
>(F
);
389 prepareDwarfEH(OptLevel
, F
, TLI
, DT
, TTI
, TM
->getTargetTriple());
392 return PreservedAnalyses::all();
393 PreservedAnalyses PA
;
394 PA
.preserve
<DominatorTreeAnalysis
>();
398 char DwarfEHPrepareLegacyPass::ID
= 0;
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)
408 FunctionPass
*llvm::createDwarfEHPass(CodeGenOptLevel OptLevel
) {
409 return new DwarfEHPrepareLegacyPass(OptLevel
);