Remove LowerInvoke's obsolete "-enable-correct-eh-support" option

This option caused LowerInvoke to generate code using SJLJ-based
exception handling, but there is no code left that interprets the
jmp_buf stack that the resulting code maintained (llvm.sjljeh.jblist).
This option has been obsolete for a while, and replaced by
SjLjEHPrepare.

This leaves the default behaviour of LowerInvoke, which is to convert
invokes to calls.

Differential Revision: http://llvm-reviews.chandlerc.com/D3136

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@204388 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Mark Seaborn 2014-03-20 19:54:47 +00:00
parent 56210e69eb
commit 9bb9615e1f
11 changed files with 18 additions and 644 deletions

View File

@ -112,11 +112,6 @@ End-user Options
optimizations allow the code generator to make use of some instructions which
would otherwise not be usable (such as ``fsin`` on X86).
.. option:: --enable-correct-eh-support
Instruct the **lowerinvoke** pass to insert code for correct exception
handling support. This is expensive and is by default omitted for efficiency.
.. option:: --stats
Print statistics recorded by code-generation passes.

View File

@ -190,12 +190,6 @@ CODE GENERATION OPTIONS
**-enable-correct-eh-support**
Make the -lowerinvoke pass insert expensive, but correct, EH code.
**-jit-enable-eh**
Exception handling should be enabled in the just-in-time compiler.

View File

@ -893,33 +893,14 @@ this would require knowledge of the entire call graph of the program including
any libraries which may not be available in bitcode form); it simply lowers
every atomic intrinsic.
``-lowerinvoke``: Lower invoke and unwind, for unwindless code generators
-------------------------------------------------------------------------
``-lowerinvoke``: Lower invokes to calls, for unwindless code generators
------------------------------------------------------------------------
This transformation is designed for use by code generators which do not yet
support stack unwinding. This pass supports two models of exception handling
lowering, the "cheap" support and the "expensive" support.
"Cheap" exception handling support gives the program the ability to execute any
program which does not "throw an exception", by turning "``invoke``"
instructions into calls and by turning "``unwind``" instructions into calls to
``abort()``. If the program does dynamically use the "``unwind``" instruction,
the program will print a message then abort.
"Expensive" exception handling support gives the full exception handling
support to the program at the cost of making the "``invoke``" instruction
really expensive. It basically inserts ``setjmp``/``longjmp`` calls to emulate
the exception handling as necessary.
Because the "expensive" support slows down programs a lot, and EH is only used
for a subset of the programs, it must be specifically enabled by the
``-enable-correct-eh-support`` option.
Note that after this pass runs the CFG is not entirely accurate (exceptional
control flow edges are not correct anymore) so only very simple things should
be done after the ``lowerinvoke`` pass has run (like generation of native
code). This should not be used as a general purpose "my LLVM-to-LLVM pass
doesn't support the ``invoke`` instruction yet" lowering pass.
support stack unwinding. This pass converts ``invoke`` instructions to
``call`` instructions, so that any exception-handling ``landingpad`` blocks
become dead code (which can be removed by running the ``-simplifycfg`` pass
afterwards).
``-lowerswitch``: Lower ``SwitchInst``\ s to branches
-----------------------------------------------------

View File

@ -262,16 +262,10 @@ extern char &LowerSwitchID;
//===----------------------------------------------------------------------===//
//
// LowerInvoke - This pass converts invoke and unwind instructions to use sjlj
// exception handling mechanisms. Note that after this pass runs the CFG is not
// entirely accurate (exceptional control flow edges are not correct anymore) so
// only very simple things should be done after the lowerinvoke pass has run
// (like generation of native code). This should *NOT* be used as a general
// purpose "my LLVM-to-LLVM pass doesn't support the invoke instruction yet"
// lowering pass.
// LowerInvoke - This pass removes invoke instructions, converting them to call
// instructions.
//
FunctionPass *createLowerInvokePass(const TargetMachine *TM = 0,
bool useExpensiveEHSupport = false);
FunctionPass *createLowerInvokePass();
extern char &LowerInvokePassID;
//===----------------------------------------------------------------------===//

