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/ADT/BitVector.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/ADT/Triple.h"
18 #include "llvm/Analysis/CFG.h"
19 #include "llvm/Analysis/DomTreeUpdater.h"
20 #include "llvm/Analysis/EHPersonalities.h"
21 #include "llvm/Analysis/TargetTransformInfo.h"
22 #include "llvm/CodeGen/RuntimeLibcalls.h"
23 #include "llvm/CodeGen/TargetLowering.h"
24 #include "llvm/CodeGen/TargetPassConfig.h"
25 #include "llvm/CodeGen/TargetSubtargetInfo.h"
26 #include "llvm/IR/BasicBlock.h"
27 #include "llvm/IR/Constants.h"
28 #include "llvm/IR/DerivedTypes.h"
29 #include "llvm/IR/Dominators.h"
30 #include "llvm/IR/Function.h"
31 #include "llvm/IR/Instructions.h"
32 #include "llvm/IR/Module.h"
33 #include "llvm/IR/Type.h"
34 #include "llvm/InitializePasses.h"
35 #include "llvm/Pass.h"
36 #include "llvm/Support/Casting.h"
37 #include "llvm/Target/TargetMachine.h"
38 #include "llvm/Transforms/Utils/Local.h"
43 #define DEBUG_TYPE "dwarfehprepare"
45 STATISTIC(NumResumesLowered
, "Number of resume calls lowered");
46 STATISTIC(NumCleanupLandingPadsUnreachable
,
47 "Number of cleanup landing pads found unreachable");
48 STATISTIC(NumCleanupLandingPadsRemaining
,
49 "Number of cleanup landing pads remaining");
50 STATISTIC(NumNoUnwind
, "Number of functions with nounwind");
51 STATISTIC(NumUnwind
, "Number of functions with unwind");
55 class DwarfEHPrepare
{
56 CodeGenOpt::Level OptLevel
;
59 const TargetLowering
&TLI
;
61 const TargetTransformInfo
*TTI
;
62 const Triple
&TargetTriple
;
64 /// Return the exception object from the value passed into
65 /// the 'resume' instruction (typically an aggregate). Clean up any dead
66 /// instructions, including the 'resume' instruction.
67 Value
*GetExceptionObject(ResumeInst
*RI
);
69 /// Replace resumes that are not reachable from a cleanup landing pad with
70 /// unreachable and then simplify those blocks.
72 pruneUnreachableResumes(SmallVectorImpl
<ResumeInst
*> &Resumes
,
73 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
);
75 /// Convert the ResumeInsts that are still present
76 /// into calls to the appropriate _Unwind_Resume function.
77 bool InsertUnwindResumeCalls();
80 DwarfEHPrepare(CodeGenOpt::Level OptLevel_
, Function
&F_
,
81 const TargetLowering
&TLI_
, DomTreeUpdater
*DTU_
,
82 const TargetTransformInfo
*TTI_
, const Triple
&TargetTriple_
)
83 : OptLevel(OptLevel_
), F(F_
), TLI(TLI_
), DTU(DTU_
), TTI(TTI_
),
84 TargetTriple(TargetTriple_
) {}
91 Value
*DwarfEHPrepare::GetExceptionObject(ResumeInst
*RI
) {
92 Value
*V
= RI
->getOperand(0);
93 Value
*ExnObj
= nullptr;
94 InsertValueInst
*SelIVI
= dyn_cast
<InsertValueInst
>(V
);
95 LoadInst
*SelLoad
= nullptr;
96 InsertValueInst
*ExcIVI
= nullptr;
97 bool EraseIVIs
= false;
100 if (SelIVI
->getNumIndices() == 1 && *SelIVI
->idx_begin() == 1) {
101 ExcIVI
= dyn_cast
<InsertValueInst
>(SelIVI
->getOperand(0));
102 if (ExcIVI
&& isa
<UndefValue
>(ExcIVI
->getOperand(0)) &&
103 ExcIVI
->getNumIndices() == 1 && *ExcIVI
->idx_begin() == 0) {
104 ExnObj
= ExcIVI
->getOperand(1);
105 SelLoad
= dyn_cast
<LoadInst
>(SelIVI
->getOperand(1));
112 ExnObj
= ExtractValueInst::Create(RI
->getOperand(0), 0, "exn.obj", RI
);
114 RI
->eraseFromParent();
117 if (SelIVI
->use_empty())
118 SelIVI
->eraseFromParent();
119 if (ExcIVI
->use_empty())
120 ExcIVI
->eraseFromParent();
121 if (SelLoad
&& SelLoad
->use_empty())
122 SelLoad
->eraseFromParent();
128 size_t DwarfEHPrepare::pruneUnreachableResumes(
129 SmallVectorImpl
<ResumeInst
*> &Resumes
,
130 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
) {
131 assert(DTU
&& "Should have DomTreeUpdater here.");
133 BitVector
ResumeReachable(Resumes
.size());
134 size_t ResumeIndex
= 0;
135 for (auto *RI
: Resumes
) {
136 for (auto *LP
: CleanupLPads
) {
137 if (isPotentiallyReachable(LP
, RI
, nullptr, &DTU
->getDomTree())) {
138 ResumeReachable
.set(ResumeIndex
);
145 // If everything is reachable, there is no change.
146 if (ResumeReachable
.all())
147 return Resumes
.size();
149 LLVMContext
&Ctx
= F
.getContext();
151 // Otherwise, insert unreachable instructions and call simplifycfg.
152 size_t ResumesLeft
= 0;
153 for (size_t I
= 0, E
= Resumes
.size(); I
< E
; ++I
) {
154 ResumeInst
*RI
= Resumes
[I
];
155 if (ResumeReachable
[I
]) {
156 Resumes
[ResumesLeft
++] = RI
;
158 BasicBlock
*BB
= RI
->getParent();
159 new UnreachableInst(Ctx
, RI
);
160 RI
->eraseFromParent();
161 simplifyCFG(BB
, *TTI
, DTU
);
164 Resumes
.resize(ResumesLeft
);
168 bool DwarfEHPrepare::InsertUnwindResumeCalls() {
169 SmallVector
<ResumeInst
*, 16> Resumes
;
170 SmallVector
<LandingPadInst
*, 16> CleanupLPads
;
171 if (F
.doesNotThrow())
175 for (BasicBlock
&BB
: F
) {
176 if (auto *RI
= dyn_cast
<ResumeInst
>(BB
.getTerminator()))
177 Resumes
.push_back(RI
);
178 if (auto *LP
= BB
.getLandingPadInst())
180 CleanupLPads
.push_back(LP
);
183 NumCleanupLandingPadsRemaining
+= CleanupLPads
.size();
188 // Check the personality, don't do anything if it's scope-based.
189 EHPersonality Pers
= classifyEHPersonality(F
.getPersonalityFn());
190 if (isScopedEHPersonality(Pers
))
193 LLVMContext
&Ctx
= F
.getContext();
195 size_t ResumesLeft
= Resumes
.size();
196 if (OptLevel
!= CodeGenOpt::None
) {
197 ResumesLeft
= pruneUnreachableResumes(Resumes
, CleanupLPads
);
198 #if LLVM_ENABLE_STATS
199 unsigned NumRemainingLPs
= 0;
200 for (BasicBlock
&BB
: F
) {
201 if (auto *LP
= BB
.getLandingPadInst())
205 NumCleanupLandingPadsUnreachable
+= CleanupLPads
.size() - NumRemainingLPs
;
206 NumCleanupLandingPadsRemaining
-= CleanupLPads
.size() - NumRemainingLPs
;
210 if (ResumesLeft
== 0)
211 return true; // We pruned them all.
213 // RewindFunction - _Unwind_Resume or the target equivalent.
214 FunctionCallee RewindFunction
;
215 CallingConv::ID RewindFunctionCallingConv
;
217 const char *RewindName
;
218 bool DoesRewindFunctionNeedExceptionObject
;
220 if ((Pers
== EHPersonality::GNU_CXX
|| Pers
== EHPersonality::GNU_CXX_SjLj
) &&
221 TargetTriple
.isTargetEHABICompatible()) {
222 RewindName
= TLI
.getLibcallName(RTLIB::CXA_END_CLEANUP
);
223 FTy
= FunctionType::get(Type::getVoidTy(Ctx
), false);
224 RewindFunctionCallingConv
=
225 TLI
.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP
);
226 DoesRewindFunctionNeedExceptionObject
= false;
228 RewindName
= TLI
.getLibcallName(RTLIB::UNWIND_RESUME
);
230 FunctionType::get(Type::getVoidTy(Ctx
), Type::getInt8PtrTy(Ctx
), false);
231 RewindFunctionCallingConv
= TLI
.getLibcallCallingConv(RTLIB::UNWIND_RESUME
);
232 DoesRewindFunctionNeedExceptionObject
= true;
234 RewindFunction
= F
.getParent()->getOrInsertFunction(RewindName
, FTy
);
236 // Create the basic block where the _Unwind_Resume call will live.
237 if (ResumesLeft
== 1) {
238 // Instead of creating a new BB and PHI node, just append the call to
239 // _Unwind_Resume to the end of the single resume block.
240 ResumeInst
*RI
= Resumes
.front();
241 BasicBlock
*UnwindBB
= RI
->getParent();
242 Value
*ExnObj
= GetExceptionObject(RI
);
243 llvm::SmallVector
<Value
*, 1> RewindFunctionArgs
;
244 if (DoesRewindFunctionNeedExceptionObject
)
245 RewindFunctionArgs
.push_back(ExnObj
);
247 // Call the rewind function.
249 CallInst::Create(RewindFunction
, RewindFunctionArgs
, "", UnwindBB
);
250 CI
->setCallingConv(RewindFunctionCallingConv
);
252 // We never expect _Unwind_Resume to return.
253 CI
->setDoesNotReturn();
254 new UnreachableInst(Ctx
, UnwindBB
);
258 std::vector
<DominatorTree::UpdateType
> Updates
;
259 Updates
.reserve(Resumes
.size());
261 llvm::SmallVector
<Value
*, 1> RewindFunctionArgs
;
263 BasicBlock
*UnwindBB
= BasicBlock::Create(Ctx
, "unwind_resume", &F
);
264 PHINode
*PN
= PHINode::Create(Type::getInt8PtrTy(Ctx
), ResumesLeft
, "exn.obj",
267 // Extract the exception object from the ResumeInst and add it to the PHI node
268 // that feeds the _Unwind_Resume call.
269 for (ResumeInst
*RI
: Resumes
) {
270 BasicBlock
*Parent
= RI
->getParent();
271 BranchInst::Create(UnwindBB
, Parent
);
272 Updates
.push_back({DominatorTree::Insert
, Parent
, UnwindBB
});
274 Value
*ExnObj
= GetExceptionObject(RI
);
275 PN
->addIncoming(ExnObj
, Parent
);
280 if (DoesRewindFunctionNeedExceptionObject
)
281 RewindFunctionArgs
.push_back(PN
);
283 // Call the function.
285 CallInst::Create(RewindFunction
, RewindFunctionArgs
, "", UnwindBB
);
286 CI
->setCallingConv(RewindFunctionCallingConv
);
288 // We never expect _Unwind_Resume to return.
289 CI
->setDoesNotReturn();
290 new UnreachableInst(Ctx
, UnwindBB
);
293 DTU
->applyUpdates(Updates
);
298 bool DwarfEHPrepare::run() {
299 bool Changed
= InsertUnwindResumeCalls();
304 static bool prepareDwarfEH(CodeGenOpt::Level OptLevel
, Function
&F
,
305 const TargetLowering
&TLI
, DominatorTree
*DT
,
306 const TargetTransformInfo
*TTI
,
307 const Triple
&TargetTriple
) {
308 DomTreeUpdater
DTU(DT
, DomTreeUpdater::UpdateStrategy::Lazy
);
310 return DwarfEHPrepare(OptLevel
, F
, TLI
, DT
? &DTU
: nullptr, TTI
,
317 class DwarfEHPrepareLegacyPass
: public FunctionPass
{
319 CodeGenOpt::Level OptLevel
;
322 static char ID
; // Pass identification, replacement for typeid.
324 DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel
= CodeGenOpt::Default
)
325 : FunctionPass(ID
), OptLevel(OptLevel
) {}
327 bool runOnFunction(Function
&F
) override
{
328 const TargetMachine
&TM
=
329 getAnalysis
<TargetPassConfig
>().getTM
<TargetMachine
>();
330 const TargetLowering
&TLI
= *TM
.getSubtargetImpl(F
)->getTargetLowering();
331 DominatorTree
*DT
= nullptr;
332 const TargetTransformInfo
*TTI
= nullptr;
333 if (auto *DTWP
= getAnalysisIfAvailable
<DominatorTreeWrapperPass
>())
334 DT
= &DTWP
->getDomTree();
335 if (OptLevel
!= CodeGenOpt::None
) {
337 DT
= &getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
338 TTI
= &getAnalysis
<TargetTransformInfoWrapperPass
>().getTTI(F
);
340 return prepareDwarfEH(OptLevel
, F
, TLI
, DT
, TTI
, TM
.getTargetTriple());
343 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
344 AU
.addRequired
<TargetPassConfig
>();
345 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
346 if (OptLevel
!= CodeGenOpt::None
) {
347 AU
.addRequired
<DominatorTreeWrapperPass
>();
348 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
350 AU
.addPreserved
<DominatorTreeWrapperPass
>();
353 StringRef
getPassName() const override
{
354 return "Exception handling preparation";
358 } // end anonymous namespace
360 char DwarfEHPrepareLegacyPass::ID
= 0;
362 INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass
, DEBUG_TYPE
,
363 "Prepare DWARF exceptions", false, false)
364 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
)
365 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig
)
366 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass
)
367 INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass
, DEBUG_TYPE
,
368 "Prepare DWARF exceptions", false, false)
370 FunctionPass
*llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel
) {
371 return new DwarfEHPrepareLegacyPass(OptLevel
);