//
// 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.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "lowerinvoke"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Target/TargetLowering.h"
#include <csetjmp>
+#include <set>
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<bool> ExpensiveEHSupport("enable-correct-eh-support",
+STATISTIC(NumInvokes, "Number of invokes replaced");
+STATISTIC(NumUnwinds, "Number of unwinds 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 VISIBILITY_HIDDEN LowerInvoke : public FunctionPass {
// Used for both models.
- Function *WriteFn;
- Function *AbortFn;
+ Constant *WriteFn;
+ Constant *AbortFn;
Value *AbortMessage;
unsigned AbortMessageLength;
// Used for expensive EH support.
const Type *JBLinkTy;
GlobalVariable *JBListHead;
- Function *SetJmpFn, *LongJmpFn;
+ Constant *SetJmpFn, *LongJmpFn;
// 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)
+ : FunctionPass((intptr_t)&ID), TLI(tli) { }
bool doInitialization(Module &M);
bool runOnFunction(Function &F);
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- // This is a cluster of orthogonal Transforms
+ // This is a cluster of orthogonal Transforms
AU.addPreservedID(PromoteMemoryToRegisterID);
- AU.addPreservedID(LowerSelectID);
AU.addPreservedID(LowerSwitchID);
AU.addPreservedID(LowerAllocationsID);
}
private:
- void createAbortMessage();
+ void createAbortMessage(Module *M);
void writeAbortMessage(Instruction *IB);
bool insertCheapEHSupport(Function &F);
void splitLiveRangesLiveAcrossInvokes(std::vector<InvokeInst*> &Invokes);
bool insertExpensiveEHSupport(Function &F);
};
+ char LowerInvoke::ID = 0;
RegisterPass<LowerInvoke>
X("lowerinvoke", "Lower invoke and unwind, for unwindless code generators");
}
// 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);
+ const Type *VoidPtrTy = PointerType::getUnqual(Type::Int8Ty);
AbortMessage = 0;
if (ExpensiveEHSupport) {
// Insert a type for the linked list of jump buffers.
std::vector<const Type*> Elements;
Elements.push_back(JmpBufTy);
OpaqueType *OT = OpaqueType::get();
- Elements.push_back(PointerType::get(OT));
+ Elements.push_back(PointerType::getUnqual(OT));
PATypeHolder JBLType(StructType::get(Elements));
OT->refineAbstractTypeTo(JBLType.get()); // Complete the cycle.
JBLinkTy = JBLType.get();
M.addTypeName("llvm.sjljeh.jmpbufty", JBLinkTy);
}
- const Type *PtrJBList = PointerType::get(JBLinkTy);
+ const Type *PtrJBList = PointerType::getUnqual(JBLinkTy);
// Now that we've done that, insert the jmpbuf list head global, unless it
// already exists.
Constant::getNullValue(PtrJBList),
"llvm.sjljeh.jblist", &M);
}
- SetJmpFn = M.getOrInsertFunction("llvm.setjmp", Type::IntTy,
- PointerType::get(JmpBufTy), (Type *)0);
+ SetJmpFn = M.getOrInsertFunction("llvm.setjmp", Type::Int32Ty,
+ PointerType::getUnqual(JmpBufTy),
+ (Type *)0);
LongJmpFn = M.getOrInsertFunction("llvm.longjmp", Type::VoidTy,
- PointerType::get(JmpBufTy),
- Type::IntTy, (Type *)0);
+ PointerType::getUnqual(JmpBufTy),
+ Type::Int32Ty, (Type *)0);
}
// 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);
- }
+#if 0 // "write" is Unix-specific.. code is going away soon anyway.
+ WriteFn = M.getOrInsertFunction("write", Type::VoidTy, Type::Int32Ty,
+ VoidPtrTy, Type::Int32Ty, (Type *)0);
+#else
+ WriteFn = 0;
+#endif
return true;
}
-void LowerInvoke::createAbortMessage() {
- Module &M = *WriteFn->getParent();
+void LowerInvoke::createAbortMessage(Module *M) {
if (ExpensiveEHSupport) {
// The abort message for expensive EH support tells the user that the
// program 'unwound' without an 'invoke' instruction.
GlobalVariable *MsgGV = new GlobalVariable(Msg->getType(), true,
GlobalValue::InternalLinkage,
- Msg, "abortmsg", &M);
- std::vector<Constant*> GEPIdx(2, Constant::getNullValue(Type::IntTy));
- AbortMessage = ConstantExpr::getGetElementPtr(MsgGV, GEPIdx);
+ Msg, "abortmsg", M);
+ std::vector<Constant*> GEPIdx(2, Constant::getNullValue(Type::Int32Ty));
+ AbortMessage = ConstantExpr::getGetElementPtr(MsgGV, &GEPIdx[0], 2);
} else {
// The abort message for cheap EH support tells the user that EH is not
// enabled.
GlobalVariable *MsgGV = new GlobalVariable(Msg->getType(), true,
GlobalValue::InternalLinkage,
- Msg, "abortmsg", &M);
- std::vector<Constant*> GEPIdx(2, Constant::getNullValue(Type::IntTy));
- AbortMessage = ConstantExpr::getGetElementPtr(MsgGV, GEPIdx);
+ Msg, "abortmsg", M);
+ std::vector<Constant*> GEPIdx(2, Constant::getNullValue(Type::Int32Ty));
+ AbortMessage = ConstantExpr::getGetElementPtr(MsgGV, &GEPIdx[0], 2);
}
}
void LowerInvoke::writeAbortMessage(Instruction *IB) {
- if (WriteFn) {
- if (AbortMessage == 0) createAbortMessage();
-
- // These are the arguments we WANT...
- std::vector<Value*> 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())
- Args[i] = ConstantExpr::getCast(cast<Constant>(Args[i]),
- FT->getParamType(i));
-
- (new CallInst(WriteFn, Args, "", IB))->setTailCall();
- }
+#if 0
+ if (AbortMessage == 0)
+ createAbortMessage(IB->getParent()->getParent()->getParent());
+
+ // These are the arguments we WANT...
+ Value* Args[3];
+ Args[0] = ConstantInt::get(Type::Int32Ty, 2);
+ Args[1] = AbortMessage;
+ Args[2] = ConstantInt::get(Type::Int32Ty, AbortMessageLength);
+ (new CallInst(WriteFn, Args, 3, "", IB))->setTailCall();
+#endif
}
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<InvokeInst>(BB->getTerminator())) {
+ std::vector<Value*> CallArgs(II->op_begin()+3, II->op_end());
// Insert a normal call instruction...
- std::string Name = II->getName(); II->setName("");
- CallInst *NewCall = new CallInst(II->getCalledValue(),
- std::vector<Value*>(II->op_begin()+3,
- II->op_end()), Name, II);
+ CallInst *NewCall = CallInst::Create(II->getCalledValue(),
+ CallArgs.begin(), CallArgs.end(), "",II);
+ NewCall->takeName(II);
NewCall->setCallingConv(II->getCallingConv());
+ NewCall->setParamAttrs(II->getParamAttrs());
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);
writeAbortMessage(UI);
// Insert a call to abort()
- (new CallInst(AbortFn, std::vector<Value*>(), "", UI))->setTailCall();
+ CallInst::Create(AbortFn, "", 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);
+ ReturnInst::Create(F.getReturnType() == Type::VoidTy ? 0 :
+ Constant::getNullValue(F.getReturnType()), UI);
// Remove the unwind instruction now.
BB->getInstList().erase(UI);
void LowerInvoke::rewriteExpensiveInvoke(InvokeInst *II, unsigned InvokeNo,
AllocaInst *InvokeNum,
SwitchInst *CatchSwitch) {
- ConstantInt *InvokeNoC = ConstantInt::get(Type::UIntTy, InvokeNo);
+ ConstantInt *InvokeNoC = ConstantInt::get(Type::Int32Ty, 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
BasicBlock::iterator NI = II->getNormalDest()->begin();
while (isa<PHINode>(NI)) ++NI;
// nonvolatile.
- new StoreInst(Constant::getNullValue(Type::UIntTy), InvokeNum, false, NI);
+ new StoreInst(Constant::getNullValue(Type::Int32Ty), InvokeNum, false, NI);
// 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<Value*>(II->op_begin()+3,
- II->op_end()), Name,
- II);
+ std::vector<Value*> CallArgs(II->op_begin()+3, II->op_end());
+ CallInst *NewCall = CallInst::Create(II->getCalledValue(),
+ CallArgs.begin(), CallArgs.end(), "",
+ II);
+ NewCall->takeName(II);
NewCall->setCallingConv(II->getCallingConv());
+ NewCall->setParamAttrs(II->getParamAttrs());
II->replaceAllUsesWith(NewCall);
// Replace the invoke with an uncond branch.
- new BranchInst(II->getNormalDest(), NewCall->getParent());
+ BranchInst::Create(II->getNormalDest(), NewCall->getParent());
II->eraseFromParent();
}
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 ensure that the argument
+ // 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) &&
++AfterAllocaInsertPt;
for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end();
AI != E; ++AI) {
- CastInst *NC = new CastInst(AI, AI->getType(), AI->getName()+".tmp",
- AfterAllocaInsertPt);
+ // 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);
- NC->setOperand(0, AI);
+ // 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);
}
// Finally, scan the code looking for instructions with bad live ranges.
new AllocaInst(JBLinkTy, 0, Align, "jblink", F.begin()->begin());
std::vector<Value*> Idx;
- Idx.push_back(Constant::getNullValue(Type::IntTy));
- Idx.push_back(ConstantInt::get(Type::UIntTy, 1));
- OldJmpBufPtr = new GetElementPtrInst(JmpBuf, Idx, "OldBuf",
- EntryBB->getTerminator());
+ Idx.push_back(Constant::getNullValue(Type::Int32Ty));
+ Idx.push_back(ConstantInt::get(Type::Int32Ty, 1));
+ OldJmpBufPtr = GetElementPtrInst::Create(JmpBuf, Idx.begin(), Idx.end(),
+ "OldBuf", EntryBB->getTerminator());
// Copy the JBListHead to the alloca.
Value *OldBuf = new LoadInst(JBListHead, "oldjmpbufptr", true,
// 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("setjmp.catch", &F);
// 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",
+ AllocaInst *InvokeNum = new AllocaInst(Type::Int32Ty, 0, "invokenum",
EntryBB->begin());
- new StoreInst(ConstantInt::get(Type::UIntTy, 0), InvokeNum, true,
+ new StoreInst(ConstantInt::get(Type::Int32Ty, 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);
+ BasicBlock *UnwindBB = BasicBlock::Create("unwindbb", &F);
Unwinds.push_back(new UnwindInst(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.
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::Int32Ty, 0);
+ Value *JmpBufPtr = GetElementPtrInst::Create(JmpBuf, Idx.begin(), Idx.end(),
+ "TheJmpBuf",
+ 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(ICmpInst::ICMP_EQ, SJRet,
+ Constant::getNullValue(SJRet->getType()),
+ "notunwind", EntryBB->getTerminator());
// 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)
// 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("dounwind", &F);
+ BasicBlock *UnwindBlock = BasicBlock::Create("unwind", &F);
+ BasicBlock *TermBlock = BasicBlock::Create("unwinderror", &F);
// If this function contains an invoke, restore the old jumpbuf ptr.
Value *BufPtr;
}
// 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(ICmpInst::ICMP_NE, BufPtr,
+ Constant::getNullValue(BufPtr->getType()),
+ "notnull", UnwindHandler);
+ BranchInst::Create(UnwindBlock, TermBlock, NotNull, UnwindHandler);
// Create the block to do the longjmp.
// Get a pointer to the jmpbuf and longjmp.
std::vector<Value*> 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);
+ Idx.push_back(Constant::getNullValue(Type::Int32Ty));
+ Idx.push_back(ConstantInt::get(Type::Int32Ty, 0));
+ Idx[0] = GetElementPtrInst::Create(BufPtr, Idx.begin(), Idx.end(), "JmpBuf",
+ UnwindBlock);
+ Idx[1] = ConstantInt::get(Type::Int32Ty, 1);
+ CallInst::Create(LongJmpFn, Idx.begin(), Idx.end(), "", UnwindBlock);
new UnreachableInst(UnwindBlock);
// Set up the term block ("throw without a catch").
writeAbortMessage(TermBlock->getTerminator());
// Insert a call to abort()
- (new CallInst(AbortFn, std::vector<Value*>(), "",
- TermBlock->getTerminator()))->setTailCall();
+ CallInst::Create(AbortFn, "",
+ 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]);
+ BranchInst::Create(UnwindHandler, Unwinds[i]);
Unwinds[i]->eraseFromParent();
}