View File

@ -423,7 +423,7 @@ void TargetPassConfig::addPassesToHandleExceptions() {
addPass(createDwarfEHPass(TM));
break;
case ExceptionHandling::None:
addPass(createLowerInvokePass(TM));
addPass(createLowerInvokePass());
// The lower invoke pass may create unreachable code. Remove it.
addPass(createUnreachableBlockEliminationPass());

View File

@ -1,4 +1,4 @@
//===- LowerInvoke.cpp - Eliminate Invoke & Unwind instructions -----------===//
//===- LowerInvoke.cpp - Eliminate Invoke instructions --------------------===//
//
// The LLVM Compiler Infrastructure
//
@ -8,29 +8,9 @@
//===----------------------------------------------------------------------===//
//
// This transformation is designed for use by code generators which do not yet
// support stack unwinding. This pass supports two models of exception handling
// lowering, the 'cheap' support and the 'expensive' support.
//
// 'Cheap' exception handling support gives the program the ability to execute
// any program which does not "throw an exception", by turning 'invoke'
// instructions into calls and by turning 'unwind' instructions into calls to
// abort(). If the program does dynamically use the unwind instruction, the
// program will print a message then abort.
//
// 'Expensive' exception handling support gives the full exception handling
// support to the program at the cost of making the 'invoke' instruction
// really expensive. It basically inserts setjmp/longjmp calls to emulate the
// exception handling as necessary.
//
// Because the 'expensive' support slows down programs a lot, and EH is only
// used for a subset of the programs, it must be specifically enabled by an
// option.
//
// Note that after this pass runs the CFG is not entirely accurate (exceptional
// control flow edges are not correct anymore) so only very simple things should
// be done after the lowerinvoke pass has run (like generation of native code).
// This should not be used as a general purpose "my LLVM-to-LLVM pass doesn't
// support the invoke instruction yet" lowering pass.
// support stack unwinding. This pass converts 'invoke' instructions to 'call'
// instructions, so that any exception-handling 'landingpad' blocks become dead
// code (which can be removed by running the '-simplifycfg' pass afterwards).
//
//===----------------------------------------------------------------------===//
@ -38,64 +18,23 @@
#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include <csetjmp>
#include <set>
using namespace llvm;
STATISTIC(NumInvokes, "Number of invokes replaced");
STATISTIC(NumSpilled, "Number of registers live across unwind edges");
static cl::opt<bool> ExpensiveEHSupport("enable-correct-eh-support",
cl::desc("Make the -lowerinvoke pass insert expensive, but correct, EH code"));
namespace {
class LowerInvoke : public FunctionPass {
const TargetMachine *TM;
// Used for both models.
Constant *AbortFn;
// Used for expensive EH support.
StructType *JBLinkTy;
GlobalVariable *JBListHead;
Constant *SetJmpFn, *LongJmpFn, *StackSaveFn, *StackRestoreFn;
bool useExpensiveEHSupport;
public:
static char ID; // Pass identification, replacement for typeid
explicit LowerInvoke(const TargetMachine *TM = 0,
bool useExpensiveEHSupport = ExpensiveEHSupport)
: FunctionPass(ID), TM(TM),
useExpensiveEHSupport(useExpensiveEHSupport) {
explicit LowerInvoke() : FunctionPass(ID) {
initializeLowerInvokePass(*PassRegistry::getPassRegistry());
}
bool doInitialization(Module &M) override;
bool runOnFunction(Function &F) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
// This is a cluster of orthogonal Transforms
AU.addPreserved("mem2reg");
AU.addPreservedID(LowerSwitchID);
}
private:
bool insertCheapEHSupport(Function &F);
void splitLiveRangesLiveAcrossInvokes(SmallVectorImpl<InvokeInst*>&Invokes);
void rewriteExpensiveInvoke(InvokeInst *II, unsigned InvokeNo,
AllocaInst *InvokeNum, AllocaInst *StackPtr,
SwitchInst *CatchSwitch);
bool insertExpensiveEHSupport(Function &F);
};
}
@ -107,65 +46,11 @@ INITIALIZE_PASS(LowerInvoke, "lowerinvoke",
char &llvm::LowerInvokePassID = LowerInvoke::ID;
// Public Interface To the LowerInvoke pass.
FunctionPass *llvm::createLowerInvokePass(const TargetMachine *TM,
bool useExpensiveEHSupport) {
return new LowerInvoke(TM, useExpensiveEHSupport || ExpensiveEHSupport);
FunctionPass *llvm::createLowerInvokePass() {
return new LowerInvoke();
}
// doInitialization - Make sure that there is a prototype for abort in the
// current module.
bool LowerInvoke::doInitialization(Module &M) {
Type *VoidPtrTy = Type::getInt8PtrTy(M.getContext());
if (useExpensiveEHSupport) {
// Insert a type for the linked list of jump buffers.
const TargetLowering *TLI = TM ? TM->getTargetLowering() : 0;
unsigned JBSize = TLI ? TLI->getJumpBufSize() : 0;
JBSize = JBSize ? JBSize : 200;
Type *JmpBufTy = ArrayType::get(VoidPtrTy, JBSize);
JBLinkTy = StructType::create(M.getContext(), "llvm.sjljeh.jmpbufty");
Type *Elts[] = { JmpBufTy, PointerType::getUnqual(JBLinkTy) };
JBLinkTy->setBody(Elts);
Type *PtrJBList = PointerType::getUnqual(JBLinkTy);
// Now that we've done that, insert the jmpbuf list head global, unless it
// already exists.
if (!(JBListHead = M.getGlobalVariable("llvm.sjljeh.jblist", PtrJBList))) {
JBListHead = new GlobalVariable(M, PtrJBList, false,
GlobalValue::LinkOnceAnyLinkage,
Constant::getNullValue(PtrJBList),
"llvm.sjljeh.jblist");
}
// VisualStudio defines setjmp as _setjmp
#if defined(_MSC_VER) && defined(setjmp) && \
!defined(setjmp_undefined_for_msvc)
# pragma push_macro("setjmp")
# undef setjmp
# define setjmp_undefined_for_msvc
#endif
SetJmpFn = Intrinsic::getDeclaration(&M, Intrinsic::setjmp);
#if defined(_MSC_VER) && defined(setjmp_undefined_for_msvc)
// let's return it to _setjmp state
# pragma pop_macro("setjmp")
# undef setjmp_undefined_for_msvc
#endif
LongJmpFn = Intrinsic::getDeclaration(&M, Intrinsic::longjmp);
StackSaveFn = Intrinsic::getDeclaration(&M, Intrinsic::stacksave);
StackRestoreFn = Intrinsic::getDeclaration(&M, Intrinsic::stackrestore);
}
// We need the 'write' and 'abort' functions for both models.
AbortFn = M.getOrInsertFunction("abort", Type::getVoidTy(M.getContext()),
(Type *)0);
return true;
}
bool LowerInvoke::insertCheapEHSupport(Function &F) {
bool LowerInvoke::runOnFunction(Function &F) {
bool Changed = false;
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator())) {
@ -192,387 +77,3 @@ bool LowerInvoke::insertCheapEHSupport(Function &F) {
}
return Changed;
}
/// rewriteExpensiveInvoke - Insert code and hack the function to replace the
/// specified invoke instruction with a call.
void LowerInvoke::rewriteExpensiveInvoke(InvokeInst *II, unsigned InvokeNo,
AllocaInst *InvokeNum,
AllocaInst *StackPtr,
SwitchInst *CatchSwitch) {
ConstantInt *InvokeNoC = ConstantInt::get(Type::getInt32Ty(II->getContext()),
InvokeNo);
// If the unwind edge has phi nodes, split the edge.
if (isa<PHINode>(II->getUnwindDest()->begin())) {
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())) {
PN->replaceAllUsesWith(PN->getIncomingValue(0));
PN->eraseFromParent();
}
}
// Insert a store of the invoke num before the invoke and store zero into the
// location afterward.
new StoreInst(InvokeNoC, InvokeNum, true, II); // volatile
// Insert a store of the stack ptr before the invoke, so we can restore it
// later in the exception case.
CallInst* StackSaveRet = CallInst::Create(StackSaveFn, "ssret", II);
new StoreInst(StackSaveRet, StackPtr, true, II); // volatile
BasicBlock::iterator NI = II->getNormalDest()->getFirstInsertionPt();
// nonvolatile.
new StoreInst(Constant::getNullValue(Type::getInt32Ty(II->getContext())),
InvokeNum, false, NI);
Instruction* StackPtrLoad =
new LoadInst(StackPtr, "stackptr.restore", true,
II->getUnwindDest()->getFirstInsertionPt());
CallInst::Create(StackRestoreFn, StackPtrLoad, "")->insertAfter(StackPtrLoad);
// Add a switch case to our unwind block.
CatchSwitch->addCase(InvokeNoC, II->getUnwindDest());
// Insert a normal call instruction.
SmallVector<Value*,16> CallArgs(II->op_begin(), II->op_end() - 3);
CallInst *NewCall = CallInst::Create(II->getCalledValue(),
CallArgs, "", II);
NewCall->takeName(II);
NewCall->setCallingConv(II->getCallingConv());
NewCall->setAttributes(II->getAttributes());
NewCall->setDebugLoc(II->getDebugLoc());
II->replaceAllUsesWith(NewCall);
// Replace the invoke with an uncond branch.
BranchInst::Create(II->getNormalDest(), NewCall->getParent());
II->eraseFromParent();
}
/// MarkBlocksLiveIn - Insert BB and all of its predescessors into LiveBBs until
/// we reach blocks we've already seen.
static void MarkBlocksLiveIn(BasicBlock *BB, std::set<BasicBlock*> &LiveBBs) {
if (!LiveBBs.insert(BB).second) return; // already been here.
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
MarkBlocksLiveIn(*PI, LiveBBs);
}
// First thing we need to do is scan the whole function for values that are
// live across unwind edges. Each value that is live across an unwind edge
// we spill into a stack location, guaranteeing that there is nothing live
// across the unwind edge. This process also splits all critical edges
// coming out of invoke's.
void LowerInvoke::
splitLiveRangesLiveAcrossInvokes(SmallVectorImpl<InvokeInst*> &Invokes) {
// First step, split all critical edges from invoke instructions.
for (unsigned i = 0, e = Invokes.size(); i != e; ++i) {
InvokeInst *II = Invokes[i];
SplitCriticalEdge(II, 0, this);
SplitCriticalEdge(II, 1, this);
assert(!isa<PHINode>(II->getNormalDest()) &&
!isa<PHINode>(II->getUnwindDest()) &&
"critical edge splitting left single entry phi nodes?");
}
Function *F = Invokes.back()->getParent()->getParent();
// To avoid having to handle incoming arguments specially, we lower each arg
// to a copy instruction in the entry block. This ensures that the argument
// value itself cannot be live across the entry block.
BasicBlock::iterator AfterAllocaInsertPt = F->begin()->begin();
while (isa<AllocaInst>(AfterAllocaInsertPt) &&
isa<ConstantInt>(cast<AllocaInst>(AfterAllocaInsertPt)->getArraySize()))
++AfterAllocaInsertPt;
for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end();
AI != E; ++AI) {
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.
if (isa<StructType>(Ty) || isa<ArrayType>(Ty) || isa<VectorType>(Ty)) {
Instruction *EI = ExtractValueInst::Create(AI, 0, "",AfterAllocaInsertPt);
Instruction *NI = InsertValueInst::Create(AI, EI, 0);
NI->insertAfter(EI);
AI->replaceAllUsesWith(NI);
// Set the operand of the instructions back to the AllocaInst.
EI->setOperand(0, AI);
NI->setOperand(0, AI);
} else {
// This is always a no-op cast because we're casting AI to AI->getType()
// so src and destination types are identical. BitCast is the only
// possibility.
CastInst *NC = new BitCastInst(
AI, AI->getType(), AI->getName()+".tmp", AfterAllocaInsertPt);
AI->replaceAllUsesWith(NC);
// Set the operand of the cast instruction back to the AllocaInst.
// Normally it's forbidden to replace a CastInst's operand because it
// could cause the opcode to reflect an illegal conversion. However,
// we're replacing it here with the same value it was constructed with.
// We do this because the above replaceAllUsesWith() clobbered the
// operand, but we want this one to remain.
NC->setOperand(0, AI);
}
}
// Finally, scan the code looking for instructions with bad live ranges.
for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ++II) {
// Ignore obvious cases we don't have to handle. In particular, most
// instructions either have no uses or only have a single use inside the
// current block. Ignore them quickly.
Instruction *Inst = II;
if (Inst->use_empty()) continue;
if (Inst->hasOneUse() &&
cast<Instruction>(Inst->user_back())->getParent() == BB &&
!isa<PHINode>(Inst->user_back())) continue;
// If this is an alloca in the entry block, it's not a real register
// value.
if (AllocaInst *AI = dyn_cast<AllocaInst>(Inst))
if (isa<ConstantInt>(AI->getArraySize()) && BB == F->begin())
continue;
// Avoid iterator invalidation by copying users to a temporary vector.
SmallVector<Instruction*,16> Users;
for (User *U : Inst->users()) {
Instruction *UI = cast<Instruction>(U);
if (UI->getParent() != BB || isa<PHINode>(UI))
Users.push_back(UI);
}
// Scan all of the uses and see if the live range is live across an unwind
// edge. If we find a use live across an invoke edge, create an alloca
// and spill the value.
// Find all of the blocks that this value is live in.
std::set<BasicBlock*> LiveBBs;
LiveBBs.insert(Inst->getParent());
while (!Users.empty()) {
Instruction *U = Users.back();
Users.pop_back();
if (!isa<PHINode>(U)) {
MarkBlocksLiveIn(U->getParent(), LiveBBs);
} else {
// Uses for a PHI node occur in their predecessor block.
PHINode *PN = cast<PHINode>(U);
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
if (PN->getIncomingValue(i) == Inst)
MarkBlocksLiveIn(PN->getIncomingBlock(i), LiveBBs);
}
}
// Now that we know all of the blocks that this thing is live in, see if
// it includes any of the unwind locations.
bool NeedsSpill = false;
for (unsigned i = 0, e = Invokes.size(); i != e; ++i) {
BasicBlock *UnwindBlock = Invokes[i]->getUnwindDest();
if (UnwindBlock != BB && LiveBBs.count(UnwindBlock)) {
NeedsSpill = true;
}
}
// If we decided we need a spill, do it.
if (NeedsSpill) {
++NumSpilled;
DemoteRegToStack(*Inst, true);
}
}
}
bool LowerInvoke::insertExpensiveEHSupport(Function &F) {
SmallVector<ReturnInst*,16> Returns;
SmallVector<InvokeInst*,16> Invokes;
UnreachableInst* UnreachablePlaceholder = 0;
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
if (ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
// Remember all return instructions in case we insert an invoke into this
// function.
Returns.push_back(RI);
} else if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator())) {
Invokes.push_back(II);
}
if (Invokes.empty()) return false;
NumInvokes += Invokes.size();
// TODO: This is not an optimal way to do this. In particular, this always
// inserts setjmp calls into the entries of functions with invoke instructions
// even though there are possibly paths through the function that do not
// execute any invokes. In particular, for functions with early exits, e.g.
// the 'addMove' method in hexxagon, it would be nice to not have to do the
// setjmp stuff on the early exit path. This requires a bit of dataflow, but
// would not be too hard to do.
// If we have an invoke instruction, insert a setjmp that dominates all
// invokes. After the setjmp, use a cond branch that goes to the original
// code path on zero, and to a designated 'catch' block of nonzero.
Value *OldJmpBufPtr = 0;
if (!Invokes.empty()) {
// First thing we need to do is scan the whole function for values that are
// live across unwind edges. Each value that is live across an unwind edge
// we spill into a stack location, guaranteeing that there is nothing live
// across the unwind edge. This process also splits all critical edges
// coming out of invoke's.
splitLiveRangesLiveAcrossInvokes(Invokes);
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 live across invokes.
const TargetLowering *TLI = TM ? TM->getTargetLowering() : 0;
unsigned Align = TLI ? TLI->getJumpBufAlignment() : 0;
AllocaInst *JmpBuf =
new AllocaInst(JBLinkTy, 0, Align,
"jblink", F.begin()->begin());
Value *Idx[] = { Constant::getNullValue(Type::getInt32Ty(F.getContext())),
ConstantInt::get(Type::getInt32Ty(F.getContext()), 1) };
OldJmpBufPtr = GetElementPtrInst::Create(JmpBuf, Idx, "OldBuf",
EntryBB->getTerminator());
// Copy the JBListHead to the alloca.
Value *OldBuf = new LoadInst(JBListHead, "oldjmpbufptr", true,
EntryBB->getTerminator());
new StoreInst(OldBuf, OldJmpBufPtr, true, EntryBB->getTerminator());
// Add the new jumpbuf to the list.
new StoreInst(JmpBuf, JBListHead, true, EntryBB->getTerminator());
// Create the catch block. The catch block is basically a big switch
// statement that goes to all of the invoke catch blocks.
BasicBlock *CatchBB =
BasicBlock::Create(F.getContext(), "setjmp.catch", &F);
// Create an alloca which keeps track of the stack pointer before every
// invoke, this allows us to properly restore the stack pointer after
// long jumping.
AllocaInst *StackPtr = new AllocaInst(Type::getInt8PtrTy(F.getContext()), 0,
"stackptr", EntryBB->begin());
// Create an alloca which keeps track of which invoke is currently
// executing. For normal calls it contains zero.
AllocaInst *InvokeNum = new AllocaInst(Type::getInt32Ty(F.getContext()), 0,
"invokenum",EntryBB->begin());
new StoreInst(ConstantInt::get(Type::getInt32Ty(F.getContext()), 0),
InvokeNum, true, EntryBB->getTerminator());
// Insert a load in the Catch 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). We insert an unreachable instruction here and
// modify the block to jump to the correct unwinding pad later.
BasicBlock *UnwindBB = BasicBlock::Create(F.getContext(), "unwindbb", &F);
UnreachablePlaceholder = new UnreachableInst(F.getContext(), UnwindBB);
Value *CatchLoad = new LoadInst(InvokeNum, "invoke.num", true, CatchBB);
SwitchInst *CatchSwitch =
SwitchInst::Create(CatchLoad, UnwindBB, Invokes.size(), CatchBB);
// Now that things are set up, insert the setjmp call itself.
// Split the entry block to insert the conditional branch for the setjmp.
BasicBlock *ContBlock = EntryBB->splitBasicBlock(EntryBB->getTerminator(),
"setjmp.cont");
Idx[1] = ConstantInt::get(Type::getInt32Ty(F.getContext()), 0);
Value *JmpBufPtr = GetElementPtrInst::Create(JmpBuf, Idx, "TheJmpBuf",
EntryBB->getTerminator());
JmpBufPtr = new BitCastInst(JmpBufPtr,
Type::getInt8PtrTy(F.getContext()),
"tmp", EntryBB->getTerminator());
Value *SJRet = CallInst::Create(SetJmpFn, JmpBufPtr, "sjret",
EntryBB->getTerminator());
// Compare the return value to zero.
Value *IsNormal = new ICmpInst(EntryBB->getTerminator(),
ICmpInst::ICMP_EQ, SJRet,
Constant::getNullValue(SJRet->getType()),
"notunwind");
// Nuke the uncond branch.
EntryBB->getTerminator()->eraseFromParent();
// Put in a new condbranch in its place.
BranchInst::Create(ContBlock, CatchBB, IsNormal, EntryBB);
// At this point, we are all set up, rewrite each invoke instruction.
for (unsigned i = 0, e = Invokes.size(); i != e; ++i)
rewriteExpensiveInvoke(Invokes[i], i+1, InvokeNum, StackPtr, CatchSwitch);
}
// We know that there is at least one unwind.
// Create three new blocks, the block to load the jmpbuf ptr and compare
// against null, the block to do the longjmp, and the error block for if it
// is null. Add them at the end of the function because they are not hot.
BasicBlock *UnwindHandler = BasicBlock::Create(F.getContext(),
"dounwind", &F);
BasicBlock *UnwindBlock = BasicBlock::Create(F.getContext(), "unwind", &F);
BasicBlock *TermBlock = BasicBlock::Create(F.getContext(), "unwinderror", &F);
// If this function contains an invoke, restore the old jumpbuf ptr.
Value *BufPtr;
if (OldJmpBufPtr) {
// Before the return, insert a copy from the saved value to the new value.
BufPtr = new LoadInst(OldJmpBufPtr, "oldjmpbufptr", UnwindHandler);
new StoreInst(BufPtr, JBListHead, UnwindHandler);
} else {
BufPtr = new LoadInst(JBListHead, "ehlist", UnwindHandler);
}
// Load the JBList, if it's null, then there was no catch!
Value *NotNull = new ICmpInst(*UnwindHandler, ICmpInst::ICMP_NE, BufPtr,
Constant::getNullValue(BufPtr->getType()),
"notnull");
BranchInst::Create(UnwindBlock, TermBlock, NotNull, UnwindHandler);
// Create the block to do the longjmp.
// Get a pointer to the jmpbuf and longjmp.
Value *Idx[] = { Constant::getNullValue(Type::getInt32Ty(F.getContext())),
ConstantInt::get(Type::getInt32Ty(F.getContext()), 0) };
Idx[0] = GetElementPtrInst::Create(BufPtr, Idx, "JmpBuf", UnwindBlock);
Idx[0] = new BitCastInst(Idx[0],
Type::getInt8PtrTy(F.getContext()),
"tmp", UnwindBlock);
Idx[1] = ConstantInt::get(Type::getInt32Ty(F.getContext()), 1);
CallInst::Create(LongJmpFn, Idx, "", UnwindBlock);
new UnreachableInst(F.getContext(), UnwindBlock);
// Set up the term block ("throw without a catch").
new UnreachableInst(F.getContext(), TermBlock);
// Insert a call to abort()
CallInst::Create(AbortFn, "",
TermBlock->getTerminator())->setTailCall();
// Replace the inserted unreachable with a branch to the unwind handler.
if (UnreachablePlaceholder) {
BranchInst::Create(UnwindHandler, UnreachablePlaceholder);
UnreachablePlaceholder->eraseFromParent();
}
// Finally, for any returns from this function, if this function contains an
// invoke, restore the old jmpbuf pointer to its input value.
if (OldJmpBufPtr) {
for (unsigned i = 0, e = Returns.size(); i != e; ++i) {
ReturnInst *R = Returns[i];
// Before the return, insert a copy from the saved value to the new value.
Value *OldBuf = new LoadInst(OldJmpBufPtr, "oldjmpbufptr", true, R);
new StoreInst(OldBuf, JBListHead, true, R);
}
}
return true;
}
bool LowerInvoke::runOnFunction(Function &F) {
if (useExpensiveEHSupport)
return insertExpensiveEHSupport(F);
else
return insertCheapEHSupport(F);
}

