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/Analysis/CFG.h"
18 #include "llvm/Analysis/DomTreeUpdater.h"
19 #include "llvm/Analysis/EHPersonalities.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/DerivedTypes.h"
28 #include "llvm/IR/Dominators.h"
29 #include "llvm/IR/Function.h"
30 #include "llvm/IR/Instructions.h"
31 #include "llvm/IR/Module.h"
32 #include "llvm/IR/Type.h"
33 #include "llvm/InitializePasses.h"
34 #include "llvm/Pass.h"
35 #include "llvm/Support/Casting.h"
36 #include "llvm/Target/TargetMachine.h"
37 #include "llvm/Transforms/Utils/Local.h"
42 #define DEBUG_TYPE "dwarfehprepare"
44 STATISTIC(NumResumesLowered
, "Number of resume calls lowered");
45 STATISTIC(NumCleanupLandingPadsUnreachable
,
46 "Number of cleanup landing pads found unreachable");
47 STATISTIC(NumCleanupLandingPadsRemaining
,
48 "Number of cleanup landing pads remaining");
49 STATISTIC(NumNoUnwind
, "Number of functions with nounwind");
50 STATISTIC(NumUnwind
, "Number of functions with unwind");
54 class DwarfEHPrepare
{
55 CodeGenOpt::Level OptLevel
;
57 // RewindFunction - _Unwind_Resume or the target equivalent.
58 FunctionCallee
&RewindFunction
;
61 const TargetLowering
&TLI
;
63 const TargetTransformInfo
*TTI
;
65 /// Return the exception object from the value passed into
66 /// the 'resume' instruction (typically an aggregate). Clean up any dead
67 /// instructions, including the 'resume' instruction.
68 Value
*GetExceptionObject(ResumeInst
*RI
);
70 /// Replace resumes that are not reachable from a cleanup landing pad with
71 /// unreachable and then simplify those blocks.
73 pruneUnreachableResumes(SmallVectorImpl
<ResumeInst
*> &Resumes
,
74 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
);
76 /// Convert the ResumeInsts that are still present
77 /// into calls to the appropriate _Unwind_Resume function.
78 bool InsertUnwindResumeCalls();
81 DwarfEHPrepare(CodeGenOpt::Level OptLevel_
, FunctionCallee
&RewindFunction_
,
82 Function
&F_
, const TargetLowering
&TLI_
, DomTreeUpdater
*DTU_
,
83 const TargetTransformInfo
*TTI_
)
84 : OptLevel(OptLevel_
), RewindFunction(RewindFunction_
), F(F_
), TLI(TLI_
),
85 DTU(DTU_
), TTI(TTI_
) {}
92 Value
*DwarfEHPrepare::GetExceptionObject(ResumeInst
*RI
) {
93 Value
*V
= RI
->getOperand(0);
94 Value
*ExnObj
= nullptr;
95 InsertValueInst
*SelIVI
= dyn_cast
<InsertValueInst
>(V
);
96 LoadInst
*SelLoad
= nullptr;
97 InsertValueInst
*ExcIVI
= nullptr;
98 bool EraseIVIs
= false;
101 if (SelIVI
->getNumIndices() == 1 && *SelIVI
->idx_begin() == 1) {
102 ExcIVI
= dyn_cast
<InsertValueInst
>(SelIVI
->getOperand(0));
103 if (ExcIVI
&& isa
<UndefValue
>(ExcIVI
->getOperand(0)) &&
104 ExcIVI
->getNumIndices() == 1 && *ExcIVI
->idx_begin() == 0) {
105 ExnObj
= ExcIVI
->getOperand(1);
106 SelLoad
= dyn_cast
<LoadInst
>(SelIVI
->getOperand(1));
113 ExnObj
= ExtractValueInst::Create(RI
->getOperand(0), 0, "exn.obj", RI
);
115 RI
->eraseFromParent();
118 if (SelIVI
->use_empty())
119 SelIVI
->eraseFromParent();
120 if (ExcIVI
->use_empty())
121 ExcIVI
->eraseFromParent();
122 if (SelLoad
&& SelLoad
->use_empty())
123 SelLoad
->eraseFromParent();
129 size_t DwarfEHPrepare::pruneUnreachableResumes(
130 SmallVectorImpl
<ResumeInst
*> &Resumes
,
131 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
) {
132 assert(DTU
&& "Should have DomTreeUpdater here.");
134 BitVector
ResumeReachable(Resumes
.size());
135 size_t ResumeIndex
= 0;
136 for (auto *RI
: Resumes
) {
137 for (auto *LP
: CleanupLPads
) {
138 if (isPotentiallyReachable(LP
, RI
, nullptr, &DTU
->getDomTree())) {
139 ResumeReachable
.set(ResumeIndex
);
146 // If everything is reachable, there is no change.
147 if (ResumeReachable
.all())
148 return Resumes
.size();
150 LLVMContext
&Ctx
= F
.getContext();
152 // Otherwise, insert unreachable instructions and call simplifycfg.
153 size_t ResumesLeft
= 0;
154 for (size_t I
= 0, E
= Resumes
.size(); I
< E
; ++I
) {
155 ResumeInst
*RI
= Resumes
[I
];
156 if (ResumeReachable
[I
]) {
157 Resumes
[ResumesLeft
++] = RI
;
159 BasicBlock
*BB
= RI
->getParent();
160 new UnreachableInst(Ctx
, RI
);
161 RI
->eraseFromParent();
162 simplifyCFG(BB
, *TTI
, DTU
);
165 Resumes
.resize(ResumesLeft
);
169 bool DwarfEHPrepare::InsertUnwindResumeCalls() {
170 SmallVector
<ResumeInst
*, 16> Resumes
;
171 SmallVector
<LandingPadInst
*, 16> CleanupLPads
;
172 if (F
.doesNotThrow())
176 for (BasicBlock
&BB
: F
) {
177 if (auto *RI
= dyn_cast
<ResumeInst
>(BB
.getTerminator()))
178 Resumes
.push_back(RI
);
179 if (auto *LP
= BB
.getLandingPadInst())
181 CleanupLPads
.push_back(LP
);
184 NumCleanupLandingPadsRemaining
+= CleanupLPads
.size();
189 // Check the personality, don't do anything if it's scope-based.
190 EHPersonality Pers
= classifyEHPersonality(F
.getPersonalityFn());
191 if (isScopedEHPersonality(Pers
))
194 LLVMContext
&Ctx
= F
.getContext();
196 size_t ResumesLeft
= Resumes
.size();
197 if (OptLevel
!= CodeGenOpt::None
) {
198 ResumesLeft
= pruneUnreachableResumes(Resumes
, CleanupLPads
);
199 #if LLVM_ENABLE_STATS
200 unsigned NumRemainingLPs
= 0;
201 for (BasicBlock
&BB
: F
) {
202 if (auto *LP
= BB
.getLandingPadInst())
206 NumCleanupLandingPadsUnreachable
+= CleanupLPads
.size() - NumRemainingLPs
;
207 NumCleanupLandingPadsRemaining
-= CleanupLPads
.size() - NumRemainingLPs
;
211 if (ResumesLeft
== 0)
212 return true; // We pruned them all.
214 // Find the rewind function if we didn't already.
215 if (!RewindFunction
) {
217 FunctionType::get(Type::getVoidTy(Ctx
), Type::getInt8PtrTy(Ctx
), false);
218 const char *RewindName
= TLI
.getLibcallName(RTLIB::UNWIND_RESUME
);
219 RewindFunction
= F
.getParent()->getOrInsertFunction(RewindName
, FTy
);
222 // Create the basic block where the _Unwind_Resume call will live.
223 if (ResumesLeft
== 1) {
224 // Instead of creating a new BB and PHI node, just append the call to
225 // _Unwind_Resume to the end of the single resume block.
226 ResumeInst
*RI
= Resumes
.front();
227 BasicBlock
*UnwindBB
= RI
->getParent();
228 Value
*ExnObj
= GetExceptionObject(RI
);
230 // Call the _Unwind_Resume function.
231 CallInst
*CI
= CallInst::Create(RewindFunction
, ExnObj
, "", UnwindBB
);
232 CI
->setCallingConv(TLI
.getLibcallCallingConv(RTLIB::UNWIND_RESUME
));
234 // We never expect _Unwind_Resume to return.
235 CI
->setDoesNotReturn();
236 new UnreachableInst(Ctx
, UnwindBB
);
240 std::vector
<DominatorTree::UpdateType
> Updates
;
241 Updates
.reserve(Resumes
.size());
243 BasicBlock
*UnwindBB
= BasicBlock::Create(Ctx
, "unwind_resume", &F
);
244 PHINode
*PN
= PHINode::Create(Type::getInt8PtrTy(Ctx
), ResumesLeft
, "exn.obj",
247 // Extract the exception object from the ResumeInst and add it to the PHI node
248 // that feeds the _Unwind_Resume call.
249 for (ResumeInst
*RI
: Resumes
) {
250 BasicBlock
*Parent
= RI
->getParent();
251 BranchInst::Create(UnwindBB
, Parent
);
252 Updates
.push_back({DominatorTree::Insert
, Parent
, UnwindBB
});
254 Value
*ExnObj
= GetExceptionObject(RI
);
255 PN
->addIncoming(ExnObj
, Parent
);
260 // Call the function.
261 CallInst
*CI
= CallInst::Create(RewindFunction
, PN
, "", UnwindBB
);
262 CI
->setCallingConv(TLI
.getLibcallCallingConv(RTLIB::UNWIND_RESUME
));
264 // We never expect _Unwind_Resume to return.
265 CI
->setDoesNotReturn();
266 new UnreachableInst(Ctx
, UnwindBB
);
269 DTU
->applyUpdates(Updates
);
274 bool DwarfEHPrepare::run() {
275 bool Changed
= InsertUnwindResumeCalls();
280 static bool prepareDwarfEH(CodeGenOpt::Level OptLevel
,
281 FunctionCallee
&RewindFunction
, Function
&F
,
282 const TargetLowering
&TLI
, DominatorTree
*DT
,
283 const TargetTransformInfo
*TTI
) {
284 DomTreeUpdater
DTU(DT
, DomTreeUpdater::UpdateStrategy::Lazy
);
286 return DwarfEHPrepare(OptLevel
, RewindFunction
, F
, TLI
, DT
? &DTU
: nullptr,
293 class DwarfEHPrepareLegacyPass
: public FunctionPass
{
294 // RewindFunction - _Unwind_Resume or the target equivalent.
295 FunctionCallee RewindFunction
= nullptr;
297 CodeGenOpt::Level OptLevel
;
300 static char ID
; // Pass identification, replacement for typeid.
302 DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel
= CodeGenOpt::Default
)
303 : FunctionPass(ID
), OptLevel(OptLevel
) {}
305 bool runOnFunction(Function
&F
) override
{
306 const TargetMachine
&TM
=
307 getAnalysis
<TargetPassConfig
>().getTM
<TargetMachine
>();
308 const TargetLowering
&TLI
= *TM
.getSubtargetImpl(F
)->getTargetLowering();
309 DominatorTree
*DT
= nullptr;
310 const TargetTransformInfo
*TTI
= nullptr;
311 if (auto *DTWP
= getAnalysisIfAvailable
<DominatorTreeWrapperPass
>())
312 DT
= &DTWP
->getDomTree();
313 if (OptLevel
!= CodeGenOpt::None
) {
315 DT
= &getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
316 TTI
= &getAnalysis
<TargetTransformInfoWrapperPass
>().getTTI(F
);
318 return prepareDwarfEH(OptLevel
, RewindFunction
, F
, TLI
, DT
, TTI
);
321 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
322 AU
.addRequired
<TargetPassConfig
>();
323 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
324 if (OptLevel
!= CodeGenOpt::None
) {
325 AU
.addRequired
<DominatorTreeWrapperPass
>();
326 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
328 AU
.addPreserved
<DominatorTreeWrapperPass
>();
331 StringRef
getPassName() const override
{
332 return "Exception handling preparation";
336 } // end anonymous namespace
338 char DwarfEHPrepareLegacyPass::ID
= 0;
340 INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass
, DEBUG_TYPE
,
341 "Prepare DWARF exceptions", false, false)
342 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
)
343 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig
)
344 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass
)
345 INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass
, DEBUG_TYPE
,
346 "Prepare DWARF exceptions", false, false)
348 FunctionPass
*llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel
) {
349 return new DwarfEHPrepareLegacyPass(OptLevel
);