From b12261ac698bf9c8dd118bb94d87aae266dac98a Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 29 Jan 2005 00:35:16 +0000 Subject: [PATCH] Merge InstrTypes.cpp into this file Adjust to changes in the User class, operand handling is very different. PHI node and switch statements must handle explicit resizing of operand lists. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19891 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/VMCore/Instructions.cpp | 629 ++++++++++++++++++++++++------------ 1 file changed, 430 insertions(+), 199 deletions(-) diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 6ebf85856f3..e936fafa229 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements the LLVM instructions... +// This file implements all of the non-inline methods for the LLVM instruction +// classes. // //===----------------------------------------------------------------------===// @@ -19,14 +20,117 @@ #include "llvm/Support/CallSite.h" using namespace llvm; +//===----------------------------------------------------------------------===// +// TerminatorInst Class +//===----------------------------------------------------------------------===// + +TerminatorInst::TerminatorInst(Instruction::TermOps iType, + Use *Ops, unsigned NumOps, Instruction *IB) + : Instruction(Type::VoidTy, iType, Ops, NumOps, "", IB) { +} + +TerminatorInst::TerminatorInst(Instruction::TermOps iType, + Use *Ops, unsigned NumOps, BasicBlock *IAE) + : Instruction(Type::VoidTy, iType, Ops, NumOps, "", IAE) { +} + + + +//===----------------------------------------------------------------------===// +// PHINode Class +//===----------------------------------------------------------------------===// + +PHINode::PHINode(const PHINode &PN) + : Instruction(PN.getType(), Instruction::PHI, + new Use[PN.getNumOperands()], PN.getNumOperands()), + ReservedSpace(PN.getNumOperands()) { + Use *OL = OperandList; + for (unsigned i = 0, e = PN.getNumOperands(); i != e; i+=2) { + OL[i].init(PN.getOperand(i), this); + OL[i+1].init(PN.getOperand(i+1), this); + } +} + +PHINode::~PHINode() { + delete [] OperandList; +} + +// removeIncomingValue - Remove an incoming value. This is useful if a +// predecessor basic block is deleted. +Value *PHINode::removeIncomingValue(unsigned Idx, bool DeletePHIIfEmpty) { + unsigned NumOps = getNumOperands(); + Use *OL = OperandList; + assert(Idx*2 < NumOps && "BB not in PHI node!"); + Value *Removed = OL[Idx*2]; + + // Move everything after this operand down. + // + // FIXME: we could just swap with the end of the list, then erase. However, + // client might not expect this to happen. The code as it is thrashes the + // use/def lists, which is kinda lame. + for (unsigned i = (Idx+1)*2; i != NumOps; i += 2) { + OL[i-2] = OL[i]; + OL[i-2+1] = OL[i+1]; + } + + // Nuke the last value. + OL[NumOps-2].set(0); + OL[NumOps-2+1].set(0); + NumOperands = NumOps-2; + + // If the PHI node is dead, because it has zero entries, nuke it now. + if (NumOps == 2 && DeletePHIIfEmpty) { + // If anyone is using this PHI, make them use a dummy value instead... + replaceAllUsesWith(UndefValue::get(getType())); + eraseFromParent(); + } + return Removed; +} + +/// resizeOperands - resize operands - This adjusts the length of the operands +/// list according to the following behavior: +/// 1. If NumOps == 0, grow the operand list in response to a push_back style +/// of operation. This grows the number of ops by 1.5 times. +/// 2. If NumOps > NumOperands, reserve space for NumOps operands. +/// 3. If NumOps == NumOperands, trim the reserved space. +/// +void PHINode::resizeOperands(unsigned NumOps) { + if (NumOps == 0) { + NumOps = (getNumOperands())*3/2; + if (NumOps < 4) NumOps = 4; // 4 op PHI nodes are VERY common. + } else if (NumOps*2 > NumOperands) { + // No resize needed. + if (ReservedSpace >= NumOps) return; + } else if (NumOps == NumOperands) { + if (ReservedSpace == NumOps) return; + } else { + return; + } + + ReservedSpace = NumOps; + Use *NewOps = new Use[NumOps]; + Use *OldOps = OperandList; + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + NewOps[i].init(OldOps[i], this); + OldOps[i].set(0); + } + delete [] OldOps; + OperandList = NewOps; +} + + //===----------------------------------------------------------------------===// // CallInst Implementation //===----------------------------------------------------------------------===// -void CallInst::init(Value *Func, const std::vector &Params) -{ - Operands.reserve(1+Params.size()); - Operands.push_back(Use(Func, this)); +CallInst::~CallInst() { + delete [] OperandList; +} + +void CallInst::init(Value *Func, const std::vector &Params) { + NumOperands = Params.size()+1; + Use *OL = OperandList = new Use[Params.size()+1]; + OL[0].init(Func, this); const FunctionType *FTy = cast(cast(Func->getType())->getElementType()); @@ -34,43 +138,43 @@ void CallInst::init(Value *Func, const std::vector &Params) assert((Params.size() == FTy->getNumParams() || (FTy->isVarArg() && Params.size() > FTy->getNumParams())) && "Calling a function with bad signature"); - for (unsigned i = 0; i != Params.size(); i++) - Operands.push_back(Use(Params[i], this)); + for (unsigned i = 0, e = Params.size(); i != e; ++i) + OL[i+1].init(Params[i], this); } -void CallInst::init(Value *Func, Value *Actual1, Value *Actual2) -{ - Operands.reserve(3); - Operands.push_back(Use(Func, this)); +void CallInst::init(Value *Func, Value *Actual1, Value *Actual2) { + NumOperands = 3; + Use *OL = OperandList = new Use[3]; + OL[0].init(Func, this); + OL[1].init(Actual1, this); + OL[2].init(Actual2, this); - const FunctionType *MTy = + const FunctionType *FTy = cast(cast(Func->getType())->getElementType()); - assert((MTy->getNumParams() == 2 || - (MTy->isVarArg() && MTy->getNumParams() == 0)) && + assert((FTy->getNumParams() == 2 || + (FTy->isVarArg() && FTy->getNumParams() == 0)) && "Calling a function with bad signature"); - Operands.push_back(Use(Actual1, this)); - Operands.push_back(Use(Actual2, this)); } -void CallInst::init(Value *Func, Value *Actual) -{ - Operands.reserve(2); - Operands.push_back(Use(Func, this)); +void CallInst::init(Value *Func, Value *Actual) { + NumOperands = 2; + Use *OL = OperandList = new Use[2]; + OL[0].init(Func, this); + OL[1].init(Actual, this); - const FunctionType *MTy = + const FunctionType *FTy = cast(cast(Func->getType())->getElementType()); - assert((MTy->getNumParams() == 1 || - (MTy->isVarArg() && MTy->getNumParams() == 0)) && + assert((FTy->getNumParams() == 1 || + (FTy->isVarArg() && FTy->getNumParams() == 0)) && "Calling a function with bad signature"); - Operands.push_back(Use(Actual, this)); } -void CallInst::init(Value *Func) -{ - Operands.reserve(1); - Operands.push_back(Use(Func, this)); +void CallInst::init(Value *Func) { + NumOperands = 1; + Use *OL = OperandList = new Use[1]; + OL[0].init(Func, this); const FunctionType *MTy = cast(cast(Func->getType())->getElementType()); @@ -82,7 +186,7 @@ CallInst::CallInst(Value *Func, const std::vector &Params, const std::string &Name, Instruction *InsertBefore) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, Name, InsertBefore) { + Instruction::Call, 0, 0, Name, InsertBefore) { init(Func, Params); } @@ -90,7 +194,7 @@ CallInst::CallInst(Value *Func, const std::vector &Params, const std::string &Name, BasicBlock *InsertAtEnd) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, Name, InsertAtEnd) { + Instruction::Call, 0, 0, Name, InsertAtEnd) { init(Func, Params); } @@ -98,7 +202,7 @@ CallInst::CallInst(Value *Func, Value *Actual1, Value *Actual2, const std::string &Name, Instruction *InsertBefore) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, Name, InsertBefore) { + Instruction::Call, 0, 0, Name, InsertBefore) { init(Func, Actual1, Actual2); } @@ -106,7 +210,7 @@ CallInst::CallInst(Value *Func, Value *Actual1, Value *Actual2, const std::string &Name, BasicBlock *InsertAtEnd) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, Name, InsertAtEnd) { + Instruction::Call, 0, 0, Name, InsertAtEnd) { init(Func, Actual1, Actual2); } @@ -114,7 +218,7 @@ CallInst::CallInst(Value *Func, Value* Actual, const std::string &Name, Instruction *InsertBefore) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, Name, InsertBefore) { + Instruction::Call, 0, 0, Name, InsertBefore) { init(Func, Actual); } @@ -122,7 +226,7 @@ CallInst::CallInst(Value *Func, Value* Actual, const std::string &Name, BasicBlock *InsertAtEnd) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, Name, InsertAtEnd) { + Instruction::Call, 0, 0, Name, InsertAtEnd) { init(Func, Actual); } @@ -130,7 +234,7 @@ CallInst::CallInst(Value *Func, const std::string &Name, Instruction *InsertBefore) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, Name, InsertBefore) { + Instruction::Call, 0, 0, Name, InsertBefore) { init(Func); } @@ -138,15 +242,17 @@ CallInst::CallInst(Value *Func, const std::string &Name, BasicBlock *InsertAtEnd) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, Name, InsertAtEnd) { + Instruction::Call, 0, 0, Name, InsertAtEnd) { init(Func); } CallInst::CallInst(const CallInst &CI) - : Instruction(CI.getType(), Instruction::Call) { - Operands.reserve(CI.Operands.size()); - for (unsigned i = 0; i < CI.Operands.size(); ++i) - Operands.push_back(Use(CI.Operands[i], this)); + : Instruction(CI.getType(), Instruction::Call, new Use[CI.getNumOperands()], + CI.getNumOperands()) { + Use *OL = OperandList; + Use *InOL = CI.OperandList; + for (unsigned i = 0, e = CI.getNumOperands(); i != e; ++i) + OL[i].init(InOL[i], this); } @@ -154,22 +260,26 @@ CallInst::CallInst(const CallInst &CI) // InvokeInst Implementation //===----------------------------------------------------------------------===// +InvokeInst::~InvokeInst() { + delete [] OperandList; +} + void InvokeInst::init(Value *Fn, BasicBlock *IfNormal, BasicBlock *IfException, - const std::vector &Params) -{ - Operands.reserve(3+Params.size()); - Operands.push_back(Use(Fn, this)); - Operands.push_back(Use((Value*)IfNormal, this)); - Operands.push_back(Use((Value*)IfException, this)); - const FunctionType *MTy = + const std::vector &Params) { + NumOperands = 3+Params.size(); + Use *OL = OperandList = new Use[3+Params.size()]; + OL[0].init(Fn, this); + OL[1].init(IfNormal, this); + OL[2].init(IfException, this); + const FunctionType *FTy = cast(cast(Fn->getType())->getElementType()); - assert((Params.size() == MTy->getNumParams()) || - (MTy->isVarArg() && Params.size() > MTy->getNumParams()) && + assert((Params.size() == FTy->getNumParams()) || + (FTy->isVarArg() && Params.size() > FTy->getNumParams()) && "Calling a function with bad signature"); - for (unsigned i = 0; i < Params.size(); i++) - Operands.push_back(Use(Params[i], this)); + for (unsigned i = 0, e = Params.size(); i != e; i++) + OL[i+3].init(Params[i], this); } InvokeInst::InvokeInst(Value *Fn, BasicBlock *IfNormal, @@ -178,7 +288,7 @@ InvokeInst::InvokeInst(Value *Fn, BasicBlock *IfNormal, const std::string &Name, Instruction *InsertBefore) : TerminatorInst(cast(cast(Fn->getType()) ->getElementType())->getReturnType(), - Instruction::Invoke, Name, InsertBefore) { + Instruction::Invoke, 0, 0, Name, InsertBefore) { init(Fn, IfNormal, IfException, Params); } @@ -188,118 +298,159 @@ InvokeInst::InvokeInst(Value *Fn, BasicBlock *IfNormal, const std::string &Name, BasicBlock *InsertAtEnd) : TerminatorInst(cast(cast(Fn->getType()) ->getElementType())->getReturnType(), - Instruction::Invoke, Name, InsertAtEnd) { + Instruction::Invoke, 0, 0, Name, InsertAtEnd) { init(Fn, IfNormal, IfException, Params); } -InvokeInst::InvokeInst(const InvokeInst &CI) - : TerminatorInst(CI.getType(), Instruction::Invoke) { - Operands.reserve(CI.Operands.size()); - for (unsigned i = 0; i < CI.Operands.size(); ++i) - Operands.push_back(Use(CI.Operands[i], this)); +InvokeInst::InvokeInst(const InvokeInst &II) + : TerminatorInst(II.getType(), Instruction::Invoke, + new Use[II.getNumOperands()], II.getNumOperands()) { + Use *OL = OperandList, *InOL = II.OperandList; + for (unsigned i = 0, e = II.getNumOperands(); i != e; ++i) + OL[i].init(InOL[i], this); } +BasicBlock *InvokeInst::getSuccessorV(unsigned idx) const { + return getSuccessor(idx); +} +unsigned InvokeInst::getNumSuccessorsV() const { + return getNumSuccessors(); +} +void InvokeInst::setSuccessorV(unsigned idx, BasicBlock *B) { + return setSuccessor(idx, B); +} + + //===----------------------------------------------------------------------===// // ReturnInst Implementation //===----------------------------------------------------------------------===// -void ReturnInst::init(Value* RetVal) { - if (RetVal && RetVal->getType() != Type::VoidTy) { - assert(!isa(RetVal) && +void ReturnInst::init(Value *retVal) { + if (retVal && retVal->getType() != Type::VoidTy) { + assert(!isa(retVal) && "Cannot return basic block. Probably using the incorrect ctor"); - Operands.reserve(1); - Operands.push_back(Use(RetVal, this)); + NumOperands = 1; + RetVal.init(retVal, this); } } +unsigned ReturnInst::getNumSuccessorsV() const { + return getNumSuccessors(); +} + // Out-of-line ReturnInst method, put here so the C++ compiler can choose to // emit the vtable for the class in this translation unit. -void ReturnInst::setSuccessor(unsigned idx, BasicBlock *NewSucc) { +void ReturnInst::setSuccessorV(unsigned idx, BasicBlock *NewSucc) { assert(0 && "ReturnInst has no successors!"); } +BasicBlock *ReturnInst::getSuccessorV(unsigned idx) const { + assert(0 && "ReturnInst has no successors!"); + abort(); + return 0; +} + + //===----------------------------------------------------------------------===// // UnwindInst Implementation //===----------------------------------------------------------------------===// -// Likewise for UnwindInst -void UnwindInst::setSuccessor(unsigned idx, BasicBlock *NewSucc) { +unsigned UnwindInst::getNumSuccessorsV() const { + return getNumSuccessors(); +} + +void UnwindInst::setSuccessorV(unsigned idx, BasicBlock *NewSucc) { assert(0 && "UnwindInst has no successors!"); } +BasicBlock *UnwindInst::getSuccessorV(unsigned idx) const { + assert(0 && "UnwindInst has no successors!"); + abort(); + return 0; +} + //===----------------------------------------------------------------------===// // UnreachableInst Implementation //===----------------------------------------------------------------------===// -void UnreachableInst::setSuccessor(unsigned idx, BasicBlock *NewSucc) { - assert(0 && "UnreachableInst has no successors!"); +unsigned UnreachableInst::getNumSuccessorsV() const { + return getNumSuccessors(); +} + +void UnreachableInst::setSuccessorV(unsigned idx, BasicBlock *NewSucc) { + assert(0 && "UnwindInst has no successors!"); +} + +BasicBlock *UnreachableInst::getSuccessorV(unsigned idx) const { + assert(0 && "UnwindInst has no successors!"); + abort(); + return 0; } //===----------------------------------------------------------------------===// // BranchInst Implementation //===----------------------------------------------------------------------===// -void BranchInst::init(BasicBlock *IfTrue) -{ - assert(IfTrue != 0 && "Branch destination may not be null!"); - Operands.reserve(1); - Operands.push_back(Use(IfTrue, this)); +void BranchInst::AssertOK() { + if (isConditional()) + assert(getCondition()->getType() == Type::BoolTy && + "May only branch on boolean predicates!"); } -void BranchInst::init(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond) -{ - assert(IfTrue && IfFalse && Cond && - "Branch destinations and condition may not be null!"); - assert(Cond && Cond->getType() == Type::BoolTy && - "May only branch on boolean predicates!"); - Operands.reserve(3); - Operands.push_back(Use(IfTrue, this)); - Operands.push_back(Use(IfFalse, this)); - Operands.push_back(Use(Cond, this)); -} - -BranchInst::BranchInst(const BranchInst &BI) : TerminatorInst(Instruction::Br) { - Operands.reserve(BI.Operands.size()); - Operands.push_back(Use(BI.Operands[0], this)); - if (BI.Operands.size() != 1) { - assert(BI.Operands.size() == 3 && "BR can have 1 or 3 operands!"); - Operands.push_back(Use(BI.Operands[1], this)); - Operands.push_back(Use(BI.Operands[2], this)); +BranchInst::BranchInst(const BranchInst &BI) : + TerminatorInst(Instruction::Br, Ops, BI.getNumOperands()) { + OperandList[0].init(BI.getOperand(0), this); + if (BI.getNumOperands() != 1) { + assert(BI.getNumOperands() == 3 && "BR can have 1 or 3 operands!"); + OperandList[1].init(BI.getOperand(1), this); + OperandList[2].init(BI.getOperand(2), this); } } +BasicBlock *BranchInst::getSuccessorV(unsigned idx) const { + return getSuccessor(idx); +} +unsigned BranchInst::getNumSuccessorsV() const { + return getNumSuccessors(); +} +void BranchInst::setSuccessorV(unsigned idx, BasicBlock *B) { + setSuccessor(idx, B); +} + + //===----------------------------------------------------------------------===// // AllocationInst Implementation //===----------------------------------------------------------------------===// -void AllocationInst::init(const Type *Ty, Value *ArraySize, unsigned iTy) { - assert(Ty != Type::VoidTy && "Cannot allocate void elements!"); - // ArraySize defaults to 1. - if (!ArraySize) ArraySize = ConstantUInt::get(Type::UIntTy, 1); - - Operands.reserve(1); - assert(ArraySize->getType() == Type::UIntTy && - "Malloc/Allocation array size != UIntTy!"); - - Operands.push_back(Use(ArraySize, this)); +static Value *getAISize(Value *Amt) { + if (!Amt) + Amt = ConstantUInt::get(Type::UIntTy, 1); + else + assert(Amt->getType() == Type::UIntTy && + "Malloc/Allocation array size != UIntTy!"); + return Amt; } AllocationInst::AllocationInst(const Type *Ty, Value *ArraySize, unsigned iTy, const std::string &Name, Instruction *InsertBefore) - : Instruction(PointerType::get(Ty), iTy, Name, InsertBefore) { - init(Ty, ArraySize, iTy); + : UnaryInstruction(PointerType::get(Ty), iTy, getAISize(ArraySize), + Name, InsertBefore) { + assert(Ty != Type::VoidTy && "Cannot allocate void!"); } AllocationInst::AllocationInst(const Type *Ty, Value *ArraySize, unsigned iTy, const std::string &Name, BasicBlock *InsertAtEnd) - : Instruction(PointerType::get(Ty), iTy, Name, InsertAtEnd) { - init(Ty, ArraySize, iTy); + : UnaryInstruction(PointerType::get(Ty), iTy, getAISize(ArraySize), + Name, InsertAtEnd) { + assert(Ty != Type::VoidTy && "Cannot allocate void!"); } bool AllocationInst::isArrayAllocation() const { - return getOperand(0) != ConstantUInt::get(Type::UIntTy, 1); + if (ConstantUInt *CUI = dyn_cast(getOperand(0))) + return CUI->getValue() != 1; + return true; } const Type *AllocationInst::getAllocatedType() const { @@ -320,21 +471,19 @@ MallocInst::MallocInst(const MallocInst &MI) // FreeInst Implementation //===----------------------------------------------------------------------===// -void FreeInst::init(Value *Ptr) -{ - assert(Ptr && isa(Ptr->getType()) && "Can't free nonpointer!"); - Operands.reserve(1); - Operands.push_back(Use(Ptr, this)); +void FreeInst::AssertOK() { + assert(isa(getOperand(0)->getType()) && + "Can not free something of nonpointer type!"); } FreeInst::FreeInst(Value *Ptr, Instruction *InsertBefore) - : Instruction(Type::VoidTy, Free, "", InsertBefore) { - init(Ptr); + : UnaryInstruction(Type::VoidTy, Free, Ptr, "", InsertBefore) { + AssertOK(); } FreeInst::FreeInst(Value *Ptr, BasicBlock *InsertAtEnd) - : Instruction(Type::VoidTy, Free, "", InsertAtEnd) { - init(Ptr); + : UnaryInstruction(Type::VoidTy, Free, Ptr, "", InsertAtEnd) { + AssertOK(); } @@ -342,37 +491,35 @@ FreeInst::FreeInst(Value *Ptr, BasicBlock *InsertAtEnd) // LoadInst Implementation //===----------------------------------------------------------------------===// -void LoadInst::init(Value *Ptr) { - assert(Ptr && isa(Ptr->getType()) && +void LoadInst::AssertOK() { + assert(isa(getOperand(0)->getType()) && "Ptr must have pointer type."); - Operands.reserve(1); - Operands.push_back(Use(Ptr, this)); } LoadInst::LoadInst(Value *Ptr, const std::string &Name, Instruction *InsertBef) - : Instruction(cast(Ptr->getType())->getElementType(), - Load, Name, InsertBef), Volatile(false) { - init(Ptr); + : UnaryInstruction(cast(Ptr->getType())->getElementType(), + Load, Ptr, Name, InsertBef), Volatile(false) { + AssertOK(); } LoadInst::LoadInst(Value *Ptr, const std::string &Name, BasicBlock *InsertAE) - : Instruction(cast(Ptr->getType())->getElementType(), - Load, Name, InsertAE), Volatile(false) { - init(Ptr); + : UnaryInstruction(cast(Ptr->getType())->getElementType(), + Load, Ptr, Name, InsertAE), Volatile(false) { + AssertOK(); } LoadInst::LoadInst(Value *Ptr, const std::string &Name, bool isVolatile, Instruction *InsertBef) - : Instruction(cast(Ptr->getType())->getElementType(), - Load, Name, InsertBef), Volatile(isVolatile) { - init(Ptr); + : UnaryInstruction(cast(Ptr->getType())->getElementType(), + Load, Ptr, Name, InsertBef), Volatile(isVolatile) { + AssertOK(); } LoadInst::LoadInst(Value *Ptr, const std::string &Name, bool isVolatile, BasicBlock *InsertAE) - : Instruction(cast(Ptr->getType())->getElementType(), - Load, Name, InsertAE), Volatile(isVolatile) { - init(Ptr); + : UnaryInstruction(cast(Ptr->getType())->getElementType(), + Load, Ptr, Name, InsertAE), Volatile(isVolatile) { + AssertOK(); } @@ -380,36 +527,46 @@ LoadInst::LoadInst(Value *Ptr, const std::string &Name, bool isVolatile, // StoreInst Implementation //===----------------------------------------------------------------------===// -StoreInst::StoreInst(Value *Val, Value *Ptr, Instruction *InsertBefore) - : Instruction(Type::VoidTy, Store, "", InsertBefore), Volatile(false) { - init(Val, Ptr); -} - -StoreInst::StoreInst(Value *Val, Value *Ptr, BasicBlock *InsertAtEnd) - : Instruction(Type::VoidTy, Store, "", InsertAtEnd), Volatile(false) { - init(Val, Ptr); -} - -StoreInst::StoreInst(Value *Val, Value *Ptr, bool isVolatile, - Instruction *InsertBefore) - : Instruction(Type::VoidTy, Store, "", InsertBefore), Volatile(isVolatile) { - init(Val, Ptr); -} - -StoreInst::StoreInst(Value *Val, Value *Ptr, bool isVolatile, - BasicBlock *InsertAtEnd) - : Instruction(Type::VoidTy, Store, "", InsertAtEnd), Volatile(isVolatile) { - init(Val, Ptr); -} - -void StoreInst::init(Value *Val, Value *Ptr) { - assert(isa(Ptr->getType()) && "Ptr must have pointer type!"); - assert(Val->getType() == cast(Ptr->getType())->getElementType() +void StoreInst::AssertOK() { + assert(isa(getOperand(1)->getType()) && + "Ptr must have pointer type!"); + assert(getOperand(0)->getType() == + cast(getOperand(1)->getType())->getElementType() && "Ptr must be a pointer to Val type!"); +} - Operands.reserve(2); - Operands.push_back(Use(Val, this)); - Operands.push_back(Use(Ptr, this)); + +StoreInst::StoreInst(Value *val, Value *addr, Instruction *InsertBefore) + : Instruction(Type::VoidTy, Store, Ops, 2, "", InsertBefore), + Volatile(false) { + Ops[0].init(val, this); + Ops[1].init(addr, this); + AssertOK(); +} + +StoreInst::StoreInst(Value *val, Value *addr, BasicBlock *InsertAtEnd) + : Instruction(Type::VoidTy, Store, Ops, 2, "", InsertAtEnd), Volatile(false) { + Ops[0].init(val, this); + Ops[1].init(addr, this); + AssertOK(); +} + +StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, + Instruction *InsertBefore) + : Instruction(Type::VoidTy, Store, Ops, 2, "", InsertBefore), + Volatile(isVolatile) { + Ops[0].init(val, this); + Ops[1].init(addr, this); + AssertOK(); +} + +StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, + BasicBlock *InsertAtEnd) + : Instruction(Type::VoidTy, Store, Ops, 2, "", InsertAtEnd), + Volatile(isVolatile) { + Ops[0].init(val, this); + Ops[1].init(addr, this); + AssertOK(); } //===----------------------------------------------------------------------===// @@ -424,27 +581,28 @@ static inline const Type *checkType(const Type *Ty) { return Ty; } -void GetElementPtrInst::init(Value *Ptr, const std::vector &Idx) -{ - Operands.reserve(1+Idx.size()); - Operands.push_back(Use(Ptr, this)); +void GetElementPtrInst::init(Value *Ptr, const std::vector &Idx) { + NumOperands = 1+Idx.size(); + Use *OL = OperandList = new Use[NumOperands]; + OL[0].init(Ptr, this); - for (unsigned i = 0, E = Idx.size(); i != E; ++i) - Operands.push_back(Use(Idx[i], this)); + for (unsigned i = 0, e = Idx.size(); i != e; ++i) + OL[i+1].init(Idx[i], this); } void GetElementPtrInst::init(Value *Ptr, Value *Idx0, Value *Idx1) { - Operands.reserve(3); - Operands.push_back(Use(Ptr, this)); - Operands.push_back(Use(Idx0, this)); - Operands.push_back(Use(Idx1, this)); + NumOperands = 3; + Use *OL = OperandList = new Use[3]; + OL[0].init(Ptr, this); + OL[1].init(Idx0, this); + OL[2].init(Idx1, this); } GetElementPtrInst::GetElementPtrInst(Value *Ptr, const std::vector &Idx, const std::string &Name, Instruction *InBe) : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(), Idx, true))), - GetElementPtr, Name, InBe) { + GetElementPtr, 0, 0, Name, InBe) { init(Ptr, Idx); } @@ -452,7 +610,7 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, const std::vector &Idx, const std::string &Name, BasicBlock *IAE) : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(), Idx, true))), - GetElementPtr, Name, IAE) { + GetElementPtr, 0, 0, Name, IAE) { init(Ptr, Idx); } @@ -460,7 +618,7 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, Value *Idx0, Value *Idx1, const std::string &Name, Instruction *InBe) : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(), Idx0, Idx1, true))), - GetElementPtr, Name, InBe) { + GetElementPtr, 0, 0, Name, InBe) { init(Ptr, Idx0, Idx1); } @@ -468,10 +626,14 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, Value *Idx0, Value *Idx1, const std::string &Name, BasicBlock *IAE) : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(), Idx0, Idx1, true))), - GetElementPtr, Name, IAE) { + GetElementPtr, 0, 0, Name, IAE) { init(Ptr, Idx0, Idx1); } +GetElementPtrInst::~GetElementPtrInst() { + delete[] OperandList; +} + // getIndexedType - Returns the type of the element that would be loaded with // a load instruction with the specified parameters. // @@ -537,19 +699,17 @@ const Type* GetElementPtrInst::getIndexedType(const Type *Ptr, // BinaryOperator Class //===----------------------------------------------------------------------===// -void BinaryOperator::init(BinaryOps iType, Value *S1, Value *S2) +void BinaryOperator::init(BinaryOps iType) { - Operands.reserve(2); - Operands.push_back(Use(S1, this)); - Operands.push_back(Use(S2, this)); - assert(S1 && S2 && S1->getType() == S2->getType()); - + Value *LHS = getOperand(0), *RHS = getOperand(1); + assert(LHS->getType() == RHS->getType() && + "Binary operator operand types must match!"); #ifndef NDEBUG switch (iType) { case Add: case Sub: case Mul: case Div: case Rem: - assert(getType() == S1->getType() && + assert(getType() == LHS->getType() && "Arithmetic operation should return same type as operands!"); assert((getType()->isInteger() || getType()->isFloatingPoint() || @@ -558,7 +718,7 @@ void BinaryOperator::init(BinaryOps iType, Value *S1, Value *S2) break; case And: case Or: case Xor: - assert(getType() == S1->getType() && + assert(getType() == LHS->getType() && "Logical operation should return same type as operands!"); assert(getType()->isIntegral() && "Tried to create a logical operation on a non-integral type!"); @@ -696,7 +856,7 @@ bool BinaryOperator::swapOperands() { else return true; // Can't commute operands - std::swap(Operands[0], Operands[1]); + std::swap(Ops[0], Ops[1]); return false; } @@ -756,28 +916,41 @@ Instruction::BinaryOps SetCondInst::getSwappedCondition(BinaryOps Opcode) { // SwitchInst Implementation //===----------------------------------------------------------------------===// -void SwitchInst::init(Value *Value, BasicBlock *Default) -{ +void SwitchInst::init(Value *Value, BasicBlock *Default, unsigned NumCases) { assert(Value && Default); - Operands.push_back(Use(Value, this)); - Operands.push_back(Use(Default, this)); + ReservedSpace = 2+NumCases*2; + NumOperands = 2; + OperandList = new Use[ReservedSpace]; + + OperandList[0].init(Value, this); + OperandList[1].init(Default, this); } SwitchInst::SwitchInst(const SwitchInst &SI) - : TerminatorInst(Instruction::Switch) { - Operands.reserve(SI.Operands.size()); - - for (unsigned i = 0, E = SI.Operands.size(); i != E; i+=2) { - Operands.push_back(Use(SI.Operands[i], this)); - Operands.push_back(Use(SI.Operands[i+1], this)); + : TerminatorInst(Instruction::Switch, new Use[SI.getNumOperands()], + SI.getNumOperands()) { + Use *OL = OperandList, *InOL = SI.OperandList; + for (unsigned i = 0, E = SI.getNumOperands(); i != E; i+=2) { + OL[i].init(InOL[i], this); + OL[i+1].init(InOL[i+1], this); } } +SwitchInst::~SwitchInst() { + delete [] OperandList; +} + + /// addCase - Add an entry to the switch instruction... /// void SwitchInst::addCase(Constant *OnVal, BasicBlock *Dest) { - Operands.push_back(Use((Value*)OnVal, this)); - Operands.push_back(Use((Value*)Dest, this)); + unsigned OpNo = NumOperands; + if (OpNo+2 > ReservedSpace) + resizeOperands(0); // Get more space! + // Initialize some new operands. + NumOperands = OpNo+2; + OperandList[OpNo].init(OnVal, this); + OperandList[OpNo+1].init(Dest, this); } /// removeCase - This method removes the specified successor from the switch @@ -786,8 +959,66 @@ void SwitchInst::addCase(Constant *OnVal, BasicBlock *Dest) { /// void SwitchInst::removeCase(unsigned idx) { assert(idx != 0 && "Cannot remove the default case!"); - assert(idx*2 < Operands.size() && "Successor index out of range!!!"); - Operands.erase(Operands.begin()+idx*2, Operands.begin()+(idx+1)*2); + assert(idx*2 < getNumOperands() && "Successor index out of range!!!"); + + unsigned NumOps = getNumOperands(); + Use *OL = OperandList; + + // Move everything after this operand down. + // + // FIXME: we could just swap with the end of the list, then erase. However, + // client might not expect this to happen. The code as it is thrashes the + // use/def lists, which is kinda lame. + for (unsigned i = (idx+1)*2; i != NumOps; i += 2) { + OL[i-2] = OL[i]; + OL[i-2+1] = OL[i+1]; + } + + // Nuke the last value. + OL[NumOps-2].set(0); + OL[NumOps-2+1].set(0); + NumOperands = NumOps-2; +} + +/// resizeOperands - resize operands - This adjusts the length of the operands +/// list according to the following behavior: +/// 1. If NumOps == 0, grow the operand list in response to a push_back style +/// of operation. This grows the number of ops by 1.5 times. +/// 2. If NumOps > NumOperands, reserve space for NumOps operands. +/// 3. If NumOps == NumOperands, trim the reserved space. +/// +void SwitchInst::resizeOperands(unsigned NumOps) { + if (NumOps == 0) { + NumOps = (getNumOperands())*3/2; + } else if (NumOps*2 > NumOperands) { + // No resize needed. + if (ReservedSpace >= NumOps) return; + } else if (NumOps == NumOperands) { + if (ReservedSpace == NumOps) return; + } else { + return; + } + + ReservedSpace = NumOps; + Use *NewOps = new Use[NumOps]; + Use *OldOps = OperandList; + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + NewOps[i].init(OldOps[i], this); + OldOps[i].set(0); + } + delete [] OldOps; + OperandList = NewOps; +} + + +BasicBlock *SwitchInst::getSuccessorV(unsigned idx) const { + return getSuccessor(idx); +} +unsigned SwitchInst::getNumSuccessorsV() const { + return getNumSuccessors(); +} +void SwitchInst::setSuccessorV(unsigned idx, BasicBlock *B) { + setSuccessor(idx, B); } @@ -799,12 +1030,12 @@ GetElementPtrInst *GetElementPtrInst::clone() const { } BinaryOperator *BinaryOperator::clone() const { - return create(getOpcode(), Operands[0], Operands[1]); + return create(getOpcode(), Ops[0], Ops[1]); } MallocInst *MallocInst::clone() const { return new MallocInst(*this); } AllocaInst *AllocaInst::clone() const { return new AllocaInst(*this); } -FreeInst *FreeInst::clone() const { return new FreeInst(Operands[0]); } +FreeInst *FreeInst::clone() const { return new FreeInst(getOperand(0)); } LoadInst *LoadInst::clone() const { return new LoadInst(*this); } StoreInst *StoreInst::clone() const { return new StoreInst(*this); } CastInst *CastInst::clone() const { return new CastInst(*this); }