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/EHPersonalities.h"
19 #include "llvm/Analysis/TargetTransformInfo.h"
20 #include "llvm/Transforms/Utils/Local.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/Pass.h"
34 #include "llvm/Support/Casting.h"
35 #include "llvm/Target/TargetMachine.h"
40 #define DEBUG_TYPE "dwarfehprepare"
42 STATISTIC(NumResumesLowered
, "Number of resume calls lowered");
46 class DwarfEHPrepare
: public FunctionPass
{
47 // RewindFunction - _Unwind_Resume or the target equivalent.
48 FunctionCallee RewindFunction
= nullptr;
50 DominatorTree
*DT
= nullptr;
51 const TargetLowering
*TLI
= nullptr;
53 bool InsertUnwindResumeCalls(Function
&Fn
);
54 Value
*GetExceptionObject(ResumeInst
*RI
);
56 pruneUnreachableResumes(Function
&Fn
,
57 SmallVectorImpl
<ResumeInst
*> &Resumes
,
58 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
);
61 static char ID
; // Pass identification, replacement for typeid.
63 DwarfEHPrepare() : FunctionPass(ID
) {}
65 bool runOnFunction(Function
&Fn
) override
;
67 bool doFinalization(Module
&M
) override
{
68 RewindFunction
= nullptr;
72 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
74 StringRef
getPassName() const override
{
75 return "Exception handling preparation";
79 } // end anonymous namespace
81 char DwarfEHPrepare::ID
= 0;
83 INITIALIZE_PASS_BEGIN(DwarfEHPrepare
, DEBUG_TYPE
,
84 "Prepare DWARF exceptions", false, false)
85 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
)
86 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig
)
87 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass
)
88 INITIALIZE_PASS_END(DwarfEHPrepare
, DEBUG_TYPE
,
89 "Prepare DWARF exceptions", false, false)
91 FunctionPass
*llvm::createDwarfEHPass() { return new DwarfEHPrepare(); }
93 void DwarfEHPrepare::getAnalysisUsage(AnalysisUsage
&AU
) const {
94 AU
.addRequired
<TargetPassConfig
>();
95 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
96 AU
.addRequired
<DominatorTreeWrapperPass
>();
99 /// GetExceptionObject - Return the exception object from the value passed into
100 /// the 'resume' instruction (typically an aggregate). Clean up any dead
101 /// instructions, including the 'resume' instruction.
102 Value
*DwarfEHPrepare::GetExceptionObject(ResumeInst
*RI
) {
103 Value
*V
= RI
->getOperand(0);
104 Value
*ExnObj
= nullptr;
105 InsertValueInst
*SelIVI
= dyn_cast
<InsertValueInst
>(V
);
106 LoadInst
*SelLoad
= nullptr;
107 InsertValueInst
*ExcIVI
= nullptr;
108 bool EraseIVIs
= false;
111 if (SelIVI
->getNumIndices() == 1 && *SelIVI
->idx_begin() == 1) {
112 ExcIVI
= dyn_cast
<InsertValueInst
>(SelIVI
->getOperand(0));
113 if (ExcIVI
&& isa
<UndefValue
>(ExcIVI
->getOperand(0)) &&
114 ExcIVI
->getNumIndices() == 1 && *ExcIVI
->idx_begin() == 0) {
115 ExnObj
= ExcIVI
->getOperand(1);
116 SelLoad
= dyn_cast
<LoadInst
>(SelIVI
->getOperand(1));
123 ExnObj
= ExtractValueInst::Create(RI
->getOperand(0), 0, "exn.obj", RI
);
125 RI
->eraseFromParent();
128 if (SelIVI
->use_empty())
129 SelIVI
->eraseFromParent();
130 if (ExcIVI
->use_empty())
131 ExcIVI
->eraseFromParent();
132 if (SelLoad
&& SelLoad
->use_empty())
133 SelLoad
->eraseFromParent();
139 /// Replace resumes that are not reachable from a cleanup landing pad with
140 /// unreachable and then simplify those blocks.
141 size_t DwarfEHPrepare::pruneUnreachableResumes(
142 Function
&Fn
, SmallVectorImpl
<ResumeInst
*> &Resumes
,
143 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
) {
144 BitVector
ResumeReachable(Resumes
.size());
145 size_t ResumeIndex
= 0;
146 for (auto *RI
: Resumes
) {
147 for (auto *LP
: CleanupLPads
) {
148 if (isPotentiallyReachable(LP
, RI
, nullptr, DT
)) {
149 ResumeReachable
.set(ResumeIndex
);
156 // If everything is reachable, there is no change.
157 if (ResumeReachable
.all())
158 return Resumes
.size();
160 const TargetTransformInfo
&TTI
=
161 getAnalysis
<TargetTransformInfoWrapperPass
>().getTTI(Fn
);
162 LLVMContext
&Ctx
= Fn
.getContext();
164 // Otherwise, insert unreachable instructions and call simplifycfg.
165 size_t ResumesLeft
= 0;
166 for (size_t I
= 0, E
= Resumes
.size(); I
< E
; ++I
) {
167 ResumeInst
*RI
= Resumes
[I
];
168 if (ResumeReachable
[I
]) {
169 Resumes
[ResumesLeft
++] = RI
;
171 BasicBlock
*BB
= RI
->getParent();
172 new UnreachableInst(Ctx
, RI
);
173 RI
->eraseFromParent();
174 simplifyCFG(BB
, TTI
);
177 Resumes
.resize(ResumesLeft
);
181 /// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present
182 /// into calls to the appropriate _Unwind_Resume function.
183 bool DwarfEHPrepare::InsertUnwindResumeCalls(Function
&Fn
) {
184 SmallVector
<ResumeInst
*, 16> Resumes
;
185 SmallVector
<LandingPadInst
*, 16> CleanupLPads
;
186 for (BasicBlock
&BB
: Fn
) {
187 if (auto *RI
= dyn_cast
<ResumeInst
>(BB
.getTerminator()))
188 Resumes
.push_back(RI
);
189 if (auto *LP
= BB
.getLandingPadInst())
191 CleanupLPads
.push_back(LP
);
197 // Check the personality, don't do anything if it's scope-based.
198 EHPersonality Pers
= classifyEHPersonality(Fn
.getPersonalityFn());
199 if (isScopedEHPersonality(Pers
))
202 LLVMContext
&Ctx
= Fn
.getContext();
204 size_t ResumesLeft
= pruneUnreachableResumes(Fn
, Resumes
, CleanupLPads
);
205 if (ResumesLeft
== 0)
206 return true; // We pruned them all.
208 // Find the rewind function if we didn't already.
209 if (!RewindFunction
) {
210 FunctionType
*FTy
= FunctionType::get(Type::getVoidTy(Ctx
),
211 Type::getInt8PtrTy(Ctx
), false);
212 const char *RewindName
= TLI
->getLibcallName(RTLIB::UNWIND_RESUME
);
213 RewindFunction
= Fn
.getParent()->getOrInsertFunction(RewindName
, FTy
);
216 // Create the basic block where the _Unwind_Resume call will live.
217 if (ResumesLeft
== 1) {
218 // Instead of creating a new BB and PHI node, just append the call to
219 // _Unwind_Resume to the end of the single resume block.
220 ResumeInst
*RI
= Resumes
.front();
221 BasicBlock
*UnwindBB
= RI
->getParent();
222 Value
*ExnObj
= GetExceptionObject(RI
);
224 // Call the _Unwind_Resume function.
225 CallInst
*CI
= CallInst::Create(RewindFunction
, ExnObj
, "", UnwindBB
);
226 CI
->setCallingConv(TLI
->getLibcallCallingConv(RTLIB::UNWIND_RESUME
));
228 // We never expect _Unwind_Resume to return.
229 new UnreachableInst(Ctx
, UnwindBB
);
233 BasicBlock
*UnwindBB
= BasicBlock::Create(Ctx
, "unwind_resume", &Fn
);
234 PHINode
*PN
= PHINode::Create(Type::getInt8PtrTy(Ctx
), ResumesLeft
,
235 "exn.obj", UnwindBB
);
237 // Extract the exception object from the ResumeInst and add it to the PHI node
238 // that feeds the _Unwind_Resume call.
239 for (ResumeInst
*RI
: Resumes
) {
240 BasicBlock
*Parent
= RI
->getParent();
241 BranchInst::Create(UnwindBB
, Parent
);
243 Value
*ExnObj
= GetExceptionObject(RI
);
244 PN
->addIncoming(ExnObj
, Parent
);
249 // Call the function.
250 CallInst
*CI
= CallInst::Create(RewindFunction
, PN
, "", UnwindBB
);
251 CI
->setCallingConv(TLI
->getLibcallCallingConv(RTLIB::UNWIND_RESUME
));
253 // We never expect _Unwind_Resume to return.
254 new UnreachableInst(Ctx
, UnwindBB
);
258 bool DwarfEHPrepare::runOnFunction(Function
&Fn
) {
259 const TargetMachine
&TM
=
260 getAnalysis
<TargetPassConfig
>().getTM
<TargetMachine
>();
261 DT
= &getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
262 TLI
= TM
.getSubtargetImpl(Fn
)->getTargetLowering();
263 bool Changed
= InsertUnwindResumeCalls(Fn
);