35#define DEBUG_TYPE "sjlj-eh-prepare"
38STATISTIC(NumSpilled,
"Number of registers live across unwind edges");
41class SjLjEHPrepareImpl {
43 Type *doubleUnderDataTy =
nullptr;
44 Type *doubleUnderJBufTy =
nullptr;
45 Type *FunctionContextTy =
nullptr;
48 Function *BuiltinSetupDispatchFn =
nullptr;
59 explicit SjLjEHPrepareImpl(
const TargetMachine *TM =
nullptr) : TM(TM) {}
60 bool doInitialization(
Module &M);
64 bool setupEntryBlockAndCallSites(
Function &
F);
73 SjLjEHPrepareImpl Impl;
83 return "SJLJ Exception Handling preparation";
91 SjLjEHPrepareImpl Impl(TM);
92 Impl.doInitialization(*
F.getParent());
93 bool Changed = Impl.runOnFunction(
F);
97char SjLjEHPrepare::ID = 0;
103 return new SjLjEHPrepare(TM);
108bool SjLjEHPrepareImpl::doInitialization(
Module &M) {
135 Value *
Zero = ConstantInt::get(Int32Ty, 0);
136 Value *One = ConstantInt::get(Int32Ty, 1);
139 Builder.CreateGEP(FunctionContextTy, FuncCtx, Idxs,
"call_site");
143 Builder.CreateStore(CallSiteNoC, CallSite,
true );
150 if (!LiveBBs.
insert(BB).second)
162 while (!UseWorkList.empty()) {
163 Value *Val = UseWorkList.pop_back_val();
164 auto *EVI = dyn_cast<ExtractValueInst>(Val);
167 if (EVI->getNumIndices() != 1)
169 if (*EVI->idx_begin() == 0)
170 EVI->replaceAllUsesWith(ExnVal);
171 else if (*EVI->idx_begin() == 1)
172 EVI->replaceAllUsesWith(SelVal);
173 if (EVI->use_empty())
174 EVI->eraseFromParent();
184 auto *SelI = cast<Instruction>(SelVal);
185 IRBuilder<> Builder(SelI->getParent(), std::next(SelI->getIterator()));
186 LPadVal = Builder.CreateInsertValue(LPadVal, ExnVal, 0,
"lpad.val");
187 LPadVal = Builder.CreateInsertValue(LPadVal, SelVal, 1,
"lpad.val");
195SjLjEHPrepareImpl::setupFunctionContext(
Function &
F,
202 auto &
DL =
F.getDataLayout();
203 const Align Alignment =
DL.getPrefTypeAlign(FunctionContextTy);
204 FuncCtx =
new AllocaInst(FunctionContextTy,
DL.getAllocaAddrSpace(),
nullptr,
205 Alignment,
"fn_context", EntryBB->
begin());
210 LPI->
getParent()->getFirstInsertionPt());
214 Builder.CreateConstGEP2_32(FunctionContextTy, FuncCtx, 0, 2,
"__data");
217 Value *ExceptionAddr = Builder.CreateConstGEP2_32(doubleUnderDataTy, FCData,
218 0, 0,
"exception_gep");
219 Value *ExnVal = Builder.CreateLoad(DataTy, ExceptionAddr,
true,
"exn_val");
220 ExnVal = Builder.CreateIntToPtr(ExnVal, Builder.getPtrTy());
222 Value *SelectorAddr = Builder.CreateConstGEP2_32(doubleUnderDataTy, FCData,
223 0, 1,
"exn_selector_gep");
225 Builder.CreateLoad(DataTy, SelectorAddr,
true,
"exn_selector_val");
230 substituteLPadValues(LPI, ExnVal, SelVal);
235 Value *PersonalityFn =
F.getPersonalityFn();
236 Value *PersonalityFieldPtr = Builder.CreateConstGEP2_32(
237 FunctionContextTy, FuncCtx, 0, 3,
"pers_fn_gep");
238 Builder.CreateStore(PersonalityFn, PersonalityFieldPtr,
true);
241 Value *LSDA = Builder.CreateCall(LSDAAddrFn, {},
"lsda_addr");
242 Value *LSDAFieldPtr =
243 Builder.CreateConstGEP2_32(FunctionContextTy, FuncCtx, 0, 4,
"lsda_gep");
244 Builder.CreateStore(LSDA, LSDAFieldPtr,
true);
253void SjLjEHPrepareImpl::lowerIncomingArguments(
Function &
F) {
255 while (isa<AllocaInst>(AfterAllocaInsPt) &&
256 cast<AllocaInst>(AfterAllocaInsPt)->isStaticAlloca())
258 assert(AfterAllocaInsPt !=
F.front().end());
260 for (
auto &AI :
F.args()) {
265 if (AI.isSwiftError())
268 Type *Ty = AI.getType();
275 AI.replaceAllUsesWith(SI);
278 SI->setOperand(1, &AI);
284void SjLjEHPrepareImpl::lowerAcrossUnwindEdges(
Function &
F,
292 if (Inst.use_empty())
294 if (Inst.hasOneUse() &&
295 cast<Instruction>(Inst.user_back())->getParent() == &BB &&
296 !isa<PHINode>(Inst.user_back()))
301 if (
auto *AI = dyn_cast<AllocaInst>(&Inst))
302 if (AI->isStaticAlloca())
309 if (UI->
getParent() != &BB || isa<PHINode>(UI))
316 while (!
Users.empty()) {
319 if (!isa<PHINode>(U)) {
323 PHINode *PN = cast<PHINode>(U);
332 bool NeedsSpill =
false;
334 BasicBlock *UnwindBlock = Invoke->getUnwindDest();
335 if (UnwindBlock != &BB && LiveBBs.
count(UnwindBlock)) {
337 << UnwindBlock->
getName() <<
"\n");
356 BasicBlock *UnwindBlock = Invoke->getUnwindDest();
362 PHIsToDemote.
insert(cast<PHINode>(PN));
363 if (PHIsToDemote.
empty())
367 for (
PHINode *PN : PHIsToDemote)
378bool SjLjEHPrepareImpl::setupEntryBlockAndCallSites(
Function &
F) {
385 if (
auto *
II = dyn_cast<InvokeInst>(BB.getTerminator())) {
386 if (
Function *Callee =
II->getCalledFunction())
387 if (
Callee->getIntrinsicID() == Intrinsic::donothing) {
390 II->eraseFromParent();
395 LPads.
insert(
II->getUnwindDest()->getLandingPadInst());
396 }
else if (
auto *RI = dyn_cast<ReturnInst>(BB.getTerminator())) {
403 NumInvokes += Invokes.
size();
405 lowerIncomingArguments(
F);
406 lowerAcrossUnwindEdges(
F, Invokes);
415 Builder.CreateConstGEP2_32(FunctionContextTy, FuncCtx, 0, 5,
"jbuf_gep");
418 Value *
FramePtr = Builder.CreateConstGEP2_32(doubleUnderJBufTy, JBufPtr, 0, 0,
421 Value *Val = Builder.CreateCall(FrameAddrFn, Builder.getInt32(0),
"fp");
422 Builder.CreateStore(Val,
FramePtr,
true);
425 Value *
StackPtr = Builder.CreateConstGEP2_32(doubleUnderJBufTy, JBufPtr, 0, 2,
428 Val = Builder.CreateCall(StackAddrFn, {},
"sp");
429 Builder.CreateStore(Val, StackPtr,
true);
432 Builder.CreateCall(BuiltinSetupDispatchFn, {});
436 Builder.CreateCall(FuncCtxFn, FuncCtx);
440 for (
unsigned I = 0, E = Invokes.
size();
I != E; ++
I) {
441 insertCallSiteStore(Invokes[
I],
I + 1);
457 if (&BB == &
F.front())
461 insertCallSiteStore(&
I, -1);
472 if (&BB == &
F.front())
475 if (
auto *CI = dyn_cast<CallInst>(&
I)) {
476 if (CI->getCalledFunction() != StackRestoreFn)
478 }
else if (!isa<AllocaInst>(&
I)) {
492 if (
CallInst *CI =
Return->getParent()->getTerminatingMustTailCall())
500bool SjLjEHPrepareImpl::runOnFunction(
Function &
F) {
502 RegisterFn =
M.getOrInsertFunction(
505 UnregisterFn =
M.getOrInsertFunction(
509 PointerType *AllocaPtrTy =
M.getDataLayout().getAllocaPtrType(
M.getContext());
517 BuiltinSetupDispatchFn =
523 bool Res = setupEntryBlockAndCallSites(
F);
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
iv Induction Variable Users
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
static void MarkBlocksLiveIn(BasicBlock *BB, SmallPtrSetImpl< BasicBlock * > &LiveBBs)
MarkBlocksLiveIn - Insert BB and all of its predecessors into LiveBBs until we reach blocks we've alr...
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static const unsigned FramePtr
an instruction to allocate memory on the stack
A container for analyses that lazily runs them and caches their results.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
static ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
const LandingPadInst * getLandingPadInst() const
Return the landingpad instruction associated with the landing pad.
const Instruction & front() const
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
This is the shared class of boolean and integer constants.
static ConstantInt * getTrue(LLVMContext &Context)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
void insertAfter(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately after the specified instruction.
void moveBefore(Instruction *MovePos)
Unlink this instruction from its current basic block and insert it into the basic block that MovePos ...
Class to represent integer types.
The landingpad instruction holds all of the information necessary to generate correct exception handl...
A Module instance is used to store all the information related to an LLVM module.
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
static PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
Return a value (possibly void), from a function.
static SelectInst * Create(Value *C, Value *S1, Value *S2, const Twine &NameStr="", InsertPosition InsertBefore=nullptr, Instruction *MDFrom=nullptr)
iterator end()
Get an iterator to the end of the SetVector.
iterator begin()
Get an iterator to the beginning of the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Primary interface to the complete machine description for the target machine.
static constexpr unsigned DefaultSjLjDataSize
The integer bit size to use for SjLj based exception handling.
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
'undef' values are things that do not have specified contents.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
StringRef getName() const
Return a constant reference to the value's name.
const ParentTy * getParent() const
self_iterator getIterator()
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createSjLjEHPreparePass(const TargetMachine *TM)
createSjLjEHPreparePass - This pass adapts exception handling code to use the GCC-style builtin setjm...
AllocaInst * DemoteRegToStack(Instruction &X, bool VolatileLoads=false, std::optional< BasicBlock::iterator > AllocaPoint=std::nullopt)
This function takes a virtual register computed by an Instruction and replaces it with a slot in the ...
AllocaInst * DemotePHIToStack(PHINode *P, std::optional< BasicBlock::iterator > AllocaPoint=std::nullopt)
This function takes a virtual register computed by a phi node and replaces it with a slot in the stac...
iterator_range< idf_iterator< T > > inverse_depth_first(const T &G)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
This struct is a compact representation of a valid (non-zero power of two) alignment.