X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTransforms%2FUtils%2FLowerInvoke.cpp;h=9ec84d730e46d8ed4ae95def24852a40078ee8ce;hp=4fbd43c6f4dcdcf92429fe98ee38b963b96a00cd;hb=0b8c9a80f20772c3793201ab5b251d3520b9cea3;hpb=4da49122f3f3c8da68a52723d846b88c72166a68 diff --git a/lib/Transforms/Utils/LowerInvoke.cpp b/lib/Transforms/Utils/LowerInvoke.cpp index 4fbd43c6f4d..9ec84d730e4 100644 --- a/lib/Transforms/Utils/LowerInvoke.cpp +++ b/lib/Transforms/Utils/LowerInvoke.cpp @@ -2,8 +2,8 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -34,212 +34,156 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "lowerinvoke" #include "llvm/Transforms/Scalar.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Instructions.h" -#include "llvm/Module.h" -#include "llvm/Pass.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/Local.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/Support/Compiler.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Local.h" #include +#include using namespace llvm; -namespace { - Statistic NumInvokes("lowerinvoke", "Number of invokes replaced"); - Statistic NumUnwinds("lowerinvoke", "Number of unwinds replaced"); - Statistic NumSpilled("lowerinvoke", - "Number of registers live across unwind edges"); - cl::opt ExpensiveEHSupport("enable-correct-eh-support", +STATISTIC(NumInvokes, "Number of invokes replaced"); +STATISTIC(NumSpilled, "Number of registers live across unwind edges"); + +static cl::opt ExpensiveEHSupport("enable-correct-eh-support", cl::desc("Make the -lowerinvoke pass insert expensive, but correct, EH code")); - class VISIBILITY_HIDDEN LowerInvoke : public FunctionPass { +namespace { + class LowerInvoke : public FunctionPass { // Used for both models. - Function *WriteFn; - Function *AbortFn; - Value *AbortMessage; - unsigned AbortMessageLength; + Constant *AbortFn; // Used for expensive EH support. - const Type *JBLinkTy; + StructType *JBLinkTy; GlobalVariable *JBListHead; - Function *SetJmpFn, *LongJmpFn; - + Constant *SetJmpFn, *LongJmpFn, *StackSaveFn, *StackRestoreFn; + bool useExpensiveEHSupport; + // We peek in TLI to grab the target's jmp_buf size and alignment const TargetLowering *TLI; - + public: - LowerInvoke(const TargetLowering *tli = NULL) : TLI(tli) { } + static char ID; // Pass identification, replacement for typeid + explicit LowerInvoke(const TargetLowering *tli = NULL, + bool useExpensiveEHSupport = ExpensiveEHSupport) + : FunctionPass(ID), useExpensiveEHSupport(useExpensiveEHSupport), + TLI(tli) { + initializeLowerInvokePass(*PassRegistry::getPassRegistry()); + } bool doInitialization(Module &M); bool runOnFunction(Function &F); - + virtual void getAnalysisUsage(AnalysisUsage &AU) const { - // This is a cluster of orthogonal Transforms - AU.addPreservedID(PromoteMemoryToRegisterID); - AU.addPreservedID(LowerSelectID); + // This is a cluster of orthogonal Transforms + AU.addPreserved("mem2reg"); AU.addPreservedID(LowerSwitchID); - AU.addPreservedID(LowerAllocationsID); } - + private: - void createAbortMessage(); - void writeAbortMessage(Instruction *IB); bool insertCheapEHSupport(Function &F); - void splitLiveRangesLiveAcrossInvokes(std::vector &Invokes); + void splitLiveRangesLiveAcrossInvokes(SmallVectorImpl&Invokes); void rewriteExpensiveInvoke(InvokeInst *II, unsigned InvokeNo, - AllocaInst *InvokeNum, SwitchInst *CatchSwitch); + AllocaInst *InvokeNum, AllocaInst *StackPtr, + SwitchInst *CatchSwitch); bool insertExpensiveEHSupport(Function &F); }; - - RegisterPass - X("lowerinvoke", "Lower invoke and unwind, for unwindless code generators"); } -const PassInfo *llvm::LowerInvokePassID = X.getPassInfo(); +char LowerInvoke::ID = 0; +INITIALIZE_PASS(LowerInvoke, "lowerinvoke", + "Lower invoke and unwind, for unwindless code generators", + false, false) + +char &llvm::LowerInvokePassID = LowerInvoke::ID; // Public Interface To the LowerInvoke pass. -FunctionPass *llvm::createLowerInvokePass(const TargetLowering *TLI) { - return new LowerInvoke(TLI); +FunctionPass *llvm::createLowerInvokePass(const TargetLowering *TLI) { + return new LowerInvoke(TLI, ExpensiveEHSupport); +} +FunctionPass *llvm::createLowerInvokePass(const TargetLowering *TLI, + bool useExpensiveEHSupport) { + return new LowerInvoke(TLI, useExpensiveEHSupport); } // doInitialization - Make sure that there is a prototype for abort in the // current module. bool LowerInvoke::doInitialization(Module &M) { - const Type *VoidPtrTy = PointerType::get(Type::SByteTy); - AbortMessage = 0; - if (ExpensiveEHSupport) { + Type *VoidPtrTy = Type::getInt8PtrTy(M.getContext()); + if (useExpensiveEHSupport) { // Insert a type for the linked list of jump buffers. unsigned JBSize = TLI ? TLI->getJumpBufSize() : 0; JBSize = JBSize ? JBSize : 200; - const Type *JmpBufTy = ArrayType::get(VoidPtrTy, JBSize); - - { // The type is recursive, so use a type holder. - std::vector Elements; - Elements.push_back(JmpBufTy); - OpaqueType *OT = OpaqueType::get(); - Elements.push_back(PointerType::get(OT)); - PATypeHolder JBLType(StructType::get(Elements)); - OT->refineAbstractTypeTo(JBLType.get()); // Complete the cycle. - JBLinkTy = JBLType.get(); - M.addTypeName("llvm.sjljeh.jmpbufty", JBLinkTy); - } + Type *JmpBufTy = ArrayType::get(VoidPtrTy, JBSize); - const Type *PtrJBList = PointerType::get(JBLinkTy); + 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(PtrJBList, false, - GlobalValue::LinkOnceLinkage, + JBListHead = new GlobalVariable(M, PtrJBList, false, + GlobalValue::LinkOnceAnyLinkage, Constant::getNullValue(PtrJBList), - "llvm.sjljeh.jblist", &M); + "llvm.sjljeh.jblist"); } - SetJmpFn = M.getOrInsertFunction("llvm.setjmp", Type::IntTy, - PointerType::get(JmpBufTy), (Type *)0); - LongJmpFn = M.getOrInsertFunction("llvm.longjmp", Type::VoidTy, - PointerType::get(JmpBufTy), - Type::IntTy, (Type *)0); + +// 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::VoidTy, (Type *)0); - - // Unfortunately, 'write' can end up being prototyped in several different - // ways. If the user defines a three (or more) operand function named 'write' - // we will use their prototype. We _do not_ want to insert another instance - // of a write prototype, because we don't know that the funcresolve pass will - // run after us. If there is a definition of a write function, but it's not - // suitable for our uses, we just don't emit write calls. If there is no - // write prototype at all, we just add one. - if (Function *WF = M.getNamedFunction("write")) { - if (WF->getFunctionType()->getNumParams() > 3 || - WF->getFunctionType()->isVarArg()) - WriteFn = WF; - else - WriteFn = 0; - } else { - WriteFn = M.getOrInsertFunction("write", Type::VoidTy, Type::IntTy, - VoidPtrTy, Type::IntTy, (Type *)0); - } + AbortFn = M.getOrInsertFunction("abort", Type::getVoidTy(M.getContext()), + (Type *)0); return true; } -void LowerInvoke::createAbortMessage() { - Module &M = *WriteFn->getParent(); - if (ExpensiveEHSupport) { - // The abort message for expensive EH support tells the user that the - // program 'unwound' without an 'invoke' instruction. - Constant *Msg = - ConstantArray::get("ERROR: Exception thrown, but not caught!\n"); - AbortMessageLength = Msg->getNumOperands()-1; // don't include \0 - - GlobalVariable *MsgGV = new GlobalVariable(Msg->getType(), true, - GlobalValue::InternalLinkage, - Msg, "abortmsg", &M); - std::vector GEPIdx(2, Constant::getNullValue(Type::IntTy)); - AbortMessage = ConstantExpr::getGetElementPtr(MsgGV, GEPIdx); - } else { - // The abort message for cheap EH support tells the user that EH is not - // enabled. - Constant *Msg = - ConstantArray::get("Exception handler needed, but not enabled. Recompile" - " program with -enable-correct-eh-support.\n"); - AbortMessageLength = Msg->getNumOperands()-1; // don't include \0 - - GlobalVariable *MsgGV = new GlobalVariable(Msg->getType(), true, - GlobalValue::InternalLinkage, - Msg, "abortmsg", &M); - std::vector GEPIdx(2, Constant::getNullValue(Type::IntTy)); - AbortMessage = ConstantExpr::getGetElementPtr(MsgGV, GEPIdx); - } -} - - -void LowerInvoke::writeAbortMessage(Instruction *IB) { - if (WriteFn) { - if (AbortMessage == 0) createAbortMessage(); - - // These are the arguments we WANT... - std::vector Args; - Args.push_back(ConstantInt::get(Type::IntTy, 2)); - Args.push_back(AbortMessage); - Args.push_back(ConstantInt::get(Type::IntTy, AbortMessageLength)); - - // If the actual declaration of write disagrees, insert casts as - // appropriate. - const FunctionType *FT = WriteFn->getFunctionType(); - unsigned NumArgs = FT->getNumParams(); - for (unsigned i = 0; i != 3; ++i) - if (i < NumArgs && FT->getParamType(i) != Args[i]->getType()) - if (Args[i]->getType()->isInteger()) - Args[i] = ConstantExpr::getIntegerCast(cast(Args[i]), - FT->getParamType(i), true); - else - Args[i] = ConstantExpr::getBitCast(cast(Args[i]), - FT->getParamType(i)); - - (new CallInst(WriteFn, Args, "", IB))->setTailCall(); - } -} - bool LowerInvoke::insertCheapEHSupport(Function &F) { bool Changed = false; for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) if (InvokeInst *II = dyn_cast(BB->getTerminator())) { + SmallVector CallArgs(II->op_begin(), II->op_end() - 3); // Insert a normal call instruction... - std::string Name = II->getName(); II->setName(""); - CallInst *NewCall = new CallInst(II->getCalledValue(), - std::vector(II->op_begin()+3, - II->op_end()), Name, II); + 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); // Insert an unconditional branch to the normal destination. - new BranchInst(II->getNormalDest(), II); + BranchInst::Create(II->getNormalDest(), II); // Remove any PHI node entries from the exception destination. II->getUnwindDest()->removePredecessor(BB); @@ -248,22 +192,6 @@ bool LowerInvoke::insertCheapEHSupport(Function &F) { BB->getInstList().erase(II); ++NumInvokes; Changed = true; - } else if (UnwindInst *UI = dyn_cast(BB->getTerminator())) { - // Insert a new call to write(2, AbortMessage, AbortMessageLength); - writeAbortMessage(UI); - - // Insert a call to abort() - (new CallInst(AbortFn, std::vector(), "", UI))->setTailCall(); - - // Insert a return instruction. This really should be a "barrier", as it - // is unreachable. - new ReturnInst(F.getReturnType() == Type::VoidTy ? 0 : - Constant::getNullValue(F.getReturnType()), UI); - - // Remove the unwind instruction now. - BB->getInstList().erase(UI); - - ++NumUnwinds; Changed = true; } return Changed; } @@ -272,32 +200,56 @@ bool LowerInvoke::insertCheapEHSupport(Function &F) { /// specified invoke instruction with a call. void LowerInvoke::rewriteExpensiveInvoke(InvokeInst *II, unsigned InvokeNo, AllocaInst *InvokeNum, + AllocaInst *StackPtr, SwitchInst *CatchSwitch) { - ConstantInt *InvokeNoC = ConstantInt::get(Type::UIntTy, InvokeNo); + ConstantInt *InvokeNoC = ConstantInt::get(Type::getInt32Ty(II->getContext()), + InvokeNo); + + // If the unwind edge has phi nodes, split the edge. + if (isa(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(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 - BasicBlock::iterator NI = II->getNormalDest()->begin(); - while (isa(NI)) ++NI; + // 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::UIntTy), InvokeNum, false, NI); - + 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. - std::string Name = II->getName(); II->setName(""); - CallInst *NewCall = new CallInst(II->getCalledValue(), - std::vector(II->op_begin()+3, - II->op_end()), Name, - II); + SmallVector 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. - new BranchInst(II->getNormalDest(), NewCall->getParent()); + BranchInst::Create(II->getNormalDest(), NewCall->getParent()); II->eraseFromParent(); } @@ -305,9 +257,9 @@ void LowerInvoke::rewriteExpensiveInvoke(InvokeInst *II, unsigned InvokeNo, /// we reach blocks we've already seen. static void MarkBlocksLiveIn(BasicBlock *BB, std::set &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); + MarkBlocksLiveIn(*PI, LiveBBs); } // First thing we need to do is scan the whole function for values that are @@ -316,7 +268,7 @@ static void MarkBlocksLiveIn(BasicBlock *BB, std::set &LiveBBs) { // across the unwind edge. This process also splits all critical edges // coming out of invoke's. void LowerInvoke:: -splitLiveRangesLiveAcrossInvokes(std::vector &Invokes) { +splitLiveRangesLiveAcrossInvokes(SmallVectorImpl &Invokes) { // First step, split all critical edges from invoke instructions. for (unsigned i = 0, e = Invokes.size(); i != e; ++i) { InvokeInst *II = Invokes[i]; @@ -328,7 +280,7 @@ splitLiveRangesLiveAcrossInvokes(std::vector &Invokes) { } 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. @@ -338,18 +290,35 @@ splitLiveRangesLiveAcrossInvokes(std::vector &Invokes) { ++AfterAllocaInsertPt; for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); AI != E; ++AI) { - // 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); - // Normally its is 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 to simply - // make NC its user. - NC->setOperand(0, 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(Ty) || isa(Ty) || isa(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) { @@ -361,15 +330,15 @@ splitLiveRangesLiveAcrossInvokes(std::vector &Invokes) { if (Inst->hasOneUse() && cast(Inst->use_back())->getParent() == BB && !isa(Inst->use_back())) continue; - + // If this is an alloca in the entry block, it's not a real register // value. if (AllocaInst *AI = dyn_cast(Inst)) if (isa(AI->getArraySize()) && BB == F->begin()) continue; - + // Avoid iterator invalidation by copying users to a temporary vector. - std::vector Users; + SmallVector Users; for (Value::use_iterator UI = Inst->use_begin(), E = Inst->use_end(); UI != E; ++UI) { Instruction *User = cast(*UI); @@ -388,7 +357,7 @@ splitLiveRangesLiveAcrossInvokes(std::vector &Invokes) { while (!Users.empty()) { Instruction *U = Users.back(); Users.pop_back(); - + if (!isa(U)) { MarkBlocksLiveIn(U->getParent(), LiveBBs); } else { @@ -399,7 +368,7 @@ splitLiveRangesLiveAcrossInvokes(std::vector &Invokes) { 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; @@ -419,9 +388,9 @@ splitLiveRangesLiveAcrossInvokes(std::vector &Invokes) { } bool LowerInvoke::insertExpensiveEHSupport(Function &F) { - std::vector Returns; - std::vector Unwinds; - std::vector Invokes; + SmallVector Returns; + SmallVector Invokes; + UnreachableInst* UnreachablePlaceholder = 0; for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) if (ReturnInst *RI = dyn_cast(BB->getTerminator())) { @@ -430,15 +399,12 @@ bool LowerInvoke::insertExpensiveEHSupport(Function &F) { Returns.push_back(RI); } else if (InvokeInst *II = dyn_cast(BB->getTerminator())) { Invokes.push_back(II); - } else if (UnwindInst *UI = dyn_cast(BB->getTerminator())) { - Unwinds.push_back(UI); } - if (Unwinds.empty() && Invokes.empty()) return false; + if (Invokes.empty()) return false; NumInvokes += Invokes.size(); - NumUnwinds += Unwinds.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 @@ -457,87 +423,100 @@ bool LowerInvoke::insertExpensiveEHSupport(Function &F) { // 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); - + 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. unsigned Align = TLI ? TLI->getJumpBufAlignment() : 0; - AllocaInst *JmpBuf = - new AllocaInst(JBLinkTy, 0, Align, "jblink", F.begin()->begin()); - - std::vector Idx; - Idx.push_back(Constant::getNullValue(Type::IntTy)); - Idx.push_back(ConstantInt::get(Type::UIntTy, 1)); - OldJmpBufPtr = new GetElementPtrInst(JmpBuf, Idx, "OldBuf", - EntryBB->getTerminator()); + 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 = new BasicBlock("setjmp.catch", &F); - + 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::UIntTy, 0, "invokenum", - EntryBB->begin()); - new StoreInst(ConstantInt::get(Type::UIntTy, 0), InvokeNum, true, - EntryBB->getTerminator()); - + 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). - BasicBlock *UnwindBB = new BasicBlock("unwindbb", &F); - Unwinds.push_back(new UnwindInst(UnwindBB)); - + // 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 = - new SwitchInst(CatchLoad, UnwindBB, Invokes.size(), 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::UIntTy, 0); - Value *JmpBufPtr = new GetElementPtrInst(JmpBuf, Idx, "TheJmpBuf", - EntryBB->getTerminator()); - Value *SJRet = new CallInst(SetJmpFn, JmpBufPtr, "sjret", - EntryBB->getTerminator()); - + 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 = BinaryOperator::createSetEQ(SJRet, - Constant::getNullValue(SJRet->getType()), - "notunwind", EntryBB->getTerminator()); + 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. - new BranchInst(ContBlock, CatchBB, IsNormal, EntryBB); + 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, CatchSwitch); + 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 = new BasicBlock("dounwind", &F); - BasicBlock *UnwindBlock = new BasicBlock("unwind", &F); - BasicBlock *TermBlock = new BasicBlock("unwinderror", &F); + 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; @@ -548,57 +527,55 @@ bool LowerInvoke::insertExpensiveEHSupport(Function &F) { } else { BufPtr = new LoadInst(JBListHead, "ehlist", UnwindHandler); } - + // Load the JBList, if it's null, then there was no catch! - Value *NotNull = BinaryOperator::createSetNE(BufPtr, - Constant::getNullValue(BufPtr->getType()), - "notnull", UnwindHandler); - new BranchInst(UnwindBlock, TermBlock, NotNull, UnwindHandler); - + 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. - std::vector Idx; - Idx.push_back(Constant::getNullValue(Type::IntTy)); - Idx.push_back(ConstantInt::get(Type::UIntTy, 0)); - Idx[0] = new GetElementPtrInst(BufPtr, Idx, "JmpBuf", UnwindBlock); - Idx[1] = ConstantInt::get(Type::IntTy, 1); - new CallInst(LongJmpFn, Idx, "", UnwindBlock); - new UnreachableInst(UnwindBlock); - + 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(TermBlock); + new UnreachableInst(F.getContext(), TermBlock); - // Insert a new call to write(2, AbortMessage, AbortMessageLength); - writeAbortMessage(TermBlock->getTerminator()); - // Insert a call to abort() - (new CallInst(AbortFn, std::vector(), "", - TermBlock->getTerminator()))->setTailCall(); - - - // Replace all unwinds with a branch to the unwind handler. - for (unsigned i = 0, e = Unwinds.size(); i != e; ++i) { - new BranchInst(UnwindHandler, Unwinds[i]); - Unwinds[i]->eraseFromParent(); - } - + 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 (ExpensiveEHSupport) + if (useExpensiveEHSupport) return insertExpensiveEHSupport(F); else return insertCheapEHSupport(F);