1 //===- DwarfEHPrepare - Prepare exception handling for code generation ----===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This pass mulches exception handling code into a form adapted to code
11 // generation. Required if using dwarf exception handling.
13 //===----------------------------------------------------------------------===//
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/EHPersonalities.h"
20 #include "llvm/Analysis/TargetTransformInfo.h"
21 #include "llvm/Transforms/Utils/Local.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/Pass.h"
35 #include "llvm/Support/Casting.h"
36 #include "llvm/Target/TargetMachine.h"
41 #define DEBUG_TYPE "dwarfehprepare"
43 STATISTIC(NumResumesLowered
, "Number of resume calls lowered");
47 class DwarfEHPrepare
: public FunctionPass
{
48 // RewindFunction - _Unwind_Resume or the target equivalent.
49 Constant
*RewindFunction
= nullptr;
51 DominatorTree
*DT
= nullptr;
52 const TargetLowering
*TLI
= nullptr;
54 bool InsertUnwindResumeCalls(Function
&Fn
);
55 Value
*GetExceptionObject(ResumeInst
*RI
);
57 pruneUnreachableResumes(Function
&Fn
,
58 SmallVectorImpl
<ResumeInst
*> &Resumes
,
59 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
);
62 static char ID
; // Pass identification, replacement for typeid.
64 DwarfEHPrepare() : FunctionPass(ID
) {}
66 bool runOnFunction(Function
&Fn
) override
;
68 bool doFinalization(Module
&M
) override
{
69 RewindFunction
= nullptr;
73 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
75 StringRef
getPassName() const override
{
76 return "Exception handling preparation";
80 } // end anonymous namespace
82 char DwarfEHPrepare::ID
= 0;
84 INITIALIZE_PASS_BEGIN(DwarfEHPrepare
, DEBUG_TYPE
,
85 "Prepare DWARF exceptions", false, false)
86 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
)
87 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig
)
88 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass
)
89 INITIALIZE_PASS_END(DwarfEHPrepare
, DEBUG_TYPE
,
90 "Prepare DWARF exceptions", false, false)
92 FunctionPass
*llvm::createDwarfEHPass() { return new DwarfEHPrepare(); }
94 void DwarfEHPrepare::getAnalysisUsage(AnalysisUsage
&AU
) const {
95 AU
.addRequired
<TargetPassConfig
>();
96 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
97 AU
.addRequired
<DominatorTreeWrapperPass
>();
100 /// GetExceptionObject - Return the exception object from the value passed into
101 /// the 'resume' instruction (typically an aggregate). Clean up any dead
102 /// instructions, including the 'resume' instruction.
103 Value
*DwarfEHPrepare::GetExceptionObject(ResumeInst
*RI
) {
104 Value
*V
= RI
->getOperand(0);
105 Value
*ExnObj
= nullptr;
106 InsertValueInst
*SelIVI
= dyn_cast
<InsertValueInst
>(V
);
107 LoadInst
*SelLoad
= nullptr;
108 InsertValueInst
*ExcIVI
= nullptr;
109 bool EraseIVIs
= false;
112 if (SelIVI
->getNumIndices() == 1 && *SelIVI
->idx_begin() == 1) {
113 ExcIVI
= dyn_cast
<InsertValueInst
>(SelIVI
->getOperand(0));
114 if (ExcIVI
&& isa
<UndefValue
>(ExcIVI
->getOperand(0)) &&
115 ExcIVI
->getNumIndices() == 1 && *ExcIVI
->idx_begin() == 0) {
116 ExnObj
= ExcIVI
->getOperand(1);
117 SelLoad
= dyn_cast
<LoadInst
>(SelIVI
->getOperand(1));
124 ExnObj
= ExtractValueInst::Create(RI
->getOperand(0), 0, "exn.obj", RI
);
126 RI
->eraseFromParent();
129 if (SelIVI
->use_empty())
130 SelIVI
->eraseFromParent();
131 if (ExcIVI
->use_empty())
132 ExcIVI
->eraseFromParent();
133 if (SelLoad
&& SelLoad
->use_empty())
134 SelLoad
->eraseFromParent();
140 /// Replace resumes that are not reachable from a cleanup landing pad with
141 /// unreachable and then simplify those blocks.
142 size_t DwarfEHPrepare::pruneUnreachableResumes(
143 Function
&Fn
, SmallVectorImpl
<ResumeInst
*> &Resumes
,
144 SmallVectorImpl
<LandingPadInst
*> &CleanupLPads
) {
145 BitVector
ResumeReachable(Resumes
.size());
146 size_t ResumeIndex
= 0;
147 for (auto *RI
: Resumes
) {
148 for (auto *LP
: CleanupLPads
) {
149 if (isPotentiallyReachable(LP
, RI
, DT
)) {
150 ResumeReachable
.set(ResumeIndex
);
157 // If everything is reachable, there is no change.
158 if (ResumeReachable
.all())
159 return Resumes
.size();
161 const TargetTransformInfo
&TTI
=
162 getAnalysis
<TargetTransformInfoWrapperPass
>().getTTI(Fn
);
163 LLVMContext
&Ctx
= Fn
.getContext();
165 // Otherwise, insert unreachable instructions and call simplifycfg.
166 size_t ResumesLeft
= 0;
167 for (size_t I
= 0, E
= Resumes
.size(); I
< E
; ++I
) {
168 ResumeInst
*RI
= Resumes
[I
];
169 if (ResumeReachable
[I
]) {
170 Resumes
[ResumesLeft
++] = RI
;
172 BasicBlock
*BB
= RI
->getParent();
173 new UnreachableInst(Ctx
, RI
);
174 RI
->eraseFromParent();
175 simplifyCFG(BB
, TTI
);
178 Resumes
.resize(ResumesLeft
);
182 /// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present
183 /// into calls to the appropriate _Unwind_Resume function.
184 bool DwarfEHPrepare::InsertUnwindResumeCalls(Function
&Fn
) {
185 SmallVector
<ResumeInst
*, 16> Resumes
;
186 SmallVector
<LandingPadInst
*, 16> CleanupLPads
;
187 for (BasicBlock
&BB
: Fn
) {
188 if (auto *RI
= dyn_cast
<ResumeInst
>(BB
.getTerminator()))
189 Resumes
.push_back(RI
);
190 if (auto *LP
= BB
.getLandingPadInst())
192 CleanupLPads
.push_back(LP
);
198 // Check the personality, don't do anything if it's scope-based.
199 EHPersonality Pers
= classifyEHPersonality(Fn
.getPersonalityFn());
200 if (isScopedEHPersonality(Pers
))
203 LLVMContext
&Ctx
= Fn
.getContext();
205 size_t ResumesLeft
= pruneUnreachableResumes(Fn
, Resumes
, CleanupLPads
);
206 if (ResumesLeft
== 0)
207 return true; // We pruned them all.
209 // Find the rewind function if we didn't already.
210 if (!RewindFunction
) {
211 FunctionType
*FTy
= FunctionType::get(Type::getVoidTy(Ctx
),
212 Type::getInt8PtrTy(Ctx
), false);
213 const char *RewindName
= TLI
->getLibcallName(RTLIB::UNWIND_RESUME
);
214 RewindFunction
= Fn
.getParent()->getOrInsertFunction(RewindName
, FTy
);
217 // Create the basic block where the _Unwind_Resume call will live.
218 if (ResumesLeft
== 1) {
219 // Instead of creating a new BB and PHI node, just append the call to
220 // _Unwind_Resume to the end of the single resume block.
221 ResumeInst
*RI
= Resumes
.front();
222 BasicBlock
*UnwindBB
= RI
->getParent();
223 Value
*ExnObj
= GetExceptionObject(RI
);
225 // Call the _Unwind_Resume function.
226 CallInst
*CI
= CallInst::Create(RewindFunction
, ExnObj
, "", UnwindBB
);
227 CI
->setCallingConv(TLI
->getLibcallCallingConv(RTLIB::UNWIND_RESUME
));
229 // We never expect _Unwind_Resume to return.
230 new UnreachableInst(Ctx
, UnwindBB
);
234 BasicBlock
*UnwindBB
= BasicBlock::Create(Ctx
, "unwind_resume", &Fn
);
235 PHINode
*PN
= PHINode::Create(Type::getInt8PtrTy(Ctx
), ResumesLeft
,
236 "exn.obj", UnwindBB
);
238 // Extract the exception object from the ResumeInst and add it to the PHI node
239 // that feeds the _Unwind_Resume call.
240 for (ResumeInst
*RI
: Resumes
) {
241 BasicBlock
*Parent
= RI
->getParent();
242 BranchInst::Create(UnwindBB
, Parent
);
244 Value
*ExnObj
= GetExceptionObject(RI
);
245 PN
->addIncoming(ExnObj
, Parent
);
250 // Call the function.
251 CallInst
*CI
= CallInst::Create(RewindFunction
, PN
, "", UnwindBB
);
252 CI
->setCallingConv(TLI
->getLibcallCallingConv(RTLIB::UNWIND_RESUME
));
254 // We never expect _Unwind_Resume to return.
255 new UnreachableInst(Ctx
, UnwindBB
);
259 bool DwarfEHPrepare::runOnFunction(Function
&Fn
) {
260 const TargetMachine
&TM
=
261 getAnalysis
<TargetPassConfig
>().getTM
<TargetMachine
>();
262 DT
= &getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
263 TLI
= TM
.getSubtargetImpl(Fn
)->getTargetLowering();
264 bool Changed
= InsertUnwindResumeCalls(Fn
);