View File

@ -1,15 +0,0 @@
; RUN: opt < %s -lowerinvoke -enable-correct-eh-support -disable-output
define void @_ZNKSt11__use_cacheISt16__numpunct_cacheIcEEclERKSt6locale() {
entry:
br i1 false, label %then, label %UnifiedReturnBlock
then: ; preds = %entry
invoke void @_Znwj( )
to label %UnifiedReturnBlock unwind label %UnifiedReturnBlock
UnifiedReturnBlock: ; preds = %then, %then, %entry
%UnifiedRetVal = phi i32* [ null, %entry ], [ null, %then ], [ null, %then ] ; <i32*> [#uses=0]
ret void
}
declare void @_Znwj()

View File

@ -1,17 +0,0 @@
; RUN: opt < %s -lowerinvoke -enable-correct-eh-support -disable-output
declare void @ll_listnext__listiterPtr()
define void @WorkTask.fn() {
block0:
invoke void @ll_listnext__listiterPtr( )
to label %block9 unwind label %block8_exception_handling
block8_exception_handling: ; preds = %block0
ret void
block9: ; preds = %block0
%w_2690 = phi { i32, i32 }* [ null, %block0 ] ; <{ i32, i32 }*> [#uses=1]
%tmp.129 = getelementptr { i32, i32 }* %w_2690, i32 0, i32 1 ; <i32*> [#uses=1]
%v2769 = load i32* %tmp.129 ; <i32> [#uses=0]
ret void
}

View File

@ -1,15 +0,0 @@
; RUN: opt < %s -lowerinvoke -enable-correct-eh-support -disable-output
declare fastcc i32 @ll_listnext__listiterPtr()
define fastcc i32 @WorkTask.fn() {
block0:
%v2679 = invoke fastcc i32 @ll_listnext__listiterPtr( )
to label %block9 unwind label %block8_exception_handling ; <i32> [#uses=1]
block8_exception_handling: ; preds = %block0
ret i32 0
block9: ; preds = %block0
%i_2689 = phi i32 [ %v2679, %block0 ] ; <i32> [#uses=1]
ret i32 %i_2689
}

View File

@ -1,14 +0,0 @@
; RUN: opt < %s -lowerinvoke -enable-correct-eh-support -disable-output
; PR2029
define i32 @main(i32 %argc, i8** %argv) {
bb470:
invoke i32 @main(i32 0, i8** null) to label %invcont474 unwind label
%lpad902
invcont474: ; preds = %bb470
ret i32 0
lpad902: ; preds = %bb470
%tmp471.lcssa = phi i8* [ null, %bb470 ] ; <i8*>
ret i32 0
}

View File

@ -1,30 +0,0 @@
; RUN: opt < %s -lowerinvoke -disable-output -enable-correct-eh-support
define i32 @foo() {
invoke i32 @foo( )
to label %Ok unwind label %Crap ; <i32>:1 [#uses=0]
Ok: ; preds = %0
invoke i32 @foo( )
to label %Ok2 unwind label %Crap ; <i32>:2 [#uses=0]
Ok2: ; preds = %Ok
ret i32 2
Crap: ; preds = %Ok, %0
ret i32 1
}
define i32 @bar(i32 %blah) {
br label %doit
doit: ; preds = %0
;; Value live across an unwind edge.
%B2 = add i32 %blah, 1 ; <i32> [#uses=1]
invoke i32 @foo( )
to label %Ok unwind label %Crap ; <i32>:1 [#uses=0]
Ok: ; preds = %doit
invoke i32 @foo( )
to label %Ok2 unwind label %Crap ; <i32>:2 [#uses=0]
Ok2: ; preds = %Ok
ret i32 2
Crap: ; preds = %Ok, %doit
ret i32 %B2
}