#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/Passes.h"
-#include "llvm/Support/Debug.h"
+#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
#include <set>
using namespace llvm;
+static cl::opt<bool> DisableOldSjLjEH("disable-old-sjlj-eh", cl::Hidden,
+ cl::desc("Disable the old SjLj EH preparation pass"));
+
STATISTIC(NumInvokes, "Number of invokes replaced");
STATISTIC(NumUnwinds, "Number of unwinds replaced");
STATISTIC(NumSpilled, "Number of registers live across unwind edges");
namespace {
class SjLjEHPass : public FunctionPass {
-
const TargetLowering *TLI;
-
- const Type *FunctionContextTy;
+ Type *FunctionContextTy;
Constant *RegisterFn;
Constant *UnregisterFn;
Constant *BuiltinSetjmpFn;
Constant *ExceptionFn;
Constant *CallSiteFn;
Constant *DispatchSetupFn;
-
Value *CallSite;
+ DenseMap<InvokeInst*, BasicBlock*> LPadSuccMap;
public:
static char ID; // Pass identification, replacement for typeid
explicit SjLjEHPass(const TargetLowering *tli = NULL)
bool doInitialization(Module &M);
bool runOnFunction(Function &F);
- virtual void getAnalysisUsage(AnalysisUsage &AU) const { }
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {}
const char *getPassName() const {
return "SJLJ Exception Handling preparation";
}
private:
+ bool setupEntryBlockAndCallSites(Function &F);
+ void setupFunctionContext(Function &F, ArrayRef<LandingPadInst*> LPads);
+
void insertCallSiteStore(Instruction *I, int Number, Value *CallSite);
void markInvokeCallSite(InvokeInst *II, int InvokeNo, Value *CallSite,
SwitchInst *CatchSwitch);
void splitLiveRangesAcrossInvokes(SmallVector<InvokeInst*,16> &Invokes);
+ void splitLandingPad(InvokeInst *II);
bool insertSjLjEHSupport(Function &F);
};
} // end anonymous namespace
bool SjLjEHPass::doInitialization(Module &M) {
// Build the function context structure.
// builtin_setjmp uses a five word jbuf
- const Type *VoidPtrTy =
- Type::getInt8PtrTy(M.getContext());
- const Type *Int32Ty = Type::getInt32Ty(M.getContext());
+ Type *VoidPtrTy = Type::getInt8PtrTy(M.getContext());
+ Type *Int32Ty = Type::getInt32Ty(M.getContext());
FunctionContextTy =
- StructType::get(M.getContext(),
- VoidPtrTy, // __prev
+ StructType::get(VoidPtrTy, // __prev
Int32Ty, // call_site
ArrayType::get(Int32Ty, 4), // __data
VoidPtrTy, // __personality
new StoreInst(CallSiteNoC, CallSite, true, I); // volatile
}
+/// splitLandingPad - Split a landing pad. This takes considerable care because
+/// of PHIs and other nasties. The problem is that the jump table needs to jump
+/// to the landing pad block. However, the landing pad block can be jumped to
+/// only by an invoke instruction. So we clone the landingpad instruction into
+/// its own basic block, have the invoke jump to there. The landingpad
+/// instruction's basic block's successor is now the target for the jump table.
+///
+/// But because of PHI nodes, we need to create another basic block for the jump
+/// table to jump to. This is definitely a hack, because the values for the PHI
+/// nodes may not be defined on the edge from the jump table. But that's okay,
+/// because the jump table is simply a construct to mimic what is happening in
+/// the CFG. So the values are mysteriously there, even though there is no value
+/// for the PHI from the jump table's edge (hence calling this a hack).
+void SjLjEHPass::splitLandingPad(InvokeInst *II) {
+ SmallVector<BasicBlock*, 2> NewBBs;
+ SplitLandingPadPredecessors(II->getUnwindDest(), II->getParent(),
+ ".1", ".2", this, NewBBs);
+
+ // Create an empty block so that the jump table has something to jump to
+ // which doesn't have any PHI nodes.
+ BasicBlock *LPad = NewBBs[0];
+ BasicBlock *Succ = *succ_begin(LPad);
+ BasicBlock *JumpTo = BasicBlock::Create(II->getContext(), "jt.land",
+ LPad->getParent(), Succ);
+ LPad->getTerminator()->eraseFromParent();
+ BranchInst::Create(JumpTo, LPad);
+ BranchInst::Create(Succ, JumpTo);
+ LPadSuccMap[II] = JumpTo;
+
+ for (BasicBlock::iterator I = Succ->begin(); isa<PHINode>(I); ++I) {
+ PHINode *PN = cast<PHINode>(I);
+ Value *Val = PN->removeIncomingValue(LPad, false);
+ PN->addIncoming(Val, JumpTo);
+ }
+}
+
/// markInvokeCallSite - Insert code to mark the call_site for this invoke
void SjLjEHPass::markInvokeCallSite(InvokeInst *II, int InvokeNo,
Value *CallSite,
// The runtime comes back to the dispatcher with the call_site - 1 in
// the context. Odd, but there it is.
ConstantInt *SwitchValC = ConstantInt::get(Type::getInt32Ty(II->getContext()),
- InvokeNo - 1);
+ InvokeNo - 1);
// If the unwind edge has phi nodes, split the edge.
if (isa<PHINode>(II->getUnwindDest()->begin())) {
- SplitCriticalEdge(II, 1, this);
+ // FIXME: New EH - This if-condition will be always true in the new scheme.
+ if (II->getUnwindDest()->isLandingPad())
+ splitLandingPad(II);
+ else
+ SplitCriticalEdge(II, 1, this);
// If there are any phi nodes left, they must have a single predecessor.
while (PHINode *PN = dyn_cast<PHINode>(II->getUnwindDest()->begin())) {
CallInst::Create(CallSiteFn, CallSiteNoC, "", II);
// Add a switch case to our unwind block.
- CatchSwitch->addCase(SwitchValC, II->getUnwindDest());
+ if (BasicBlock *SuccBB = LPadSuccMap[II]) {
+ CatchSwitch->addCase(SwitchValC, SuccBB);
+ } else {
+ CatchSwitch->addCase(SwitchValC, II->getUnwindDest());
+ }
+
// We still want this to look like an invoke so we emit the LSDA properly,
// so we don't transform the invoke into a call here.
}
for (unsigned i = 0, e = Invokes.size(); i != e; ++i) {
InvokeInst *II = Invokes[i];
SplitCriticalEdge(II, 0, this);
- SplitCriticalEdge(II, 1, this);
+
+ // FIXME: New EH - This if-condition will be always true in the new scheme.
+ if (II->getUnwindDest()->isLandingPad())
+ splitLandingPad(II);
+ else
+ SplitCriticalEdge(II, 1, this);
+
assert(!isa<PHINode>(II->getNormalDest()) &&
!isa<PHINode>(II->getUnwindDest()) &&
- "critical edge splitting left single entry phi nodes?");
+ "Critical edge splitting left single entry phi nodes?");
}
Function *F = Invokes.back()->getParent()->getParent();
++AfterAllocaInsertPt;
for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end();
AI != E; ++AI) {
- const Type *Ty = AI->getType();
+ Type *Ty = AI->getType();
// Aggregate types can't be cast, but are legal argument types, so we have
// to handle them differently. We use an extract/insert pair as a
// lightweight method to achieve the same goal.
}
}
+/// CreateLandingPadLoad - Load the exception handling values and insert them
+/// into a structure.
+static Instruction *CreateLandingPadLoad(Function &F, Value *ExnAddr,
+ Value *SelAddr,
+ BasicBlock::iterator InsertPt) {
+ Value *Exn = new LoadInst(ExnAddr, "exn", false,
+ InsertPt);
+ Type *Ty = Type::getInt8PtrTy(F.getContext());
+ Exn = CastInst::Create(Instruction::IntToPtr, Exn, Ty, "", InsertPt);
+ Value *Sel = new LoadInst(SelAddr, "sel", false, InsertPt);
+
+ Ty = StructType::get(Exn->getType(), Sel->getType(), NULL);
+ InsertValueInst *LPadVal = InsertValueInst::Create(llvm::UndefValue::get(Ty),
+ Exn, 0,
+ "lpad.val", InsertPt);
+ return InsertValueInst::Create(LPadVal, Sel, 1, "lpad.val", InsertPt);
+}
+
+/// ReplaceLandingPadVal - Replace the landingpad instruction's value with a
+/// load from the stored values (via CreateLandingPadLoad). This looks through
+/// PHI nodes, and removes them if they are dead.
+static void ReplaceLandingPadVal(Function &F, Instruction *Inst, Value *ExnAddr,
+ Value *SelAddr) {
+ if (Inst->use_empty()) return;
+
+ while (!Inst->use_empty()) {
+ Instruction *I = cast<Instruction>(Inst->use_back());
+
+ if (PHINode *PN = dyn_cast<PHINode>(I)) {
+ ReplaceLandingPadVal(F, PN, ExnAddr, SelAddr);
+ if (PN->use_empty()) PN->eraseFromParent();
+ continue;
+ }
+
+ I->replaceUsesOfWith(Inst, CreateLandingPadLoad(F, ExnAddr, SelAddr, I));
+ }
+}
+
bool SjLjEHPass::insertSjLjEHSupport(Function &F) {
SmallVector<ReturnInst*,16> Returns;
SmallVector<UnwindInst*,16> Unwinds;
SmallVector<CallInst*,16> EH_Exceptions;
SmallVector<Instruction*,16> JmpbufUpdatePoints;
- // Note: Skip the entry block since there's nothing there that interests
- // us. eh.selector and eh.exception shouldn't ever be there, and we
- // want to disregard any allocas that are there.
- for (Function::iterator BB = F.begin(), E = F.end(); ++BB != E;) {
+ for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
+ // Note: Skip the entry block since there's nothing there that interests
+ // us. eh.selector and eh.exception shouldn't ever be there, and we
+ // want to disregard any allocas that are there.
+ //
+ // FIXME: This is awkward. The new EH scheme won't need to skip the entry
+ // block.
+ if (BB == F.begin()) {
+ if (InvokeInst *II = dyn_cast<InvokeInst>(F.begin()->getTerminator())) {
+ // FIXME: This will be always non-NULL in the new EH.
+ if (LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst())
+ if (!PersonalityFn) PersonalityFn = LPI->getPersonalityFn();
+ }
+
+ continue;
+ }
+
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
if (CallInst *CI = dyn_cast<CallInst>(I)) {
if (CI->getCalledFunction() == SelectorFn) {
}
} else if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
JmpbufUpdatePoints.push_back(AI);
+ } else if (InvokeInst *II = dyn_cast<InvokeInst>(I)) {
+ // FIXME: This will be always non-NULL in the new EH.
+ if (LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst())
+ if (!PersonalityFn) PersonalityFn = LPI->getPersonalityFn();
}
}
}
// invoke's.
splitLiveRangesAcrossInvokes(Invokes);
+
+ SmallVector<LandingPadInst*, 16> LandingPads;
+ for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
+ if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator()))
+ // FIXME: This will be always non-NULL in the new EH.
+ if (LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst())
+ LandingPads.push_back(LPI);
+ }
+
+
BasicBlock *EntryBB = F.begin();
// Create an alloca for the incoming jump buffer ptr and the new jump buffer
// that needs to be restored on all exits from the function. This is an
"fcn_context", F.begin()->begin());
Value *Idxs[2];
- const Type *Int32Ty = Type::getInt32Ty(F.getContext());
+ Type *Int32Ty = Type::getInt32Ty(F.getContext());
Value *Zero = ConstantInt::get(Int32Ty, 0);
// We need to also keep around a reference to the call_site field
Idxs[0] = Zero;
Idxs[1] = ConstantInt::get(Int32Ty, 1);
- CallSite = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2,
- "call_site",
+ CallSite = GetElementPtrInst::Create(FunctionContext, Idxs, "call_site",
EntryBB->getTerminator());
// The exception selector comes back in context->data[1]
Idxs[1] = ConstantInt::get(Int32Ty, 2);
- Value *FCData = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2,
- "fc_data",
+ Value *FCData = GetElementPtrInst::Create(FunctionContext, Idxs, "fc_data",
EntryBB->getTerminator());
Idxs[1] = ConstantInt::get(Int32Ty, 1);
- Value *SelectorAddr = GetElementPtrInst::Create(FCData, Idxs, Idxs+2,
+ Value *SelectorAddr = GetElementPtrInst::Create(FCData, Idxs,
"exc_selector_gep",
EntryBB->getTerminator());
// The exception value comes back in context->data[0]
Idxs[1] = Zero;
- Value *ExceptionAddr = GetElementPtrInst::Create(FCData, Idxs, Idxs+2,
+ Value *ExceptionAddr = GetElementPtrInst::Create(FCData, Idxs,
"exception_gep",
EntryBB->getTerminator());
// instruction hasn't already been removed.
if (!I->getParent()) continue;
Value *Val = new LoadInst(ExceptionAddr, "exception", true, I);
- const Type *Ty = Type::getInt8PtrTy(F.getContext());
+ Type *Ty = Type::getInt8PtrTy(F.getContext());
Val = CastInst::Create(Instruction::IntToPtr, Val, Ty, "", I);
I->replaceAllUsesWith(Val);
I->eraseFromParent();
}
+ for (unsigned i = 0, e = LandingPads.size(); i != e; ++i)
+ ReplaceLandingPadVal(F, LandingPads[i], ExceptionAddr, SelectorAddr);
+
// The entry block changes to have the eh.sjlj.setjmp, with a conditional
// branch to a dispatch block for non-zero returns. If we return normally,
// we're not handling an exception and just register the function context and
BasicBlock::Create(F.getContext(), "eh.sjlj.setjmp.catch", &F);
// Insert a load of the callsite in the dispatch block, and a switch on its
- // value. By default, we go to a block that just does an unwind (which is the
- // correct action for a standard call).
- BasicBlock *UnwindBlock =
- BasicBlock::Create(F.getContext(), "unwindbb", &F);
- Unwinds.push_back(new UnwindInst(F.getContext(), UnwindBlock));
+ // value. By default, we issue a trap statement.
+ BasicBlock *TrapBlock =
+ BasicBlock::Create(F.getContext(), "trapbb", &F);
+ CallInst::Create(Intrinsic::getDeclaration(F.getParent(), Intrinsic::trap),
+ "", TrapBlock);
+ new UnreachableInst(F.getContext(), TrapBlock);
Value *DispatchLoad = new LoadInst(CallSite, "invoke.num", true,
DispatchBlock);
SwitchInst *DispatchSwitch =
- SwitchInst::Create(DispatchLoad, UnwindBlock, Invokes.size(),
+ SwitchInst::Create(DispatchLoad, TrapBlock, Invokes.size(),
DispatchBlock);
// Split the entry block to insert the conditional branch for the setjmp.
BasicBlock *ContBlock = EntryBB->splitBasicBlock(EntryBB->getTerminator(),
Idxs[0] = Zero;
Idxs[1] = ConstantInt::get(Int32Ty, 4);
Value *LSDAFieldPtr =
- GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2,
- "lsda_gep",
+ GetElementPtrInst::Create(FunctionContext, Idxs, "lsda_gep",
EntryBB->getTerminator());
Value *LSDA = CallInst::Create(LSDAAddrFn, "lsda_addr",
EntryBB->getTerminator());
Idxs[1] = ConstantInt::get(Int32Ty, 3);
Value *PersonalityFieldPtr =
- GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2,
- "lsda_gep",
+ GetElementPtrInst::Create(FunctionContext, Idxs, "lsda_gep",
EntryBB->getTerminator());
new StoreInst(PersonalityFn, PersonalityFieldPtr, true,
EntryBB->getTerminator());
// Save the frame pointer.
Idxs[1] = ConstantInt::get(Int32Ty, 5);
Value *JBufPtr
- = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2,
- "jbuf_gep",
+ = GetElementPtrInst::Create(FunctionContext, Idxs, "jbuf_gep",
EntryBB->getTerminator());
Idxs[1] = ConstantInt::get(Int32Ty, 0);
Value *FramePtr =
- GetElementPtrInst::Create(JBufPtr, Idxs, Idxs+2, "jbuf_fp_gep",
+ GetElementPtrInst::Create(JBufPtr, Idxs, "jbuf_fp_gep",
EntryBB->getTerminator());
Value *Val = CallInst::Create(FrameAddrFn,
// Save the stack pointer.
Idxs[1] = ConstantInt::get(Int32Ty, 2);
Value *StackPtr =
- GetElementPtrInst::Create(JBufPtr, Idxs, Idxs+2, "jbuf_sp_gep",
+ GetElementPtrInst::Create(JBufPtr, Idxs, "jbuf_sp_gep",
EntryBB->getTerminator());
Val = CallInst::Create(StackAddrFn, "sp", EntryBB->getTerminator());
// Add a call to dispatch_setup after the setjmp call. This is expanded to any
// target-specific setup that needs to be done.
- CallInst::Create(DispatchSetupFn, "", EntryBB->getTerminator());
+ CallInst::Create(DispatchSetupFn, DispatchVal, "", EntryBB->getTerminator());
// check the return value of the setjmp. non-zero goes to dispatcher.
Value *IsNormal = new ICmpInst(EntryBB->getTerminator(),
if (Callee != SelectorFn && Callee != ExceptionFn
&& !CI->doesNotThrow())
insertCallSiteStore(CI, -1, CallSite);
+ } else if (ResumeInst *RI = dyn_cast<ResumeInst>(I)) {
+ insertCallSiteStore(RI, -1, CallSite);
}
}
// Replace all unwinds with a branch to the unwind handler.
// ??? Should this ever happen with sjlj exceptions?
for (unsigned i = 0, e = Unwinds.size(); i != e; ++i) {
- BranchInst::Create(UnwindBlock, Unwinds[i]);
+ BranchInst::Create(TrapBlock, Unwinds[i]);
Unwinds[i]->eraseFromParent();
}
return true;
}
+/// setupFunctionContext - Allocate the function context on the stack and fill
+/// it with all of the data that we know at this point.
+void SjLjEHPass::setupFunctionContext(Function &F,
+ ArrayRef<LandingPadInst*> LPads) {
+ BasicBlock *EntryBB = F.begin();
+
+ // Create an alloca for the incoming jump buffer ptr and the new jump buffer
+ // that needs to be restored on all exits from the function. This is an alloca
+ // because the value needs to be added to the global context list.
+ unsigned Align =
+ TLI->getTargetData()->getPrefTypeAlignment(FunctionContextTy);
+ AllocaInst *FuncCtx =
+ new AllocaInst(FunctionContextTy, 0, Align, "fn_context", EntryBB->begin());
+
+ // Fill in the function context structure.
+ Value *Idxs[2];
+ Type *Int32Ty = Type::getInt32Ty(F.getContext());
+ Value *Zero = ConstantInt::get(Int32Ty, 0);
+ Value *One = ConstantInt::get(Int32Ty, 1);
+
+ // Keep around a reference to the call_site field.
+ Idxs[0] = Zero;
+ Idxs[1] = One;
+ CallSite = GetElementPtrInst::Create(FuncCtx, Idxs, "call_site",
+ EntryBB->getTerminator());
+
+ // Reference the __data field.
+ Idxs[1] = ConstantInt::get(Int32Ty, 2);
+ Value *FCData = GetElementPtrInst::Create(FuncCtx, Idxs, "__data",
+ EntryBB->getTerminator());
+
+ // The exception value comes back in context->__data[0].
+ Idxs[1] = Zero;
+ Value *ExceptionAddr = GetElementPtrInst::Create(FCData, Idxs,
+ "exception_gep",
+ EntryBB->getTerminator());
+
+ // The exception selector comes back in context->__data[1].
+ Idxs[1] = One;
+ Value *SelectorAddr = GetElementPtrInst::Create(FCData, Idxs,
+ "exn_selector_gep",
+ EntryBB->getTerminator());
+
+ for (unsigned I = 0, E = LPads.size(); I != E; ++I) {
+ LandingPadInst *LPI = LPads[I];
+ IRBuilder<> Builder(LPI->getParent()->getFirstInsertionPt());
+
+ Value *ExnVal = Builder.CreateLoad(ExceptionAddr, true, "exn_val");
+ ExnVal = Builder.CreateIntToPtr(ExnVal, Type::getInt8PtrTy(F.getContext()));
+ Value *SelVal = Builder.CreateLoad(SelectorAddr, true, "exn_selector_val");
+
+ Type *LPadType = LPI->getType();
+ Value *LPadVal = UndefValue::get(LPadType);
+ LPadVal = Builder.CreateInsertValue(LPadVal, ExnVal, 0, "lpad.val");
+ LPadVal = Builder.CreateInsertValue(LPadVal, SelVal, 1, "lpad.val");
+
+ LPI->replaceAllUsesWith(LPadVal);
+ }
+
+ // Personality function
+ Idxs[1] = ConstantInt::get(Int32Ty, 3);
+ if (!PersonalityFn)
+ PersonalityFn = LPads[0]->getPersonalityFn();
+ Value *PersonalityFieldPtr =
+ GetElementPtrInst::Create(FuncCtx, Idxs, "pers_fn_gep",
+ EntryBB->getTerminator());
+ new StoreInst(PersonalityFn, PersonalityFieldPtr, true,
+ EntryBB->getTerminator());
+
+ // LSDA address
+ Idxs[1] = ConstantInt::get(Int32Ty, 4);
+ Value *LSDAFieldPtr =
+ GetElementPtrInst::Create(FuncCtx, Idxs, "lsda_gep",
+ EntryBB->getTerminator());
+ Value *LSDA = CallInst::Create(LSDAAddrFn, "lsda_addr",
+ EntryBB->getTerminator());
+ new StoreInst(LSDA, LSDAFieldPtr, true, EntryBB->getTerminator());
+
+ // Get a reference to the jump buffer.
+ Idxs[1] = ConstantInt::get(Int32Ty, 5);
+ Value *JBufPtr =
+ GetElementPtrInst::Create(FuncCtx, Idxs, "jbuf_gep",
+ EntryBB->getTerminator());
+ Idxs[1] = Zero;
+ Value *FramePtr =
+ GetElementPtrInst::Create(JBufPtr, Idxs, "jbuf_fp_gep",
+ EntryBB->getTerminator());
+
+ // Save the frame pointer.
+ Value *Val = CallInst::Create(FrameAddrFn,
+ ConstantInt::get(Int32Ty, 0),
+ "fp",
+ EntryBB->getTerminator());
+ new StoreInst(Val, FramePtr, true, EntryBB->getTerminator());
+
+ // Save the stack pointer.
+ Idxs[1] = ConstantInt::get(Int32Ty, 2);
+ Value *StackPtr =
+ GetElementPtrInst::Create(JBufPtr, Idxs, "jbuf_sp_gep",
+ EntryBB->getTerminator());
+
+ Val = CallInst::Create(StackAddrFn, "sp", EntryBB->getTerminator());
+ new StoreInst(Val, StackPtr, true, EntryBB->getTerminator());
+
+ // Call the setjmp instrinsic. It fills in the rest of the jmpbuf.
+ Value *SetjmpArg =
+ CastInst::Create(Instruction::BitCast, JBufPtr,
+ Type::getInt8PtrTy(F.getContext()), "",
+ EntryBB->getTerminator());
+ Value *DispatchVal = CallInst::Create(BuiltinSetjmpFn, SetjmpArg,
+ "dispatch",
+ EntryBB->getTerminator());
+
+ // Add a call to dispatch_setup after the setjmp call. This is expanded to any
+ // target-specific setup that needs to be done.
+ CallInst::Create(DispatchSetupFn, DispatchVal, "", EntryBB->getTerminator());
+}
+
+/// setupEntryBlockAndCallSites - Setup the entry block by creating and filling
+/// the function context and marking the call sites with the appropriate
+/// values. These values are used by the DWARF EH emitter.
+bool SjLjEHPass::setupEntryBlockAndCallSites(Function &F) {
+ SmallVector<InvokeInst*, 16> Invokes;
+ SmallVector<LandingPadInst*, 16> LPads;
+
+ // Look through the terminators of the basic blocks to find invokes.
+ for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
+ if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator())) {
+ Invokes.push_back(II);
+ LPads.push_back(II->getUnwindDest()->getLandingPadInst());
+ }
+
+ if (Invokes.empty()) return false;
+
+ setupFunctionContext(F, LPads);
+
+ // At this point, we are all set up, update the invoke instructions to mark
+ // their call_site values, and fill in the dispatch switch accordingly.
+ for (unsigned I = 0, E = Invokes.size(); I != E; ++I) {
+ insertCallSiteStore(Invokes[I], I + 1, CallSite);
+
+ ConstantInt *CallSiteNum =
+ ConstantInt::get(Type::getInt32Ty(F.getContext()), I + 1);
+
+ // Record the call site value for the back end so it stays associated with
+ // the invoke.
+ CallInst::Create(CallSiteFn, CallSiteNum, "", Invokes[I]);
+ }
+
+ // Mark call instructions that aren't nounwind as no-action (call_site ==
+ // -1). Skip the entry block, as prior to then, no function context has been
+ // created for this function and any unexpected exceptions thrown will go
+ // directly to the caller's context, which is what we want anyway, so no need
+ // to do anything here.
+ for (Function::iterator BB = F.begin(), E = F.end(); ++BB != E;) {
+ for (BasicBlock::iterator I = BB->begin(), end = BB->end(); I != end; ++I)
+ if (CallInst *CI = dyn_cast<CallInst>(I)) {
+ if (!CI->doesNotThrow())
+ insertCallSiteStore(CI, -1, CallSite);
+ } else if (ResumeInst *RI = dyn_cast<ResumeInst>(I)) {
+ insertCallSiteStore(RI, -1, CallSite);
+ }
+ }
+
+ return true;
+}
+
bool SjLjEHPass::runOnFunction(Function &F) {
- bool Res = insertSjLjEHSupport(F);
+ bool Res = false;
+ if (!DisableOldSjLjEH)
+ Res = insertSjLjEHSupport(F);
+ else
+ Res = setupEntryBlockAndCallSites(F);
return Res;
}