]>
git.proxmox.com Git - rustc.git/blob - src/llvm/lib/CodeGen/DwarfEHPrepare.cpp
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/CodeGen/Passes.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/IR/CallSite.h"
18 #include "llvm/IR/Dominators.h"
19 #include "llvm/IR/Function.h"
20 #include "llvm/IR/Instructions.h"
21 #include "llvm/IR/IntrinsicInst.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/MC/MCAsmInfo.h"
24 #include "llvm/Pass.h"
25 #include "llvm/Target/TargetLowering.h"
26 #include "llvm/Target/TargetSubtargetInfo.h"
27 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
28 #include "llvm/Transforms/Utils/SSAUpdater.h"
31 #define DEBUG_TYPE "dwarfehprepare"
33 STATISTIC(NumResumesLowered
, "Number of resume calls lowered");
36 class DwarfEHPrepare
: public FunctionPass
{
37 const TargetMachine
*TM
;
39 // RewindFunction - _Unwind_Resume or the target equivalent.
40 Constant
*RewindFunction
;
42 bool InsertUnwindResumeCalls(Function
&Fn
);
43 Value
*GetExceptionObject(ResumeInst
*RI
);
46 static char ID
; // Pass identification, replacement for typeid.
47 DwarfEHPrepare(const TargetMachine
*TM
)
48 : FunctionPass(ID
), TM(TM
), RewindFunction(nullptr) {
49 initializeDominatorTreeWrapperPassPass(*PassRegistry::getPassRegistry());
52 bool runOnFunction(Function
&Fn
) override
;
54 bool doFinalization(Module
&M
) override
{
55 RewindFunction
= nullptr;
59 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{ }
61 const char *getPassName() const override
{
62 return "Exception handling preparation";
65 } // end anonymous namespace
67 char DwarfEHPrepare::ID
= 0;
69 FunctionPass
*llvm::createDwarfEHPass(const TargetMachine
*TM
) {
70 return new DwarfEHPrepare(TM
);
73 /// GetExceptionObject - Return the exception object from the value passed into
74 /// the 'resume' instruction (typically an aggregate). Clean up any dead
75 /// instructions, including the 'resume' instruction.
76 Value
*DwarfEHPrepare::GetExceptionObject(ResumeInst
*RI
) {
77 Value
*V
= RI
->getOperand(0);
78 Value
*ExnObj
= nullptr;
79 InsertValueInst
*SelIVI
= dyn_cast
<InsertValueInst
>(V
);
80 LoadInst
*SelLoad
= nullptr;
81 InsertValueInst
*ExcIVI
= nullptr;
82 bool EraseIVIs
= false;
85 if (SelIVI
->getNumIndices() == 1 && *SelIVI
->idx_begin() == 1) {
86 ExcIVI
= dyn_cast
<InsertValueInst
>(SelIVI
->getOperand(0));
87 if (ExcIVI
&& isa
<UndefValue
>(ExcIVI
->getOperand(0)) &&
88 ExcIVI
->getNumIndices() == 1 && *ExcIVI
->idx_begin() == 0) {
89 ExnObj
= ExcIVI
->getOperand(1);
90 SelLoad
= dyn_cast
<LoadInst
>(SelIVI
->getOperand(1));
97 ExnObj
= ExtractValueInst::Create(RI
->getOperand(0), 0, "exn.obj", RI
);
99 RI
->eraseFromParent();
102 if (SelIVI
->getNumUses() == 0)
103 SelIVI
->eraseFromParent();
104 if (ExcIVI
->getNumUses() == 0)
105 ExcIVI
->eraseFromParent();
106 if (SelLoad
&& SelLoad
->getNumUses() == 0)
107 SelLoad
->eraseFromParent();
113 /// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present
114 /// into calls to the appropriate _Unwind_Resume function.
115 bool DwarfEHPrepare::InsertUnwindResumeCalls(Function
&Fn
) {
116 SmallVector
<ResumeInst
*, 16> Resumes
;
117 for (Function::iterator I
= Fn
.begin(), E
= Fn
.end(); I
!= E
; ++I
) {
118 TerminatorInst
*TI
= I
->getTerminator();
119 if (ResumeInst
*RI
= dyn_cast
<ResumeInst
>(TI
))
120 Resumes
.push_back(RI
);
126 // Find the rewind function if we didn't already.
127 const TargetLowering
*TLI
= TM
->getSubtargetImpl()->getTargetLowering();
128 if (!RewindFunction
) {
129 LLVMContext
&Ctx
= Resumes
[0]->getContext();
130 FunctionType
*FTy
= FunctionType::get(Type::getVoidTy(Ctx
),
131 Type::getInt8PtrTy(Ctx
), false);
132 const char *RewindName
= TLI
->getLibcallName(RTLIB::UNWIND_RESUME
);
133 RewindFunction
= Fn
.getParent()->getOrInsertFunction(RewindName
, FTy
);
136 // Create the basic block where the _Unwind_Resume call will live.
137 LLVMContext
&Ctx
= Fn
.getContext();
138 unsigned ResumesSize
= Resumes
.size();
140 if (ResumesSize
== 1) {
141 // Instead of creating a new BB and PHI node, just append the call to
142 // _Unwind_Resume to the end of the single resume block.
143 ResumeInst
*RI
= Resumes
.front();
144 BasicBlock
*UnwindBB
= RI
->getParent();
145 Value
*ExnObj
= GetExceptionObject(RI
);
147 // Call the _Unwind_Resume function.
148 CallInst
*CI
= CallInst::Create(RewindFunction
, ExnObj
, "", UnwindBB
);
149 CI
->setCallingConv(TLI
->getLibcallCallingConv(RTLIB::UNWIND_RESUME
));
151 // We never expect _Unwind_Resume to return.
152 new UnreachableInst(Ctx
, UnwindBB
);
156 BasicBlock
*UnwindBB
= BasicBlock::Create(Ctx
, "unwind_resume", &Fn
);
157 PHINode
*PN
= PHINode::Create(Type::getInt8PtrTy(Ctx
), ResumesSize
,
158 "exn.obj", UnwindBB
);
160 // Extract the exception object from the ResumeInst and add it to the PHI node
161 // that feeds the _Unwind_Resume call.
162 for (SmallVectorImpl
<ResumeInst
*>::iterator
163 I
= Resumes
.begin(), E
= Resumes
.end(); I
!= E
; ++I
) {
165 BasicBlock
*Parent
= RI
->getParent();
166 BranchInst::Create(UnwindBB
, Parent
);
168 Value
*ExnObj
= GetExceptionObject(RI
);
169 PN
->addIncoming(ExnObj
, Parent
);
174 // Call the function.
175 CallInst
*CI
= CallInst::Create(RewindFunction
, PN
, "", UnwindBB
);
176 CI
->setCallingConv(TLI
->getLibcallCallingConv(RTLIB::UNWIND_RESUME
));
178 // We never expect _Unwind_Resume to return.
179 new UnreachableInst(Ctx
, UnwindBB
);
183 bool DwarfEHPrepare::runOnFunction(Function
&Fn
) {
184 bool Changed
= InsertUnwindResumeCalls(Fn
);