diff options
-rw-r--r-- | CREDITS.TXT | 4 | ||||
-rw-r--r-- | include/llvm/Constants.h | 42 | ||||
-rw-r--r-- | include/llvm/GlobalAlias.h | 15 | ||||
-rw-r--r-- | include/llvm/GlobalVariable.h | 35 | ||||
-rw-r--r-- | include/llvm/InstrTypes.h | 71 | ||||
-rw-r--r-- | include/llvm/Instruction.h | 1 | ||||
-rw-r--r-- | include/llvm/Instructions.h | 591 | ||||
-rw-r--r-- | include/llvm/OperandTraits.h | 163 | ||||
-rw-r--r-- | include/llvm/Use.h | 81 | ||||
-rw-r--r-- | include/llvm/User.h | 242 | ||||
-rw-r--r-- | include/llvm/Value.h | 7 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.cpp | 51 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.h | 50 | ||||
-rw-r--r-- | lib/VMCore/ConstantFold.cpp | 16 | ||||
-rw-r--r-- | lib/VMCore/Constants.cpp | 182 | ||||
-rw-r--r-- | lib/VMCore/Globals.cpp | 18 | ||||
-rw-r--r-- | lib/VMCore/Instructions.cpp | 412 | ||||
-rw-r--r-- | lib/VMCore/Use.cpp | 131 |
18 files changed, 1528 insertions, 584 deletions
diff --git a/CREDITS.TXT b/CREDITS.TXT index 84f7e5ad16..83d1cd39ff 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -110,6 +110,10 @@ E: greened@obbligato.org D: Miscellaneous bug fixes D: Register allocation refactoring +N: Gabor Greif +E: ggreif@gmail.com +D: Improvements for space efficiency + N: Gordon Henriksen E: gordonhenriksen@mac.com D: Pluggable GC support diff --git a/include/llvm/Constants.h b/include/llvm/Constants.h index c69a381a69..a55c19a86b 100644 --- a/include/llvm/Constants.h +++ b/include/llvm/Constants.h @@ -22,6 +22,7 @@ #include "llvm/Constant.h" #include "llvm/Type.h" +#include "llvm/OperandTraits.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APFloat.h" @@ -318,7 +319,6 @@ class ConstantArray : public Constant { ConstantArray(const ConstantArray &); // DO NOT IMPLEMENT protected: ConstantArray(const ArrayType *T, const std::vector<Constant*> &Val); - ~ConstantArray(); public: /// get() - Static factory methods - Return objects of the specified value static Constant *get(const ArrayType *T, const std::vector<Constant*> &); @@ -336,6 +336,9 @@ public: /// null termination. static Constant *get(const std::string &Initializer, bool AddNull = true); + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + /// getType - Specialize the getType() method to always return an ArrayType, /// which reduces the amount of casting needed in parts of the compiler. /// @@ -374,6 +377,11 @@ public: } }; +template <> +struct OperandTraits<ConstantArray> : VariadicOperandTraits<> { +}; + +DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantArray, Constant) //===----------------------------------------------------------------------===// // ConstantStruct - Constant Struct Declarations @@ -384,7 +392,6 @@ class ConstantStruct : public Constant { ConstantStruct(const ConstantStruct &); // DO NOT IMPLEMENT protected: ConstantStruct(const StructType *T, const std::vector<Constant*> &Val); - ~ConstantStruct(); public: /// get() - Static factory methods - Return objects of the specified value /// @@ -396,6 +403,9 @@ public: return get(std::vector<Constant*>(Vals, Vals+NumVals), Packed); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + /// getType() specialization - Reduce amount of casting... /// inline const StructType *getType() const { @@ -419,6 +429,12 @@ public: } }; +template <> +struct OperandTraits<ConstantStruct> : VariadicOperandTraits<> { +}; + +DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantStruct, Constant) + //===----------------------------------------------------------------------===// /// ConstantVector - Constant Vector Declarations /// @@ -428,7 +444,6 @@ class ConstantVector : public Constant { ConstantVector(const ConstantVector &); // DO NOT IMPLEMENT protected: ConstantVector(const VectorType *T, const std::vector<Constant*> &Val); - ~ConstantVector(); public: /// get() - Static factory methods - Return objects of the specified value static Constant *get(const VectorType *T, const std::vector<Constant*> &); @@ -438,6 +453,9 @@ public: return get(std::vector<Constant*>(Vals, Vals+NumVals)); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + /// getType - Specialize the getType() method to always return a VectorType, /// which reduces the amount of casting needed in parts of the compiler. /// @@ -475,6 +493,12 @@ public: } }; +template <> +struct OperandTraits<ConstantVector> : VariadicOperandTraits<> { +}; + +DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantVector, Constant) + //===----------------------------------------------------------------------===// /// ConstantPointerNull - a constant pointer value that points to null /// @@ -573,6 +597,9 @@ public: static Constant *getIntToPtr(Constant *C, const Type *Ty); static Constant *getBitCast (Constant *C, const Type *Ty); + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + // @brief Convenience function for getting one of the casting operations // using a CastOps opcode. static Constant *getCast( @@ -709,13 +736,13 @@ public: virtual void destroyConstant(); virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U); - /// Override methods to provide more type information... +/* /// Override methods to provide more type information... inline Constant *getOperand(unsigned i) { return cast<Constant>(User::getOperand(i)); } inline Constant *getOperand(unsigned i) const { return const_cast<Constant*>(cast<Constant>(User::getOperand(i))); - } + }*/ /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -725,6 +752,11 @@ public: } }; +template <> +struct OperandTraits<ConstantExpr> : VariadicOperandTraits<1> { +}; + +DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantExpr, Constant) //===----------------------------------------------------------------------===// /// UndefValue - 'undef' values are things that do not have specified contents. diff --git a/include/llvm/GlobalAlias.h b/include/llvm/GlobalAlias.h index b59537c9af..7c147eb62a 100644 --- a/include/llvm/GlobalAlias.h +++ b/include/llvm/GlobalAlias.h @@ -16,6 +16,7 @@ #define LLVM_GLOBAL_ALIAS_H #include "llvm/GlobalValue.h" +#include "llvm/OperandTraits.h" namespace llvm { @@ -42,17 +43,19 @@ class GlobalAlias : public GlobalValue { GlobalAlias *getPrev() { return Prev; } const GlobalAlias *getPrev() const { return Prev; } - Use Aliasee; public: - // allocate space for exactly zero operands + // allocate space for exactly one operand void *operator new(size_t s) { - return User::operator new(s, 0); + return User::operator new(s, 1); } /// GlobalAlias ctor - If a parent module is specified, the alias is /// automatically inserted into the end of the specified module's alias list. GlobalAlias(const Type *Ty, LinkageTypes Linkage, const std::string &Name = "", Constant* Aliasee = 0, Module *Parent = 0); + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + /// isDeclaration - Is this global variable lacking an initializer? If so, /// the global variable is defined in some other translation unit, and is thus /// only a declaration here. @@ -95,6 +98,12 @@ public: } }; +template <> +struct OperandTraits<GlobalAlias> : FixedNumOperandTraits<1> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalAlias, Value) + } // End llvm namespace #endif diff --git a/include/llvm/GlobalVariable.h b/include/llvm/GlobalVariable.h index 8c6d8030c6..5a42e78a4a 100644 --- a/include/llvm/GlobalVariable.h +++ b/include/llvm/GlobalVariable.h @@ -21,6 +21,7 @@ #define LLVM_GLOBAL_VARIABLE_H #include "llvm/GlobalValue.h" +#include "llvm/OperandTraits.h" namespace llvm { @@ -44,26 +45,32 @@ class GlobalVariable : public GlobalValue { bool isConstantGlobal : 1; // Is this a global constant? bool isThreadLocalSymbol : 1; // Is this symbol "Thread Local"? - Use Initializer; public: - // allocate space for exactly zero operands + // allocate space for exactly one operand void *operator new(size_t s) { - return User::operator new(s, 0); + return User::operator new(s, 1); } /// GlobalVariable ctor - If a parent module is specified, the global is /// automatically inserted into the end of the specified modules global list. GlobalVariable(const Type *Ty, bool isConstant, LinkageTypes Linkage, Constant *Initializer = 0, const std::string &Name = "", - Module *Parent = 0, bool ThreadLocal = false, + Module *Parent = 0, bool ThreadLocal = false, unsigned AddressSpace = 0); /// GlobalVariable ctor - This creates a global and inserts it before the /// specified other global. GlobalVariable(const Type *Ty, bool isConstant, LinkageTypes Linkage, Constant *Initializer, const std::string &Name, - GlobalVariable *InsertBefore, bool ThreadLocal = false, + GlobalVariable *InsertBefore, bool ThreadLocal = false, unsigned AddressSpace = 0); - + + ~GlobalVariable() { + NumOperands = 1; // FIXME: needed by operator delete + } + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + /// isDeclaration - Is this global variable lacking an initializer? If so, /// the global variable is defined in some other translation unit, and is thus /// only a declaration here. @@ -79,24 +86,24 @@ public: /// illegal to call this method if the global is external, because we cannot /// tell what the value is initialized to! /// - inline Constant *getInitializer() const { + inline /*const FIXME*/ Constant *getInitializer() const { assert(hasInitializer() && "GV doesn't have initializer!"); - return reinterpret_cast<Constant*>(Initializer.get()); + return static_cast<Constant*>(Op<0>().get()); } inline Constant *getInitializer() { assert(hasInitializer() && "GV doesn't have initializer!"); - return reinterpret_cast<Constant*>(Initializer.get()); + return static_cast<Constant*>(Op<0>().get()); } inline void setInitializer(Constant *CPV) { if (CPV == 0) { if (hasInitializer()) { - Initializer.set(0); + Op<0>().set(0); NumOperands = 0; } } else { if (!hasInitializer()) NumOperands = 1; - Initializer.set(CPV); + Op<0>().set(CPV); } } @@ -141,6 +148,12 @@ private: const GlobalVariable *getPrev() const { return Prev; } }; +template <> +struct OperandTraits<GlobalVariable> : OptionalOperandTraits<> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalVariable, Value) + } // End llvm namespace #endif diff --git a/include/llvm/InstrTypes.h b/include/llvm/InstrTypes.h index f735602ca8..a68b562212 100644 --- a/include/llvm/InstrTypes.h +++ b/include/llvm/InstrTypes.h @@ -17,6 +17,7 @@ #define LLVM_INSTRUCTION_TYPES_H #include "llvm/Instruction.h" +#include "llvm/OperandTraits.h" namespace llvm { @@ -78,22 +79,22 @@ public: } }; + //===----------------------------------------------------------------------===// // UnaryInstruction Class //===----------------------------------------------------------------------===// class UnaryInstruction : public Instruction { void *operator new(size_t, unsigned); // Do not implement - Use Op; - // avoiding warning: 'this' : used in base member initializer list - UnaryInstruction* this_() { return this; } protected: - UnaryInstruction(const Type *Ty, unsigned iType, Value *V, Instruction *IB =0) - : Instruction(Ty, iType, &Op, 1, IB), Op(V, this_()) { + UnaryInstruction(const Type *Ty, unsigned iType, Value *V, Instruction *IB = 0) + : Instruction(Ty, iType, &Op<0>(), 1, IB) { + Op<0>() = V; } UnaryInstruction(const Type *Ty, unsigned iType, Value *V, BasicBlock *IAE) - : Instruction(Ty, iType, &Op, 1, IAE), Op(V, this_()) { + : Instruction(Ty, iType, &Op<0>(), 1, IAE) { + Op<0>() = V; } public: // allocate space for exactly one operand @@ -104,16 +105,8 @@ public: // Out of line virtual method, so the vtable, etc has a home. ~UnaryInstruction(); - // Transparently provide more efficient getOperand methods. - Value *getOperand(unsigned i) const { - assert(i == 0 && "getOperand() out of range!"); - return Op; - } - void setOperand(unsigned i, Value *Val) { - assert(i == 0 && "setOperand() out of range!"); - Op = Val; - } - unsigned getNumOperands() const { return 1; } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const UnaryInstruction *) { return true; } @@ -130,13 +123,18 @@ public: } }; +template <> +struct OperandTraits<UnaryInstruction> : FixedNumOperandTraits<1> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(UnaryInstruction, Value) + //===----------------------------------------------------------------------===// // BinaryOperator Class //===----------------------------------------------------------------------===// class BinaryOperator : public Instruction { void *operator new(size_t, unsigned); // Do not implement - Use Ops[2]; protected: void init(BinaryOps iType); BinaryOperator(BinaryOps iType, Value *S1, Value *S2, const Type *Ty, @@ -150,15 +148,7 @@ public: } /// Transparently provide more efficient getOperand methods. - Value *getOperand(unsigned i) const { - assert(i < 2 && "getOperand() out of range!"); - return Ops[i]; - } - void setOperand(unsigned i, Value *Val) { - assert(i < 2 && "setOperand() out of range!"); - Ops[i] = Val; - } - unsigned getNumOperands() const { return 2; } + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// create() - Construct a binary instruction, given the opcode and the two /// operands. Optionally (if InstBefore is specified) insert the instruction @@ -251,6 +241,12 @@ public: } }; +template <> +struct OperandTraits<BinaryOperator> : FixedNumOperandTraits<2> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryOperator, Value) + //===----------------------------------------------------------------------===// // CastInst Class //===----------------------------------------------------------------------===// @@ -497,6 +493,7 @@ public: /// This class is the base class for the comparison instructions. /// @brief Abstract base class of comparison instructions. +// FIXME: why not derive from BinaryOperator? class CmpInst: public Instruction { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT CmpInst(); // do not implement @@ -507,8 +504,6 @@ protected: CmpInst(Instruction::OtherOps op, unsigned short pred, Value *LHS, Value *RHS, const std::string &Name, BasicBlock *InsertAtEnd); - Use Ops[2]; // CmpInst instructions always have 2 operands, optimize - public: // allocate space for exactly two operands void *operator new(size_t s) { @@ -548,17 +543,7 @@ public: } /// @brief Provide more efficient getOperand methods. - Value *getOperand(unsigned i) const { - assert(i < 2 && "getOperand() out of range!"); - return Ops[i]; - } - void setOperand(unsigned i, Value *Val) { - assert(i < 2 && "setOperand() out of range!"); - Ops[i] = Val; - } - - /// @brief CmpInst instructions always have 2 operands. - unsigned getNumOperands() const { return 2; } + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// This is just a convenience that dispatches to the subclasses. /// @brief Swap the operands and adjust predicate accordingly to retain @@ -598,6 +583,14 @@ public: } }; + +// FIXME: these are redundant if CmpInst < BinaryOperator +template <> +struct OperandTraits<CmpInst> : FixedNumOperandTraits<2> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CmpInst, Value) + } // End llvm namespace #endif diff --git a/include/llvm/Instruction.h b/include/llvm/Instruction.h index 29ae5c3cfb..40d83059fe 100644 --- a/include/llvm/Instruction.h +++ b/include/llvm/Instruction.h @@ -20,7 +20,6 @@ namespace llvm { struct AssemblyAnnotationWriter; -class BinaryOperator; template<typename ValueSubClass, typename ItemParentClass> class SymbolTableListTraits; diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index f292a3173f..86bc3f5793 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -21,10 +21,10 @@ #include "llvm/InstrTypes.h" #include "llvm/DerivedTypes.h" #include "llvm/ParameterAttributes.h" +#include "llvm/BasicBlock.h" namespace llvm { -class BasicBlock; class ConstantInt; class PointerType; class VectorType; @@ -288,11 +288,11 @@ public: /// class StoreInst : public Instruction { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - Use Ops[2]; - StoreInst(const StoreInst &SI) : Instruction(SI.getType(), Store, Ops, 2) { - Ops[0].init(SI.Ops[0], this); - Ops[1].init(SI.Ops[1], this); + StoreInst(const StoreInst &SI) : Instruction(SI.getType(), Store, + &Op<0>(), 2) { + Op<0>().init(SI.Op<0>(), this); + Op<1>().init(SI.Op<1>(), this); setVolatile(SI.isVolatile()); setAlignment(SI.getAlignment()); @@ -329,15 +329,7 @@ public: } /// Transparently provide more efficient getOperand methods. - Value *getOperand(unsigned i) const { - assert(i < 2 && "getOperand() out of range!"); - return Ops[i]; - } - void setOperand(unsigned i, Value *Val) { - assert(i < 2 && "setOperand() out of range!"); - Ops[i] = Val; - } - unsigned getNumOperands() const { return 2; } + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// getAlignment - Return the alignment of the access that is being performed /// @@ -363,6 +355,11 @@ public: } }; +template <> +struct OperandTraits<StoreInst> : FixedNumOperandTraits<2> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(StoreInst, Value) //===----------------------------------------------------------------------===// // GetElementPtrInst Class @@ -380,14 +377,7 @@ static inline const Type *checkType(const Type *Ty) { /// access elements of arrays and structs /// class GetElementPtrInst : public Instruction { - GetElementPtrInst(const GetElementPtrInst &GEPI) - : Instruction(reinterpret_cast<const Type*>(GEPI.getType()), GetElementPtr, - 0, GEPI.getNumOperands()) { - Use *OL = OperandList = new Use[NumOperands]; - Use *GEPIOL = GEPI.OperandList; - for (unsigned i = 0, E = NumOperands; i != E; ++i) - OL[i].init(GEPIOL[i], this); - } + GetElementPtrInst(const GetElementPtrInst &GEPI); void init(Value *Ptr, Value* const *Idx, unsigned NumIdx); void init(Value *Ptr, Value *Idx); @@ -400,8 +390,9 @@ class GetElementPtrInst : public Instruction { unsigned NumIdx = static_cast<unsigned>(std::distance(IdxBegin, IdxEnd)); if (NumIdx > 0) { - // This requires that the itoerator points to contiguous memory. - init(Ptr, &*IdxBegin, NumIdx); + // This requires that the iterator points to contiguous memory. + init(Ptr, &*IdxBegin, NumIdx); // FIXME: for the general case + // we have to build an array here } else { init(Ptr, 0, NumIdx); @@ -446,34 +437,21 @@ class GetElementPtrInst : public Instruction { /// instruction, the second appends the new instruction to the specified /// BasicBlock. template<typename InputIterator> - GetElementPtrInst(Value *Ptr, InputIterator IdxBegin, - InputIterator IdxEnd, - const std::string &Name = "", - Instruction *InsertBefore = 0) - : Instruction(PointerType::get( - checkType(getIndexedType(Ptr->getType(), - IdxBegin, IdxEnd, true)), - cast<PointerType>(Ptr->getType())->getAddressSpace()), - GetElementPtr, 0, 0, InsertBefore) { - init(Ptr, IdxBegin, IdxEnd, Name, - typename std::iterator_traits<InputIterator>::iterator_category()); - } + inline GetElementPtrInst(Value *Ptr, InputIterator IdxBegin, + InputIterator IdxEnd, + unsigned Values, + const std::string &Name, + Instruction *InsertBefore); template<typename InputIterator> - GetElementPtrInst(Value *Ptr, InputIterator IdxBegin, InputIterator IdxEnd, - const std::string &Name, BasicBlock *InsertAtEnd) - : Instruction(PointerType::get( - checkType(getIndexedType(Ptr->getType(), - IdxBegin, IdxEnd, true)), - cast<PointerType>(Ptr->getType())->getAddressSpace()), - GetElementPtr, 0, 0, InsertAtEnd) { - init(Ptr, IdxBegin, IdxEnd, Name, - typename std::iterator_traits<InputIterator>::iterator_category()); - } + inline GetElementPtrInst(Value *Ptr, + InputIterator IdxBegin, InputIterator IdxEnd, + unsigned Values, + const std::string &Name, BasicBlock *InsertAtEnd); /// Constructors - These two constructors are convenience methods because one /// and two index getelementptr instructions are so common. - GetElementPtrInst(Value *Ptr, Value *Idx, - const std::string &Name = "", Instruction *InsertBefore = 0); + GetElementPtrInst(Value *Ptr, Value *Idx, const std::string &Name = "", + Instruction *InsertBefore = 0); GetElementPtrInst(Value *Ptr, Value *Idx, const std::string &Name, BasicBlock *InsertAtEnd); public: @@ -482,28 +460,40 @@ public: InputIterator IdxEnd, const std::string &Name = "", Instruction *InsertBefore = 0) { - return new(0/*FIXME*/) GetElementPtrInst(Ptr, IdxBegin, IdxEnd, Name, InsertBefore); + typename std::iterator_traits<InputIterator>::difference_type Values = + 1 + std::distance(IdxBegin, IdxEnd); + return new(Values) + GetElementPtrInst(Ptr, IdxBegin, IdxEnd, Values, Name, InsertBefore); } template<typename InputIterator> - static GetElementPtrInst *Create(Value *Ptr, InputIterator IdxBegin, InputIterator IdxEnd, - const std::string &Name, BasicBlock *InsertAtEnd) { - return new(0/*FIXME*/) GetElementPtrInst(Ptr, IdxBegin, IdxEnd, Name, InsertAtEnd); + static GetElementPtrInst *Create(Value *Ptr, + InputIterator IdxBegin, InputIterator IdxEnd, + const std::string &Name, + BasicBlock *InsertAtEnd) { + typename std::iterator_traits<InputIterator>::difference_type Values = + 1 + std::distance(IdxBegin, IdxEnd); + return new(Values) + GetElementPtrInst(Ptr, IdxBegin, IdxEnd, Values, Name, InsertAtEnd); } - /// Constructors - These two constructors are convenience methods because one - /// and two index getelementptr instructions are so common. + /// Constructors - These two creators are convenience methods because one + /// index getelementptr instructions are so common. static GetElementPtrInst *Create(Value *Ptr, Value *Idx, - const std::string &Name = "", Instruction *InsertBefore = 0) { - return new(2/*FIXME*/) GetElementPtrInst(Ptr, Idx, Name, InsertBefore); + const std::string &Name = "", + Instruction *InsertBefore = 0) { + return new(2) GetElementPtrInst(Ptr, Idx, Name, InsertBefore); } static GetElementPtrInst *Create(Value *Ptr, Value *Idx, - const std::string &Name, BasicBlock *InsertAtEnd) { - return new(2/*FIXME*/) GetElementPtrInst(Ptr, Idx, Name, InsertAtEnd); + const std::string &Name, + BasicBlock *InsertAtEnd) { + return new(2) GetElementPtrInst(Ptr, Idx, Name, InsertAtEnd); } - ~GetElementPtrInst(); virtual GetElementPtrInst *clone() const; + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + // getType - Overload to return most specific pointer type... const PointerType *getType() const { return reinterpret_cast<const PointerType*>(Instruction::getType()); @@ -570,6 +560,51 @@ public: } }; +template <> +struct OperandTraits<GetElementPtrInst> : VariadicOperandTraits<1> { +}; + +template<typename InputIterator> +GetElementPtrInst::GetElementPtrInst(Value *Ptr, + InputIterator IdxBegin, + InputIterator IdxEnd, + unsigned Values, + const std::string &Name, + Instruction *InsertBefore) + : Instruction(PointerType::get(checkType( + getIndexedType(Ptr->getType(), + IdxBegin, IdxEnd, true)), + cast<PointerType>(Ptr->getType()) + ->getAddressSpace()), + GetElementPtr, + OperandTraits<GetElementPtrInst>::op_end(this) - Values, + Values, InsertBefore) { + init(Ptr, IdxBegin, IdxEnd, Name, + typename std::iterator_traits<InputIterator>::iterator_category()); +} +template<typename InputIterator> +GetElementPtrInst::GetElementPtrInst(Value *Ptr, + InputIterator IdxBegin, + InputIterator IdxEnd, + unsigned Values, + const std::string &Name, + BasicBlock *InsertAtEnd) + : Instruction(PointerType::get(checkType( + getIndexedType(Ptr->getType(), + IdxBegin, IdxEnd, true)), + cast<PointerType>(Ptr->getType()) + ->getAddressSpace()), + GetElementPtr, + OperandTraits<GetElementPtrInst>::op_end(this) - Values, + Values, InsertAtEnd) { + init(Ptr, IdxBegin, IdxEnd, Name, + typename std::iterator_traits<InputIterator>::iterator_category()); +} + + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrInst, Value) + + //===----------------------------------------------------------------------===// // ICmpInst Class //===----------------------------------------------------------------------===// @@ -723,7 +758,7 @@ public: /// @brief Swap operands and adjust predicate. void swapOperands() { SubclassData = getSwappedPredicate(); - std::swap(Ops[0], Ops[1]); + std::swap(Op<0>(), Op<1>()); } virtual ICmpInst *clone() const; @@ -847,7 +882,7 @@ public: /// @brief Swap operands and adjust predicate. void swapOperands() { SubclassData = getSwappedPredicate(); - std::swap(Ops[0], Ops[1]); + std::swap(Op<0>(), Op<1>()); } virtual FCmpInst *clone() const; @@ -900,13 +935,7 @@ class CallInst : public Instruction { /// @brief Construct a CallInst from a range of arguments template<typename InputIterator> CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, - const std::string &Name = "", Instruction *InsertBefore = 0) - : Instruction(cast<FunctionType>(cast<PointerType>(Func->getType()) - ->getElementType())->getReturnType(), - Instruction::Call, 0, 0, InsertBefore) { - init(Func, ArgBegin, ArgEnd, Name, - typename std::iterator_traits<InputIterator>::iterator_category()); - } + const std::string &Name, Instruction *InsertBefore); /// Construct a CallInst given a range of arguments. InputIterator /// must be a random-access iterator pointing to contiguous storage @@ -915,35 +944,29 @@ class CallInst : public Instruction { /// incur runtime overhead. /// @brief Construct a CallInst from a range of arguments template<typename InputIterator> - CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, - const std::string &Name, BasicBlock *InsertAtEnd) - : Instruction(cast<FunctionType>(cast<PointerType>(Func->getType()) - ->getElementType())->getReturnType(), - Instruction::Call, 0, 0, InsertAtEnd) { - init(Func, ArgBegin, ArgEnd, Name, - typename std::iterator_traits<InputIterator>::iterator_category()); - } + inline CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, + const std::string &Name, BasicBlock *InsertAtEnd); - CallInst(Value *F, Value *Actual, const std::string& Name = "", - Instruction *InsertBefore = 0); + CallInst(Value *F, Value *Actual, const std::string& Name, + Instruction *InsertBefore); CallInst(Value *F, Value *Actual, const std::string& Name, BasicBlock *InsertAtEnd); - explicit CallInst(Value *F, const std::string &Name = "", - Instruction *InsertBefore = 0); + explicit CallInst(Value *F, const std::string &Name, + Instruction *InsertBefore); CallInst(Value *F, const std::string &Name, BasicBlock *InsertAtEnd); public: template<typename InputIterator> - static CallInst *Create(Value *Func, InputIterator ArgBegin, - InputIterator ArgEnd, + static CallInst *Create(Value *Func, + InputIterator ArgBegin, InputIterator ArgEnd, const std::string &Name = "", Instruction *InsertBefore = 0) { return new(ArgEnd - ArgBegin + 1) CallInst(Func, ArgBegin, ArgEnd, Name, InsertBefore); } template<typename InputIterator> - static CallInst *Create(Value *Func, InputIterator ArgBegin, - InputIterator ArgEnd, const std::string &Name, - BasicBlock *InsertAtEnd) { + static CallInst *Create(Value *Func, + InputIterator ArgBegin, InputIterator ArgEnd, + const std::string &Name, BasicBlock *InsertAtEnd) { return new(ArgEnd - ArgBegin + 1) CallInst(Func, ArgBegin, ArgEnd, Name, InsertAtEnd); } @@ -967,6 +990,9 @@ public: ~CallInst(); virtual CallInst *clone() const; + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); bool isTailCall() const { return SubclassData & 1; } void setTailCall(bool isTailCall = true) { @@ -1050,6 +1076,36 @@ public: } }; +template <> +struct OperandTraits<CallInst> : VariadicOperandTraits<1> { +}; + +template<typename InputIterator> +CallInst::CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, + const std::string &Name, BasicBlock *InsertAtEnd) + : Instruction(cast<FunctionType>(cast<PointerType>(Func->getType()) + ->getElementType())->getReturnType(), + Instruction::Call, + OperandTraits<CallInst>::op_end(this) - (ArgEnd - ArgBegin + 1), + ArgEnd - ArgBegin + 1, InsertAtEnd) { + init(Func, ArgBegin, ArgEnd, Name, + typename std::iterator_traits<InputIterator>::iterator_category()); +} + +template<typename InputIterator> +CallInst::CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, + const std::string &Name, Instruction *InsertBefore) + : Instruction(cast<FunctionType>(cast<PointerType>(Func->getType()) + ->getElementType())->getReturnType(), + Instruction::Call, + OperandTraits<CallInst>::op_end(this) - (ArgEnd - ArgBegin + 1), + ArgEnd - ArgBegin + 1, InsertBefore) { + init(Func, ArgBegin, ArgEnd, Name, + typename std::iterator_traits<InputIterator>::iterator_category()); +} + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CallInst, Value) + //===----------------------------------------------------------------------===// // SelectInst Class //===----------------------------------------------------------------------===// @@ -1057,27 +1113,27 @@ public: /// SelectInst - This class represents the LLVM 'select' instruction. /// class SelectInst : public Instruction { - Use Ops[3]; - void init(Value *C, Value *S1, Value *S2) { - Ops[0].init(C, this); - Ops[1].init(S1, this); - Ops[2].init(S2, this); + Op<0>() = C; + Op<1>() = S1; + Op<2>() = S2; } SelectInst(const SelectInst &SI) - : Instruction(SI.getType(), SI.getOpcode(), Ops, 3) { - init(SI.Ops[0], SI.Ops[1], SI.Ops[2]); + : Instruction(SI.getType(), SI.getOpcode(), &Op<0>(), 3) { + init(SI.Op<0>(), SI.Op<1>(), SI.Op<2>()); } - SelectInst(Value *C, Value *S1, Value *S2, const std::string &Name = "", - Instruction *InsertBefore = 0) - : Instruction(S1->getType(), Instruction::Select, Ops, 3, InsertBefore) { + SelectInst(Value *C, Value *S1, Value *S2, const std::string &Name, + Instruction *InsertBefore) + : Instruction(S1->getType(), Instruction::Select, + &Op<0>(), 3, InsertBefore) { init(C, S1, S2); setName(Name); } SelectInst(Value *C, Value *S1, Value *S2, const std::string &Name, BasicBlock *InsertAtEnd) - : Instruction(S1->getType(), Instruction::Select, Ops, 3, InsertAtEnd) { + : Instruction(S1->getType(), Instruction::Select, + &Op<0>(), 3, InsertAtEnd) { init(C, S1, S2); setName(Name); } @@ -1092,20 +1148,12 @@ public: return new(3) SelectInst(C, S1, S2, Name, InsertAtEnd); } - Value *getCondition() const { return Ops[0]; } - Value *getTrueValue() const { return Ops[1]; } - Value *getFalseValue() const { return Ops[2]; } + Value *getCondition() const { return Op<0>(); } + Value *getTrueValue() const { return Op<1>(); } + Value *getFalseValue() const { return Op<2>(); } /// Transparently provide more efficient getOperand methods. - Value *getOperand(unsigned i) const { - assert(i < 3 && "getOperand() out of range!"); - return Ops[i]; - } - void setOperand(unsigned i, Value *Val) { - assert(i < 3 && "setOperand() out of range!"); - Ops[i] = Val; - } - unsigned getNumOperands() const { return 3; } + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); OtherOps getOpcode() const { return static_cast<OtherOps>(Instruction::getOpcode()); @@ -1123,6 +1171,12 @@ public: } }; +template <> +struct OperandTraits<SelectInst> : FixedNumOperandTraits<3> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(SelectInst, Value) + //===----------------------------------------------------------------------===// // VAArgInst Class //===----------------------------------------------------------------------===// @@ -1165,17 +1219,16 @@ public: /// element from a VectorType value /// class ExtractElementInst : public Instruction { - Use Ops[2]; ExtractElementInst(const ExtractElementInst &EE) : - Instruction(EE.getType(), ExtractElement, Ops, 2) { - Ops[0].init(EE.Ops[0], this); - Ops[1].init(EE.Ops[1], this); + Instruction(EE.getType(), ExtractElement, &Op<0>(), 2) { + Op<0>().init(EE.Op<0>(), this); + Op<1>().init(EE.Op<1>(), this); } public: // allocate space for exactly two operands void *operator new(size_t s) { - return User::operator new(s, 2); // FIXME: unsigned Idx forms of constructor? + return User::operator new(s, 2); // FIXME: "unsigned Idx" forms of ctor? } ExtractElementInst(Value *Vec, Value *Idx, const std::string &Name = "", Instruction *InsertBefore = 0); @@ -1193,15 +1246,7 @@ public: virtual ExtractElementInst *clone() const; /// Transparently provide more efficient getOperand methods. - Value *getOperand(unsigned i) const { - assert(i < 2 && "getOperand() out of range!"); - return Ops[i]; - } - void setOperand(unsigned i, Value *Val) { - assert(i < 2 && "setOperand() out of range!"); - Ops[i] = Val; - } - unsigned getNumOperands() const { return 2; } + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const ExtractElementInst *) { return true; } @@ -1213,6 +1258,12 @@ public: } }; +template <> +struct OperandTraits<ExtractElementInst> : FixedNumOperandTraits<2> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ExtractElementInst, Value) + //===----------------------------------------------------------------------===// // InsertElementInst Class //===----------------------------------------------------------------------===// @@ -1221,7 +1272,6 @@ public: /// element into a VectorType value /// class InsertElementInst : public Instruction { - Use Ops[3]; InsertElementInst(const InsertElementInst &IE); InsertElementInst(Value *Vec, Value *NewElt, Value *Idx, const std::string &Name = "",Instruction *InsertBefore = 0); @@ -1236,14 +1286,14 @@ public: return new(IE.getNumOperands()) InsertElementInst(IE); } static InsertElementInst *Create(Value *Vec, Value *NewElt, Value *Idx, - const std::string &Name = "",Instruction *InsertBefore = 0) { + const std::string &Name = "", + Instruction *InsertBefore = 0) { return new(3) InsertElementInst(Vec, NewElt, Idx, Name, InsertBefore); } static InsertElementInst *Create(Value *Vec, Value *NewElt, unsigned Idx, const std::string &Name = "", Instruction *InsertBefore = 0) { - return new(3/*FIXME*/) - InsertElementInst(Vec, NewElt, Idx, Name, InsertBefore); + return new(3) InsertElementInst(Vec, NewElt, Idx, Name, InsertBefore); } static InsertElementInst *Create(Value *Vec, Value *NewElt, Value *Idx, const std::string &Name, @@ -1253,8 +1303,7 @@ public: static InsertElementInst *Create(Value *Vec, Value *NewElt, unsigned Idx, const std::string &Name, BasicBlock *InsertAtEnd) { - return new(3/*FIXME*/) - InsertElementInst(Vec, NewElt, Idx, Name, InsertAtEnd); + return new(3) InsertElementInst(Vec, NewElt, Idx, Name, InsertAtEnd); } /// isValidOperands - Return true if an insertelement instruction can be @@ -1271,15 +1320,7 @@ public: } /// Transparently provide more efficient getOperand methods. - Value *getOperand(unsigned i) const { - assert(i < 3 && "getOperand() out of range!"); - return Ops[i]; - } - void setOperand(unsigned i, Value *Val) { - assert(i < 3 && "setOperand() out of range!"); - Ops[i] = Val; - } - unsigned getNumOperands() const { return 3; } + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const InsertElementInst *) { return true; } @@ -1291,6 +1332,12 @@ public: } }; +template <> +struct OperandTraits<InsertElementInst> : FixedNumOperandTraits<3> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementInst, Value) + //===----------------------------------------------------------------------===// // ShuffleVectorInst Class //===----------------------------------------------------------------------===// @@ -1299,7 +1346,6 @@ public: /// input vectors. /// class ShuffleVectorInst : public Instruction { - Use Ops[3]; ShuffleVectorInst(const ShuffleVectorInst &IE); public: // allocate space for exactly three operands @@ -1325,19 +1371,7 @@ public: } /// Transparently provide more efficient getOperand methods. - const Value *getOperand(unsigned i) const { - assert(i < 3 && "getOperand() out of range!"); - return Ops[i]; - } - Value *getOperand(unsigned i) { - assert(i < 3 && "getOperand() out of range!"); - return Ops[i]; - } - void setOperand(unsigned i, Value *Val) { - assert(i < 3 && "setOperand() out of range!"); - Ops[i] = Val; - } - unsigned getNumOperands() const { return 3; } + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// getMaskValue - Return the index from the shuffle mask for the specified /// output result. This is either -1 if the element is undef or a number less @@ -1354,6 +1388,11 @@ public: } }; +template <> +struct OperandTraits<ShuffleVectorInst> : FixedNumOperandTraits<3> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ShuffleVectorInst, Value) //===----------------------------------------------------------------------===// // PHINode Class @@ -1406,6 +1445,9 @@ public: virtual PHINode *clone() const; + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + /// getNumIncomingValues - Return the number of incoming edges /// unsigned getNumIncomingValues() const { return getNumOperands()/2; } @@ -1427,10 +1469,10 @@ public: /// getIncomingBlock - Return incoming basic block number x /// BasicBlock *getIncomingBlock(unsigned i) const { - return reinterpret_cast<BasicBlock*>(getOperand(i*2+1)); + return static_cast<BasicBlock*>(getOperand(i*2+1)); } void setIncomingBlock(unsigned i, BasicBlock *BB) { - setOperand(i*2+1, reinterpret_cast<Value*>(BB)); + setOperand(i*2+1, BB); } unsigned getOperandNumForIncomingBlock(unsigned i) { return i*2+1; @@ -1449,7 +1491,7 @@ public: // Initialize some new operands. NumOperands = OpNo+2; OperandList[OpNo].init(V, this); - OperandList[OpNo+1].init(reinterpret_cast<Value*>(BB), this); + OperandList[OpNo+1].init(BB, this); } /// removeIncomingValue - Remove an incoming value. This is useful if a @@ -1462,7 +1504,7 @@ public: /// Value *removeIncomingValue(unsigned Idx, bool DeletePHIIfEmpty = true); - Value *removeIncomingValue(const BasicBlock *BB, bool DeletePHIIfEmpty =true){ + Value *removeIncomingValue(const BasicBlock *BB, bool DeletePHIIfEmpty=true) { int Idx = getBasicBlockIndex(BB); assert(Idx >= 0 && "Invalid basic block argument to remove!"); return removeIncomingValue(Idx, DeletePHIIfEmpty); @@ -1474,7 +1516,7 @@ public: int getBasicBlockIndex(const BasicBlock *BB) const { Use *OL = OperandList; for (unsigned i = 0, e = getNumOperands(); i != e; i += 2) - if (OL[i+1] == reinterpret_cast<const Value*>(BB)) return i/2; + if (OL[i+1].get() == BB) return i/2; return -1; } @@ -1499,6 +1541,13 @@ public: void resizeOperands(unsigned NumOperands); }; +template <> +struct OperandTraits<PHINode> : HungoffOperandTraits<2> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(PHINode, Value) + + //===----------------------------------------------------------------------===// // ReturnInst Class //===----------------------------------------------------------------------===// @@ -1508,7 +1557,6 @@ public: /// does not continue in this function any longer. /// class ReturnInst : public TerminatorInst { - Use RetVal; ReturnInst(const ReturnInst &RI); void init(Value * const* retVals, unsigned N); @@ -1517,20 +1565,19 @@ private: // ReturnInst() - 'ret void' instruction // ReturnInst( null) - 'ret void' instruction // ReturnInst(Value* X) - 'ret X' instruction - // ReturnInst( null, Inst *) - 'ret void' instruction, insert before I + // ReturnInst( null, Inst *I) - 'ret void' instruction, insert before I // ReturnInst(Value* X, Inst *I) - 'ret X' instruction, insert before I - // ReturnInst( null, BB *B) - 'ret void' instruction, insert @ end of BB - // ReturnInst(Value* X, BB *B) - 'ret X' instruction, insert @ end of BB + // ReturnInst( null, BB *B) - 'ret void' instruction, insert @ end of B + // ReturnInst(Value* X, BB *B) - 'ret X' instruction, insert @ end of B // ReturnInst(Value* X, N) - 'ret X,X+1...X+N-1' instruction - // ReturnInst(Value* X, N, Inst *) - 'ret X,X+1...X+N-1', insert before I - // ReturnInst(Value* X, N, BB *) - 'ret X,X+1...X+N-1', insert @ end of BB + // ReturnInst(Value* X, N, Inst *I) - 'ret X,X+1...X+N-1', insert before I + // ReturnInst(Value* X, N, BB *B) - 'ret X,X+1...X+N-1', insert @ end of B // // NOTE: If the Value* passed is of type void then the constructor behaves as // if it was passed NULL. explicit ReturnInst(Value *retVal = 0, Instruction *InsertBefore = 0); ReturnInst(Value *retVal, BasicBlock *InsertAtEnd); - ReturnInst(Value * const* retVals, unsigned N); - ReturnInst(Value * const* retVals, unsigned N, Instruction *InsertBefore); + ReturnInst(Value * const* retVals, unsigned N, Instruction *InsertBefore = 0); ReturnInst(Value * const* retVals, unsigned N, BasicBlock *InsertAtEnd); explicit ReturnInst(BasicBlock *InsertAtEnd); public: @@ -1540,11 +1587,8 @@ public: static ReturnInst* Create(Value *retVal, BasicBlock *InsertAtEnd) { return new(!!retVal) ReturnInst(retVal, InsertAtEnd); } - static ReturnInst* Create(Value * const* retVals, unsigned N) { - return new(N) ReturnInst(retVals, N); - } static ReturnInst* Create(Value * const* retVals, unsigned N, - Instruction *InsertBefore) { + Instruction *InsertBefore = 0) { return new(N) ReturnInst(retVals, N, InsertBefore); } static ReturnInst* Create(Value * const* retVals, unsigned N, @@ -1555,18 +1599,18 @@ public: return new(0) ReturnInst(InsertAtEnd); } virtual ~ReturnInst(); + inline void operator delete(void*); virtual ReturnInst *clone() const; - Value *getOperand(unsigned n = 0) const { - if (getNumOperands() > 1) - return TerminatorInst::getOperand(n); - else - return RetVal; - } + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + /// Convenience accessor Value *getReturnValue(unsigned n = 0) const { - return getOperand(n); + return n < getNumOperands() + ? getOperand(n) + : 0; } unsigned getNumSuccessors() const { return 0; } @@ -1585,6 +1629,18 @@ public: virtual void setSuccessorV(unsigned idx, BasicBlock *B); }; +template <> +struct OperandTraits<ReturnInst> : VariadicOperandTraits<> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ReturnInst, Value) +void ReturnInst::operator delete(void *it) { + ReturnInst* me(static_cast<ReturnInst*>(it)); + Use::zap(OperandTraits<ReturnInst>::op_begin(me), + OperandTraits<ReturnInst>::op_end(me), + true); +} + //===----------------------------------------------------------------------===// // BranchInst Class //===----------------------------------------------------------------------===// @@ -1596,7 +1652,6 @@ class BranchInst : public TerminatorInst { /// Ops list - Branches are strange. The operands are ordered: /// TrueDest, FalseDest, Cond. This makes some accessors faster because /// they don't have to check for cond/uncond branchness. - Use Ops[3]; BranchInst(const BranchInst &BI); void AssertOK(); // BranchInst constructors (where {B, T, F} are blocks, and C is a condition): @@ -1616,28 +1671,29 @@ public: static BranchInst *Create(BasicBlock *IfTrue, Instruction *InsertBefore = 0) { return new(1) BranchInst(IfTrue, InsertBefore); } - static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, - Instruction *InsertBefore = 0) { + static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *IfFalse, + Value *Cond, Instruction *InsertBefore = 0) { return new(3) BranchInst(IfTrue, IfFalse, Cond, InsertBefore); } static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd) { return new(1) BranchInst(IfTrue, InsertAtEnd); } - static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, - BasicBlock *InsertAtEnd) { + static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *IfFalse, + Value *Cond, BasicBlock *InsertAtEnd) { return new(3) BranchInst(IfTrue, IfFalse, Cond, InsertAtEnd); } - /// Transparently provide more efficient getOperand methods. - Value *getOperand(unsigned i) const { - assert(i < getNumOperands() && "getOperand() out of range!"); - return Ops[i]; - } - void setOperand(unsigned i, Value *Val) { - assert(i < getNumOperands() && "setOperand() out of range!"); - Ops[i] = Val; + ~BranchInst() + { + if (NumOperands == 1) + { + NumOperands = (Use*)this - OperandList; + } } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + virtual BranchInst *clone() const; bool isUnconditional() const { return getNumOperands() == 1; } @@ -1657,12 +1713,12 @@ public: // targeting the specified block. // FIXME: Eliminate this ugly method. void setUnconditionalDest(BasicBlock *Dest) { + Op<0>() = Dest; if (isConditional()) { // Convert this to an uncond branch. + Op<1>().set(0); + Op<2>().set(0); NumOperands = 1; - Ops[1].set(0); - Ops[2].set(0); } - setOperand(0, reinterpret_cast<Value*>(Dest)); } unsigned getNumSuccessors() const { return 1+isConditional(); } @@ -1674,7 +1730,7 @@ public: void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < getNumSuccessors() && "Successor # out of range for Branch!"); - setOperand(idx, reinterpret_cast<Value*>(NewSucc)); + setOperand(idx, NewSucc); } // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -1691,6 +1747,15 @@ private: virtual void setSuccessorV(unsigned idx, BasicBlock *B); }; +template <> +struct OperandTraits<BranchInst> : HungoffOperandTraits<> { + // we need to access operands via OperandList, since + // the NumOperands may change from 3 to 1 + static inline void *allocate(unsigned); // FIXME +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BranchInst, Value) + //===----------------------------------------------------------------------===// // SwitchInst Class //===----------------------------------------------------------------------===// @@ -1699,6 +1764,7 @@ private: /// SwitchInst - Multiway switch /// class SwitchInst : public TerminatorInst { + void *operator new(size_t, unsigned); // DO NOT IMPLEMENT unsigned ReservedSpace; // Operand[0] = Value to switch on // Operand[1] = Default basic block destination @@ -1707,6 +1773,10 @@ class SwitchInst : public TerminatorInst { SwitchInst(const SwitchInst &RI); void init(Value *Value, BasicBlock *Default, unsigned NumCases); void resizeOperands(unsigned No); + // allocate space for exactly zero operands + void *operator new(size_t s) { + return User::operator new(s, 0); + } /// SwitchInst ctor - Create a new switch instruction, specifying a value to /// switch on and a default destination. The number of additional cases can /// be specified here to make memory allocation more efficient. This @@ -1721,18 +1791,19 @@ class SwitchInst : public TerminatorInst { SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, BasicBlock *InsertAtEnd); public: - static SwitchInst *Create(Value *Value, BasicBlock *Default, unsigned NumCases, - Instruction *InsertBefore = 0) { - return new(NumCases/*FIXME*/) - SwitchInst(Value, Default, NumCases, InsertBefore); + static SwitchInst *Create(Value *Value, BasicBlock *Default, + unsigned NumCases, Instruction *InsertBefore = 0) { + return new SwitchInst(Value, Default, NumCases, InsertBefore); } - static SwitchInst *Create(Value *Value, BasicBlock *Default, unsigned NumCases, - BasicBlock *InsertAtEnd) { - return new(NumCases/*FIXME*/) - SwitchInst(Value, Default, NumCases, InsertAtEnd); + static SwitchInst *Create(Value *Value, BasicBlock *Default, + unsigned NumCases, BasicBlock *InsertAtEnd) { + return new SwitchInst(Value, Default, NumCases, InsertAtEnd); } ~SwitchInst(); + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + // Accessor Methods for Switch stmt Value *getCondition() const { return getOperand(0); } void setCondition(Value *V) { setOperand(0, V); } @@ -1805,7 +1876,7 @@ public: } void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < getNumSuccessors() && "Successor # out of range for switch!"); - setOperand(idx*2+1, reinterpret_cast<Value*>(NewSucc)); + setOperand(idx*2+1, NewSucc); } // getSuccessorValue - Return the value associated with the specified @@ -1829,6 +1900,13 @@ private: virtual void setSuccessorV(unsigned idx, BasicBlock *B); }; +template <> +struct OperandTraits<SwitchInst> : HungoffOperandTraits<2> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(SwitchInst, Value) + + //===----------------------------------------------------------------------===// // InvokeInst Class //===----------------------------------------------------------------------===// @@ -1866,15 +1944,10 @@ class InvokeInst : public TerminatorInst { /// /// @brief Construct an InvokeInst from a range of arguments template<typename InputIterator> - InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, - const std::string &Name = "", Instruction *InsertBefore = 0) - : TerminatorInst(cast<FunctionType>(cast<PointerType>(Func->getType()) - ->getElementType())->getReturnType(), - Instruction::Invoke, 0, 0, InsertBefore) { - init(Func, IfNormal, IfException, ArgBegin, ArgEnd, Name, - typename std::iterator_traits<InputIterator>::iterator_category()); - } + inline InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, + InputIterator ArgBegin, InputIterator ArgEnd, + unsigned Values, + const std::string &Name, Instruction *InsertBefore); /// Construct an InvokeInst given a range of arguments. /// InputIterator must be a random-access iterator pointing to @@ -1884,38 +1957,36 @@ class InvokeInst : public TerminatorInst { /// /// @brief Construct an InvokeInst from a range of arguments template<typename InputIterator> - InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, - const std::string &Name, BasicBlock *InsertAtEnd) - : TerminatorInst(cast<FunctionType>(cast<PointerType>(Func->getType()) - ->getElementType())->getReturnType(), - Instruction::Invoke, 0, 0, InsertAtEnd) { - init(Func, IfNormal, IfException, ArgBegin, ArgEnd, Name, - typename std::iterator_traits<InputIterator>::iterator_category()); - } + inline InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, + InputIterator ArgBegin, InputIterator ArgEnd, + unsigned Values, + const std::string &Name, BasicBlock *InsertAtEnd); public: template<typename InputIterator> - static InvokeInst *Create(Value *Func, BasicBlock *IfNormal, - BasicBlock *IfException, + static InvokeInst *Create(Value *Func, + BasicBlock *IfNormal, BasicBlock *IfException, InputIterator ArgBegin, InputIterator ArgEnd, const std::string &Name = "", Instruction *InsertBefore = 0) { - return new(ArgEnd - ArgBegin + 3) - InvokeInst(Func, IfNormal, IfException, ArgBegin, ArgEnd, Name, InsertBefore); + unsigned Values(ArgEnd - ArgBegin + 3); + return new(Values) InvokeInst(Func, IfNormal, IfException, ArgBegin, ArgEnd, + Values, Name, InsertBefore); } template<typename InputIterator> - static InvokeInst *Create(Value *Func, BasicBlock *IfNormal, - BasicBlock *IfException, + static InvokeInst *Create(Value *Func, + BasicBlock *IfNormal, BasicBlock *IfException, InputIterator ArgBegin, InputIterator ArgEnd, const std::string &Name, BasicBlock *InsertAtEnd) { - return new(ArgEnd - ArgBegin + 3) - InvokeInst(Func, IfNormal, IfException, ArgBegin, ArgEnd, Name, InsertAtEnd); + unsigned Values(ArgEnd - ArgBegin + 3); + return new(Values) InvokeInst(Func, IfNormal, IfException, ArgBegin, ArgEnd, + Values, Name, InsertAtEnd); } - ~InvokeInst(); - virtual InvokeInst *clone() const; + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + /// getCallingConv/setCallingConv - Get or set the calling convention of this /// function call. unsigned getCallingConv() const { return SubclassData; } @@ -1985,11 +2056,11 @@ public: return cast<BasicBlock>(getOperand(2)); } void setNormalDest(BasicBlock *B) { - setOperand(1, reinterpret_cast<Value*>(B)); + setOperand(1, B); } void setUnwindDest(BasicBlock *B) { - setOperand(2, reinterpret_cast<Value*>(B)); + setOperand(2, B); } BasicBlock *getSuccessor(unsigned i) const { @@ -1999,7 +2070,7 @@ public: void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < 2 && "Successor # out of range for invoke!"); - setOperand(idx+1, reinterpret_cast<Value*>(NewSucc)); + setOperand(idx+1, NewSucc); } unsigned getNumSuccessors() const { return 2; } @@ -2018,6 +2089,40 @@ private: virtual void setSuccessorV(unsigned idx, BasicBlock *B); }; +template <> +struct OperandTraits<InvokeInst> : VariadicOperandTraits<3> { +}; + +template<typename InputIterator> +InvokeInst::InvokeInst(Value *Func, + BasicBlock *IfNormal, BasicBlock *IfException, + InputIterator ArgBegin, InputIterator ArgEnd, + unsigned Values, + const std::string &Name, Instruction *InsertBefore) + : TerminatorInst(cast<FunctionType>(cast<PointerType>(Func->getType()) + ->getElementType())->getReturnType(), + Instruction::Invoke, + OperandTraits<InvokeInst>::op_end(this) - Values, + Values, InsertBefore) { + init(Func, IfNormal, IfException, ArgBegin, ArgEnd, Name, + typename std::iterator_traits<InputIterator>::iterator_category()); +} +template<typename InputIterator> +InvokeInst::InvokeInst(Value *Func, + BasicBlock *IfNormal, BasicBlock *IfException, + InputIterator ArgBegin, InputIterator ArgEnd, + unsigned Values, + const std::string &Name, BasicBlock *InsertAtEnd) + : TerminatorInst(cast<FunctionType>(cast<PointerType>(Func->getType()) + ->getElementType())->getReturnType(), + Instruction::Invoke, + OperandTraits<InvokeInst>::op_end(this) - Values, + Values, InsertAtEnd) { + init(Func, IfNormal, IfException, ArgBegin, ArgEnd, Name, + typename std::iterator_traits<InputIterator>::iterator_category()); +} + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InvokeInst, Value) //===----------------------------------------------------------------------===// // UnwindInst Class @@ -2572,11 +2677,10 @@ public: /// class GetResultInst : public /*FIXME: Unary*/Instruction { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - Use Aggr; unsigned Idx; GetResultInst(const GetResultInst &GRI) : - Instruction(GRI.getType(), Instruction::GetResult, &Aggr, 1) { - Aggr.init(GRI.Aggr, this); + Instruction(GRI.getType(), Instruction::GetResult, &Op<0>(), 1) { + Op<0>().init(GRI.Op<0>(), this); Idx = GRI.Idx; } @@ -2585,9 +2689,9 @@ public: void *operator new(size_t s) { return User::operator new(s, 1); } - explicit GetResultInst(Value *Aggr, unsigned index, - const std::string &Name = "", - Instruction *InsertBefore = 0); + GetResultInst(Value *Aggr, unsigned index, + const std::string &Name = "", + Instruction *InsertBefore = 0); /// isValidOperands - Return true if an getresult instruction can be /// formed with the specified operands. @@ -2607,7 +2711,8 @@ public: return Idx; } - unsigned getNumOperands() const { return 1; } + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const GetResultInst *) { return true; } @@ -2619,6 +2724,14 @@ public: } }; +// FIXME: these are redundant if GetResultInst < UnaryInstruction +template <> +struct OperandTraits<GetResultInst> : FixedNumOperandTraits<1> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetResultInst, Value) + + } // End llvm namespace #endif diff --git a/include/llvm/OperandTraits.h b/include/llvm/OperandTraits.h new file mode 100644 index 0000000000..3811927e57 --- /dev/null +++ b/include/llvm/OperandTraits.h @@ -0,0 +1,163 @@ +//===-- llvm/OperandTraits.h - OperandTraits class definition ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the traits classes that are handy for enforcing the correct +// layout of various User subclasses. It also provides the means for accessing +// the operands in the most efficient manner. +// + +#ifndef LLVM_OPERAND_TRAITS_H +#define LLVM_OPERAND_TRAITS_H + +#include "llvm/User.h" + +namespace llvm { + +//===----------------------------------------------------------------------===// +// FixedNumOperands Trait Class +//===----------------------------------------------------------------------===// + +template <unsigned ARITY> +struct FixedNumOperandTraits { + static Use *op_begin(User* U) { + return reinterpret_cast<Use*>(U) - ARITY; + } + static Use *op_end(User* U) { + return reinterpret_cast<Use*>(U); + } + static unsigned operands(const User*) { + return ARITY; + } + struct prefix { + Use Ops[ARITY]; + prefix(); // DO NOT IMPLEMENT + }; + template <class U> + struct Layout { + struct overlay : prefix, U { + overlay(); // DO NOT IMPLEMENT + }; + }; + static inline void *allocate(unsigned); // FIXME +}; + +//===----------------------------------------------------------------------===// +// OptionalOperands Trait Class +//===----------------------------------------------------------------------===// + +template <unsigned ARITY = 1> +struct OptionalOperandTraits : FixedNumOperandTraits<ARITY> { + static unsigned operands(const User *U) { + return U->getNumOperands(); + } +}; + +//===----------------------------------------------------------------------===// +// VariadicOperand Trait Class +//===----------------------------------------------------------------------===// + +template <unsigned MINARITY = 0> +struct VariadicOperandTraits { + static Use *op_begin(User* U) { + return reinterpret_cast<Use*>(U) - U->getNumOperands(); + } + static Use *op_end(User* U) { + return reinterpret_cast<Use*>(U); + } + static unsigned operands(const User *U) { + return U->getNumOperands(); + } + static inline void *allocate(unsigned); // FIXME +}; + +//===----------------------------------------------------------------------===// +// HungoffOperand Trait Class +//===----------------------------------------------------------------------===// + +template <unsigned MINARITY = 1> +struct HungoffOperandTraits { + static Use *op_begin(User* U) { + return U->OperandList; + } + static Use *op_end(User* U) { + return U->OperandList + U->getNumOperands(); + } + static unsigned operands(const User *U) { + return U->getNumOperands(); + } + static inline void *allocate(unsigned); // FIXME +}; + +/// Macro for generating in-class operand accessor declarations. +/// It should only be called in the public section of the interface. +/// +#define DECLARE_TRANSPARENT_OPERAND_ACCESSORS(VALUECLASS) \ + public: \ + inline VALUECLASS *getOperand(unsigned) const; \ + inline void setOperand(unsigned, VALUECLASS*); \ + protected: \ + template <unsigned> inline Use &Op(); \ + template <unsigned> inline const Use &Op() const; \ + public: \ + inline unsigned getNumOperands() const + +/// Macro for generating out-of-class operand accessor definitions +#define DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CLASS, VALUECLASS) \ +VALUECLASS *CLASS::getOperand(unsigned i_nocapture) const { \ + assert(i_nocapture < OperandTraits<CLASS>::operands(this) \ + && "getOperand() out of range!"); \ + return static_cast<VALUECLASS*>( \ + OperandTraits<CLASS>::op_begin(const_cast<CLASS*>(this))[i_nocapture]); \ +} \ +void CLASS::setOperand(unsigned i_nocapture, VALUECLASS *Val_nocapture) { \ + assert(i_nocapture < OperandTraits<CLASS>::operands(this) \ + && "setOperand() out of range!"); \ + OperandTraits<CLASS>::op_begin(this)[i_nocapture] = Val_nocapture; \ +} \ +unsigned CLASS::getNumOperands() const { \ + return OperandTraits<CLASS>::operands(this); \ +} \ +template <unsigned Idx_nocapture> Use &CLASS::Op() { \ + return OperandTraits<CLASS>::op_begin(this)[Idx_nocapture]; \ +} \ +template <unsigned Idx_nocapture> const Use &CLASS::Op() const { \ + return OperandTraits<CLASS>::op_begin( \ + const_cast<CLASS*>(this))[Idx_nocapture]; \ +} + + +/// Macro for generating out-of-class operand accessor +/// definitions with casted result +#define DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(CLASS, VALUECLASS) \ +VALUECLASS *CLASS::getOperand(unsigned i_nocapture) const { \ + assert(i_nocapture < OperandTraits<CLASS>::operands(this) \ + && "getOperand() out of range!"); \ + return cast<VALUECLASS>( \ + OperandTraits<CLASS>::op_begin(const_cast<CLASS*>(this))[i_nocapture]); \ +} \ +void CLASS::setOperand(unsigned i_nocapture, VALUECLASS *Val_nocapture) { \ + assert(i_nocapture < OperandTraits<CLASS>::operands(this) \ + && "setOperand() out of range!"); \ + OperandTraits<CLASS>::op_begin(this)[i_nocapture] = Val_nocapture; \ +} \ +unsigned CLASS::getNumOperands() const { \ + return OperandTraits<CLASS>::operands(this); \ +} \ +template <unsigned Idx_nocapture> Use &CLASS::Op() { \ + return OperandTraits<CLASS>::op_begin(this)[Idx_nocapture]; \ +} \ +template <unsigned Idx_nocapture> const Use &CLASS::Op() const { \ + return OperandTraits<CLASS>::op_begin( \ + const_cast<CLASS*>(this))[Idx_nocapture]; \ +} + + +} // End llvm namespace + +#endif diff --git a/include/llvm/Use.h b/include/llvm/Use.h index e050743ffd..b4d4bda620 100644 --- a/include/llvm/Use.h +++ b/include/llvm/Use.h @@ -26,6 +26,40 @@ class User; //===----------------------------------------------------------------------===// +// Generic Tagging Functions +//===----------------------------------------------------------------------===// + +/// Tag - generic tag type for (at least 32 bit) pointers +enum Tag { noTag, tagOne, tagTwo, tagThree }; + +/// addTag - insert tag bits into an (untagged) pointer +template <typename T, typename TAG> +inline T *addTag(const T *P, TAG Tag) { + return reinterpret_cast<T*>(ptrdiff_t(P) | Tag); +} + +/// stripTag - remove tag bits from a pointer, +/// making it dereferencable +template <ptrdiff_t MASK, typename T> +inline T *stripTag(const T *P) { + return reinterpret_cast<T*>(ptrdiff_t(P) & ~MASK); +} + +/// extractTag - extract tag bits from a pointer +template <typename TAG, TAG MASK, typename T> +inline TAG extractTag(const T *P) { + return TAG(ptrdiff_t(P) & MASK); +} + +/// transferTag - transfer tag bits from a pointer, +/// to an untagged pointer +template <ptrdiff_t MASK, typename T> +inline T *transferTag(const T *From, const T *To) { + return reinterpret_cast<T*>((ptrdiff_t(From) & MASK) | ptrdiff_t(To)); +} + + +//===----------------------------------------------------------------------===// // Use Class //===----------------------------------------------------------------------===// @@ -35,20 +69,36 @@ class Use { public: inline void init(Value *V, User *U); - Use(Value *V, User *U) { init(V, U); } - Use(const Use &U) { init(U.Val, U.U); } +private: + /// Allow std::swap some intimacy + template <typename U> friend void std::swap(U&, U&); + + /// Copy ctor - Only for std::swap + Use(const Use &U) { init(U.get(), 0); } + + /// Destructor - Only for zap() and std::swap inline ~Use() { - if (Val) removeFromList(); + if (get()) removeFromList(); } - /// Default ctor - This leaves the Use completely unitialized. The only thing + /// Default ctor - This leaves the Use completely uninitialized. The only thing /// that is valid to do with this use is to call the "init" method. - inline Use() : Val(0) {} + + inline Use() {} + enum PrevPtrTag { zeroDigitTag = noTag + , oneDigitTag = tagOne + , stopTag = tagTwo + , fullStopTag = tagThree }; + +public: operator Value*() const { return Val; } Value *get() const { return Val; } - User *getUser() const { return U; } + User *getUser() const; + const Use* getImpliedUser() const; + static Use *initTags(Use *Start, Use *Stop, ptrdiff_t Done = 0); + static void zap(Use *Start, const Use *Stop, bool del = false); inline void set(Value *Val); @@ -57,7 +107,7 @@ public: return RHS; } const Use &operator=(const Use &RHS) { - set(RHS.Val); + set(RHS.get()); return *this; } @@ -66,19 +116,22 @@ public: Use *getNext() const { return Next; } private: - Use *Next, **Prev; Value *Val; - User *U; + Use *Next, **Prev; + void setPrev(Use **NewPrev) { + Prev = transferTag<fullStopTag>(Prev, NewPrev); + } void addToList(Use **List) { Next = *List; - if (Next) Next->Prev = &Next; - Prev = List; + if (Next) Next->setPrev(&Next); + setPrev(List); *List = this; } void removeFromList() { - *Prev = Next; - if (Next) Next->Prev = Prev; + Use **StrippedPrev = stripTag<fullStopTag>(Prev); + *StrippedPrev = Next; + if (Next) Next->setPrev(StrippedPrev); } friend class Value; @@ -138,7 +191,7 @@ public: // Retrieve a reference to the current User UserTy *operator*() const { - assert(U && "Cannot increment end iterator!"); + assert(U && "Cannot dereference end iterator!"); return U->getUser(); } diff --git a/include/llvm/User.h b/include/llvm/User.h index d3e4f1ede2..1454779154 100644 --- a/include/llvm/User.h +++ b/include/llvm/User.h @@ -23,15 +23,203 @@ namespace llvm { +/*============================================================================== + + + ----------------------------------------------------------------- + --- Interaction and relationship between User and Use objects --- + ----------------------------------------------------------------- + + +A subclass of User can choose between incorporating its Use objects +or refer to them out-of-line by means of a pointer. A mixed variant +(some Uses inline others hung off) is impractical and breaks the invariant +that the Use objects belonging to the same User form a contiguous array. + +We have 2 different layouts in the User (sub)classes: + +Layout a) +The Use object(s) are inside (resp. at fixed offset) of the User +object and there are a fixed number of them. + +Layout b) +The Use object(s) are referenced by a pointer to an +array from the User object and there may be a variable +number of them. + +Initially each layout will possess a direct pointer to the +start of the array of Uses. Though not mandatory for layout a), +we stick to this redundancy for the sake of simplicity. +The User object will also store the number of Use objects it +has. (Theoretically this information can also be calculated +given the scheme presented below.) + +Special forms of allocation operators (operator new) +will enforce the following memory layouts: + + +# Layout a) will be modelled by prepending the User object +# by the Use[] array. +# +# ...---.---.---.---.-------... +# | P | P | P | P | User +# '''---'---'---'---'-------''' + + +# Layout b) will be modelled by pointing at the Use[] array. +# +# .-------... +# | User +# '-------''' +# | +# v +# .---.---.---.---... +# | P | P | P | P | +# '---'---'---'---''' + + (In the above figures 'P' stands for the Use** that + is stored in each Use object in the member Use::Prev) + + +Since the Use objects will be deprived of the direct pointer to +their User objects, there must be a fast and exact method to +recover it. This is accomplished by the following scheme: + +A bit-encoding in the 2 LSBits of the Use::Prev will allow to find the +start of the User object: + +00 --> binary digit 0 +01 --> binary digit 1 +10 --> stop and calc (s) +11 --> full stop (S) + +Given a Use*, all we have to do is to walk till we get +a stop and we either have a User immediately behind or +we have to walk to the next stop picking up digits +and calculating the offset: + +.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---------------- +| 1 | s | 1 | 0 | 1 | 0 | s | 1 | 1 | 0 | s | 1 | 1 | s | 1 | S | User (or User*) +'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---------------- + |+15 |+10 |+6 |+3 |+1 + | | | | |__> + | | | |__________> + | | |______________________> + | |______________________________________> + |__________________________________________________________> + + +Only the significant number of bits need to be stored between the +stops, so that the worst case is 20 memory accesses when there are +1000 Use objects. + +The following literate Haskell fragment demonstrates the concept: + +> import Test.QuickCheck +> +> digits :: Int -> [Char] -> [Char] +> digits 0 acc = '0' : acc +> digits 1 acc = '1' : acc +> digits n acc = digits (n `div` 2) $ digits (n `mod` 2) acc +> +> dist :: Int -> [Char] -> [Char] +> dist 0 [] = ['S'] +> dist 0 acc = acc +> dist 1 acc = let r = dist 0 acc in 's' : digits (length r) r +> dist n acc = dist (n - 1) $ dist 1 acc +> +> takeLast n ss = reverse $ take n $ reverse ss +> +> test = takeLast 40 $ dist 20 [] +> + +Printing <test> gives: "1s100000s11010s10100s1111s1010s110s11s1S" + +The reverse algorithm computes the +length of the string just by examining +a certain prefix: + +> pref :: [Char] -> Int +> pref "S" = 1 +> pref ('s':'1':rest) = decode 2 1 rest +> pref (_:rest) = 1 + pref rest +> +> decode walk acc ('0':rest) = decode (walk + 1) (acc * 2) rest +> decode walk acc ('1':rest) = decode (walk + 1) (acc * 2 + 1) rest +> decode walk acc _ = walk + acc +> + +Now, as expected, printing <pref test> gives 40. + +We can quickCheck this with following property: + +> testcase = dist 2000 [] +> testcaseLength = length testcase +> +> identityProp n = n > 0 && n <= testcaseLength ==> length arr == pref arr +> where arr = takeLast n testcase + +As expected <quickCheck identityProp> gives: + +*Main> quickCheck identityProp +OK, passed 100 tests. + +Let's be a bit more exhaustive: + +> +> deepCheck p = check (defaultConfig { configMaxTest = 500 }) p +> + +And here is the result of <deepCheck identityProp>: + +*Main> deepCheck identityProp +OK, passed 500 tests. + + +To maintain the invariant that the 2 LSBits of each Use** in Use +never change after being set up, setters of Use::Prev must re-tag the +new Use** on every modification. Accordingly getters must strip the +tag bits. + +For layout b) instead of the User we will find a pointer (User* with LSBit set). +Following this pointer brings us to the User. A portable trick will ensure +that the first bytes of User (if interpreted as a pointer) will never have +the LSBit set. + +==============================================================================*/ + +/// OperandTraits - Compile-time customization of +/// operand-related allocators and accessors +/// for use of the User class +template <class> +struct OperandTraits; + +class User; + +/// OperandTraits<User> - specialization to User +template <> +struct OperandTraits<User> { + static inline Use *op_begin(User*); + static inline Use *op_end(User*); + static inline unsigned operands(const User*); + template <class U> + struct Layout { + typedef U overlay; + }; + static inline void *allocate(unsigned); +}; + class User : public Value { User(const User &); // Do not implement void *operator new(size_t); // Do not implement + template <unsigned> + friend struct HungoffOperandTraits; protected: /// OperandList - This is a pointer to the array of Users for this operand. /// For nodes of fixed arity (e.g. a binary operator) this array will live - /// embedded into the derived class. For nodes of variable arity - /// (e.g. ConstantArrays, CallInst, PHINodes, ReturnInst etc), this memory - /// will be dynamically allocated and should be destroyed by the classes + /// prefixed to the derived class. For nodes of resizable variable arity + /// (e.g. PHINodes, SwitchInst etc.), this memory will be dynamically + /// allocated and should be destroyed by the classes' /// virtual dtor. Use *OperandList; @@ -39,13 +227,43 @@ protected: /// unsigned NumOperands; - void *operator new(size_t s, size_t) { - return ::operator new(s); + void *operator new(size_t s, unsigned Us) { + void *Storage = ::operator new(s + sizeof(Use) * Us); + Use *Start = static_cast<Use*>(Storage); + Use *End = Start + Us; + User *Obj = reinterpret_cast<User*>(End); + Obj->OperandList = Start; + Obj->NumOperands = Us; + Use::initTags(Start, End); + return Obj; } User(const Type *Ty, unsigned vty, Use *OpList, unsigned NumOps) : Value(Ty, vty), OperandList(OpList), NumOperands(NumOps) {} - + Use *allocHungoffUses(unsigned) const; + void dropHungoffUses(Use *U) { + if (OperandList == U) { + OperandList = 0; + NumOperands = 0; + } + Use::zap(U, U->getImpliedUser(), true); + } public: + ~User() { + Use::zap(OperandList, OperandList + NumOperands); + } + void operator delete(void *Usr) { + User *Start = static_cast<User*>(Usr); + Use *Storage = static_cast<Use*>(Usr) - Start->NumOperands; + ::operator delete(Storage == Start->OperandList + ? Storage + : Usr); + } + template <unsigned Idx> Use &Op() { + return OperandTraits<User>::op_begin(this)[Idx]; + } + template <unsigned Idx> const Use &Op() const { + return OperandTraits<User>::op_begin(const_cast<User*>(this))[Idx]; + } Value *getOperand(unsigned i) const { assert(i < NumOperands && "getOperand() out of range!"); return OperandList[i]; @@ -93,6 +311,18 @@ public: } }; +inline Use *OperandTraits<User>::op_begin(User *U) { + return U->op_begin(); +} + +inline Use *OperandTraits<User>::op_end(User *U) { + return U->op_end(); +} + +inline unsigned OperandTraits<User>::operands(const User *U) { + return U->getNumOperands(); +} + template<> struct simplify_type<User::op_iterator> { typedef Value* SimpleType; diff --git a/include/llvm/Value.h b/include/llvm/Value.h index 2bcac08a95..2d6351d530 100644 --- a/include/llvm/Value.h +++ b/include/llvm/Value.h @@ -232,10 +232,9 @@ inline std::ostream &operator<<(std::ostream &OS, const Value &V) { return OS; } -void Use::init(Value *v, User *user) { - Val = v; - U = user; - if (Val) Val->addUse(*this); +void Use::init(Value *V, User *user) { + Val = V; + if (V) V->addUse(*this); } void Use::set(Value *V) { diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index ec25f52b1b..78cd1de205 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/OperandTraits.h" using namespace llvm; void BitcodeReader::FreeState() { @@ -115,55 +116,81 @@ static int GetDecodedBinaryOpcode(unsigned Val, const Type *Ty) { } } - +namespace llvm { namespace { /// @brief A class for maintaining the slot number definition /// as a placeholder for the actual definition for forward constants defs. class ConstantPlaceHolder : public ConstantExpr { ConstantPlaceHolder(); // DO NOT IMPLEMENT void operator=(const ConstantPlaceHolder &); // DO NOT IMPLEMENT - Use Op; public: // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 1); } explicit ConstantPlaceHolder(const Type *Ty) - : ConstantExpr(Ty, Instruction::UserOp1, &Op, 1), - Op(UndefValue::get(Type::Int32Ty), this) { + : ConstantExpr(Ty, Instruction::UserOp1, &Op<0>(), 1) { + Op<0>() = UndefValue::get(Type::Int32Ty); } + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; } + + // FIXME: can we inherit this from ConstantExpr? +template <> +struct OperandTraits<ConstantPlaceHolder> : FixedNumOperandTraits<1> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value) +} + +void BitcodeReaderValueList::resize(unsigned Desired) { + if (Desired > Capacity) { + // Since we expect many values to come from the bitcode file we better + // allocate the double amount, so that the array size grows exponentially + // at each reallocation. Also, add a small amount of 100 extra elements + // each time, to reallocate less frequently when the array is still small. + // + Capacity = Desired * 2 + 100; + Use *New = allocHungoffUses(Capacity); + Use *Old = OperandList; + unsigned Ops = getNumOperands(); + for (int i(Ops - 1); i >= 0; --i) + New[i] = Old[i].get(); + OperandList = New; + if (Old) Use::zap(Old, Old + Ops, true); + } +} + Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx, const Type *Ty) { if (Idx >= size()) { // Insert a bunch of null values. - Uses.resize(Idx+1); - OperandList = &Uses[0]; + resize(Idx + 1); NumOperands = Idx+1; } - if (Value *V = Uses[Idx]) { + if (Value *V = OperandList[Idx]) { assert(Ty == V->getType() && "Type mismatch in constant table!"); return cast<Constant>(V); } // Create and return a placeholder, which will later be RAUW'd. Constant *C = new ConstantPlaceHolder(Ty); - Uses[Idx].init(C, this); + OperandList[Idx].init(C, this); return C; } Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, const Type *Ty) { if (Idx >= size()) { // Insert a bunch of null values. - Uses.resize(Idx+1); - OperandList = &Uses[0]; + resize(Idx + 1); NumOperands = Idx+1; } - if (Value *V = Uses[Idx]) { + if (Value *V = OperandList[Idx]) { assert((Ty == 0 || Ty == V->getType()) && "Type mismatch in value table!"); return V; } @@ -173,7 +200,7 @@ Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, const Type *Ty) { // Create and return a placeholder, which will later be RAUW'd. Value *V = new Argument(Ty); - Uses[Idx].init(V, this); + OperandList[Idx].init(V, this); return V; } diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index 86b00a5ef1..c35846f402 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -17,7 +17,7 @@ #include "llvm/ModuleProvider.h" #include "llvm/ParameterAttributes.h" #include "llvm/Type.h" -#include "llvm/User.h" +#include "llvm/OperandTraits.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/ADT/DenseMap.h" @@ -26,32 +26,43 @@ namespace llvm { class MemoryBuffer; +//===----------------------------------------------------------------------===// +// BitcodeReaderValueList Class +//===----------------------------------------------------------------------===// + class BitcodeReaderValueList : public User { - std::vector<Use> Uses; + unsigned Capacity; public: - BitcodeReaderValueList() : User(Type::VoidTy, Value::ArgumentVal, 0, 0) {} - + BitcodeReaderValueList() : User(Type::VoidTy, Value::ArgumentVal, 0, 0) + , Capacity(0) {} + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + // vector compatibility methods unsigned size() const { return getNumOperands(); } + void resize(unsigned); void push_back(Value *V) { - Uses.push_back(Use(V, this)); - OperandList = &Uses[0]; - ++NumOperands; + unsigned OldOps(NumOperands), NewOps(NumOperands + 1); + resize(NewOps); + NumOperands = NewOps; + OperandList[OldOps] = V; } void clear() { - std::vector<Use>().swap(Uses); + if (OperandList) dropHungoffUses(OperandList); + Capacity = 0; } Value *operator[](unsigned i) const { return getOperand(i); } - Value *back() const { return Uses.back(); } - void pop_back() { Uses.pop_back(); --NumOperands; } + Value *back() const { return getOperand(size() - 1); } + void pop_back() { setOperand(size() - 1, 0); --NumOperands; } bool empty() const { return NumOperands == 0; } void shrinkTo(unsigned N) { assert(N <= NumOperands && "Invalid shrinkTo request!"); - Uses.resize(N); - NumOperands = N; + while (NumOperands > N) + pop_back(); } virtual void print(std::ostream&) const {} @@ -73,11 +84,20 @@ public: private: void initVal(unsigned Idx, Value *V) { - assert(Uses[Idx] == 0 && "Cannot init an already init'd Use!"); - Uses[Idx].init(V, this); + if (Idx >= size()) { + // Insert a bunch of null values. + resize(Idx * 2 + 1); + } + assert(getOperand(Idx) == 0 && "Cannot init an already init'd Use!"); + OperandList[Idx].init(V, this); } }; - + +template <> +struct OperandTraits<BitcodeReaderValueList> : HungoffOperandTraits</*16 FIXME*/> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BitcodeReaderValueList, Value) class BitcodeReader : public ModuleProvider { MemoryBuffer *Buffer; diff --git a/lib/VMCore/ConstantFold.cpp b/lib/VMCore/ConstantFold.cpp index 9f31bcdb75..5138031da9 100644 --- a/lib/VMCore/ConstantFold.cpp +++ b/lib/VMCore/ConstantFold.cpp @@ -332,10 +332,10 @@ Constant *llvm::ConstantFoldExtractElementInstruction(const Constant *Val, if (const ConstantVector *CVal = dyn_cast<ConstantVector>(Val)) { if (const ConstantInt *CIdx = dyn_cast<ConstantInt>(Idx)) { - return const_cast<Constant*>(CVal->getOperand(CIdx->getZExtValue())); + return CVal->getOperand(CIdx->getZExtValue()); } else if (isa<UndefValue>(Idx)) { // ee({w,x,y,z}, undef) -> w (an arbitrary value). - return const_cast<Constant*>(CVal->getOperand(0)); + return CVal->getOperand(0); } } return 0; @@ -401,7 +401,7 @@ Constant *llvm::ConstantFoldInsertElementInstruction(const Constant *Val, /// return the specified element value. Otherwise return null. static Constant *GetVectorElement(const Constant *C, unsigned EltNo) { if (const ConstantVector *CV = dyn_cast<ConstantVector>(C)) - return const_cast<Constant*>(CV->getOperand(EltNo)); + return CV->getOperand(EltNo); const Type *EltTy = cast<VectorType>(C->getType())->getElementType(); if (isa<ConstantAggregateZero>(C)) @@ -1222,9 +1222,9 @@ Constant *llvm::ConstantFoldCompareInstruction(unsigned short pred, if (const ConstantVector *CP2 = dyn_cast<ConstantVector>(C2)) { if (pred == FCmpInst::FCMP_OEQ || pred == FCmpInst::FCMP_UEQ) { for (unsigned i = 0, e = CP1->getNumOperands(); i != e; ++i) { - Constant *C= ConstantExpr::getFCmp(FCmpInst::FCMP_OEQ, - const_cast<Constant*>(CP1->getOperand(i)), - const_cast<Constant*>(CP2->getOperand(i))); + Constant *C = ConstantExpr::getFCmp(FCmpInst::FCMP_OEQ, + CP1->getOperand(i), + CP2->getOperand(i)); if (ConstantInt *CB = dyn_cast<ConstantInt>(C)) return CB; } @@ -1233,8 +1233,8 @@ Constant *llvm::ConstantFoldCompareInstruction(unsigned short pred, } else if (pred == ICmpInst::ICMP_EQ) { for (unsigned i = 0, e = CP1->getNumOperands(); i != e; ++i) { Constant *C = ConstantExpr::getICmp(ICmpInst::ICMP_EQ, - const_cast<Constant*>(CP1->getOperand(i)), - const_cast<Constant*>(CP2->getOperand(i))); + CP1->getOperand(i), + CP2->getOperand(i)); if (ConstantInt *CB = dyn_cast<ConstantInt>(C)) return CB; } diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index 0b8fcc4325..d0c837335d 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -354,7 +354,9 @@ ConstantFP *ConstantFP::get(const Type *Ty, double V) { ConstantArray::ConstantArray(const ArrayType *T, const std::vector<Constant*> &V) - : Constant(T, ConstantArrayVal, new Use[V.size()], V.size()) { + : Constant(T, ConstantArrayVal, + OperandTraits<ConstantArray>::op_end(this) - V.size(), + V.size()) { assert(V.size() == T->getNumElements() && "Invalid initializer vector for constant array"); Use *OL = OperandList; @@ -369,13 +371,12 @@ ConstantArray::ConstantArray(const ArrayType *T, } } -ConstantArray::~ConstantArray() { - delete [] OperandList; -} ConstantStruct::ConstantStruct(const StructType *T, const std::vector<Constant*> &V) - : Constant(T, ConstantStructVal, new Use[V.size()], V.size()) { + : Constant(T, ConstantStructVal, + OperandTraits<ConstantStruct>::op_end(this) - V.size(), + V.size()) { assert(V.size() == T->getNumElements() && "Invalid initializer vector for constant structure"); Use *OL = OperandList; @@ -392,14 +393,12 @@ ConstantStruct::ConstantStruct(const StructType *T, } } -ConstantStruct::~ConstantStruct() { - delete [] OperandList; -} - ConstantVector::ConstantVector(const VectorType *T, const std::vector<Constant*> &V) - : Constant(T, ConstantVectorVal, new Use[V.size()], V.size()) { + : Constant(T, ConstantVectorVal, + OperandTraits<ConstantVector>::op_end(this) - V.size(), + V.size()) { Use *OL = OperandList; for (std::vector<Constant*>::const_iterator I = V.begin(), E = V.end(); I != E; ++I, ++OL) { @@ -412,10 +411,8 @@ ConstantVector::ConstantVector(const VectorType *T, } } -ConstantVector::~ConstantVector() { - delete [] OperandList; -} +namespace llvm { // We declare several classes private to this file, so use an anonymous // namespace namespace { @@ -424,49 +421,54 @@ namespace { /// behind the scenes to implement unary constant exprs. class VISIBILITY_HIDDEN UnaryConstantExpr : public ConstantExpr { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - Use Op; public: // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 1); } UnaryConstantExpr(unsigned Opcode, Constant *C, const Type *Ty) - : ConstantExpr(Ty, Opcode, &Op, 1), Op(C, this) {} + : ConstantExpr(Ty, Opcode, &Op<0>(), 1) { + Op<0>() = C; + } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// BinaryConstantExpr - This class is private to Constants.cpp, and is used /// behind the scenes to implement binary constant exprs. class VISIBILITY_HIDDEN BinaryConstantExpr : public ConstantExpr { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - Use Ops[2]; public: // allocate space for exactly two operands void *operator new(size_t s) { return User::operator new(s, 2); } BinaryConstantExpr(unsigned Opcode, Constant *C1, Constant *C2) - : ConstantExpr(C1->getType(), Opcode, Ops, 2) { - Ops[0].init(C1, this); - Ops[1].init(C2, this); + : ConstantExpr(C1->getType(), Opcode, &Op<0>(), 2) { + Op<0>().init(C1, this); + Op<1>().init(C2, this); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// SelectConstantExpr - This class is private to Constants.cpp, and is used /// behind the scenes to implement select constant exprs. class VISIBILITY_HIDDEN SelectConstantExpr : public ConstantExpr { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - Use Ops[3]; public: // allocate space for exactly three operands void *operator new(size_t s) { return User::operator new(s, 3); } SelectConstantExpr(Constant *C1, Constant *C2, Constant *C3) - : ConstantExpr(C2->getType(), Instruction::Select, Ops, 3) { - Ops[0].init(C1, this); - Ops[1].init(C2, this); - Ops[2].init(C3, this); + : ConstantExpr(C2->getType(), Instruction::Select, &Op<0>(), 3) { + Op<0>().init(C1, this); + Op<1>().init(C2, this); + Op<2>().init(C3, this); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// ExtractElementConstantExpr - This class is private to @@ -474,7 +476,6 @@ public: /// extractelement constant exprs. class VISIBILITY_HIDDEN ExtractElementConstantExpr : public ConstantExpr { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - Use Ops[2]; public: // allocate space for exactly two operands void *operator new(size_t s) { @@ -482,10 +483,12 @@ public: } ExtractElementConstantExpr(Constant *C1, Constant *C2) : ConstantExpr(cast<VectorType>(C1->getType())->getElementType(), - Instruction::ExtractElement, Ops, 2) { - Ops[0].init(C1, this); - Ops[1].init(C2, this); + Instruction::ExtractElement, &Op<0>(), 2) { + Op<0>().init(C1, this); + Op<1>().init(C2, this); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// InsertElementConstantExpr - This class is private to @@ -493,7 +496,6 @@ public: /// insertelement constant exprs. class VISIBILITY_HIDDEN InsertElementConstantExpr : public ConstantExpr { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - Use Ops[3]; public: // allocate space for exactly three operands void *operator new(size_t s) { @@ -501,11 +503,13 @@ public: } InsertElementConstantExpr(Constant *C1, Constant *C2, Constant *C3) : ConstantExpr(C1->getType(), Instruction::InsertElement, - Ops, 3) { - Ops[0].init(C1, this); - Ops[1].init(C2, this); - Ops[2].init(C3, this); + &Op<0>(), 3) { + Op<0>().init(C1, this); + Op<1>().init(C2, this); + Op<2>().init(C3, this); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// ShuffleVectorConstantExpr - This class is private to @@ -513,7 +517,6 @@ public: /// shufflevector constant exprs. class VISIBILITY_HIDDEN ShuffleVectorConstantExpr : public ConstantExpr { void *operator new(size_t, unsigned); // DO NOT IMPLEMENT - Use Ops[3]; public: // allocate space for exactly three operands void *operator new(size_t s) { @@ -521,32 +524,27 @@ public: } ShuffleVectorConstantExpr(Constant *C1, Constant *C2, Constant *C3) : ConstantExpr(C1->getType(), Instruction::ShuffleVector, - Ops, 3) { - Ops[0].init(C1, this); - Ops[1].init(C2, this); - Ops[2].init(C3, this); + &Op<0>(), 3) { + Op<0>().init(C1, this); + Op<1>().init(C2, this); + Op<2>().init(C3, this); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; /// GetElementPtrConstantExpr - This class is private to Constants.cpp, and is /// used behind the scenes to implement getelementpr constant exprs. class VISIBILITY_HIDDEN GetElementPtrConstantExpr : public ConstantExpr { GetElementPtrConstantExpr(Constant *C, const std::vector<Constant*> &IdxList, - const Type *DestTy) - : ConstantExpr(DestTy, Instruction::GetElementPtr, - new Use[IdxList.size()+1], IdxList.size()+1) { - OperandList[0].init(C, this); - for (unsigned i = 0, E = IdxList.size(); i != E; ++i) - OperandList[i+1].init(IdxList[i], this); - } + const Type *DestTy); public: static GetElementPtrConstantExpr *Create(Constant *C, const std::vector<Constant*> &IdxList, - const Type *DestTy) { - return new(IdxList.size() + 1/*FIXME*/) GetElementPtrConstantExpr(C, IdxList, DestTy); - } - ~GetElementPtrConstantExpr() { - delete [] OperandList; + const Type *DestTy) { + return new(IdxList.size() + 1) GetElementPtrConstantExpr(C, IdxList, DestTy); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; // CompareConstantExpr - This class is private to Constants.cpp, and is used @@ -559,17 +557,77 @@ struct VISIBILITY_HIDDEN CompareConstantExpr : public ConstantExpr { return User::operator new(s, 2); } unsigned short predicate; - Use Ops[2]; CompareConstantExpr(Instruction::OtherOps opc, unsigned short pred, Constant* LHS, Constant* RHS) - : ConstantExpr(Type::Int1Ty, opc, Ops, 2), predicate(pred) { - OperandList[0].init(LHS, this); - OperandList[1].init(RHS, this); + : ConstantExpr(Type::Int1Ty, opc, &Op<0>(), 2), predicate(pred) { + Op<0>().init(LHS, this); + Op<1>().init(RHS, this); } + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; } // end anonymous namespace +template <> +struct OperandTraits<UnaryConstantExpr> : FixedNumOperandTraits<1> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(UnaryConstantExpr, Value) + +template <> +struct OperandTraits<BinaryConstantExpr> : FixedNumOperandTraits<2> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryConstantExpr, Value) + +template <> +struct OperandTraits<SelectConstantExpr> : FixedNumOperandTraits<3> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(SelectConstantExpr, Value) + +template <> +struct OperandTraits<ExtractElementConstantExpr> : FixedNumOperandTraits<2> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ExtractElementConstantExpr, Value) + +template <> +struct OperandTraits<InsertElementConstantExpr> : FixedNumOperandTraits<3> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementConstantExpr, Value) + +template <> +struct OperandTraits<ShuffleVectorConstantExpr> : FixedNumOperandTraits<3> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ShuffleVectorConstantExpr, Value) + + +template <> +struct OperandTraits<GetElementPtrConstantExpr> : VariadicOperandTraits<1> { +}; + +GetElementPtrConstantExpr::GetElementPtrConstantExpr + (Constant *C, + const std::vector<Constant*> &IdxList, + const Type *DestTy) + : ConstantExpr(DestTy, Instruction::GetElementPtr, + OperandTraits<GetElementPtrConstantExpr>::op_end(this) + - (IdxList.size()+1), + IdxList.size()+1) { + OperandList[0].init(C, this); + for (unsigned i = 0, E = IdxList.size(); i != E; ++i) + OperandList[i+1].init(IdxList[i], this); +} + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrConstantExpr, Value) + + +template <> +struct OperandTraits<CompareConstantExpr> : FixedNumOperandTraits<2> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CompareConstantExpr, Value) + + +} // End llvm namespace + // Utility function for determining if a ConstantExpr is a CastOp or not. This // can't be inline because we don't want to #include Instruction.h into @@ -815,17 +873,29 @@ bool ConstantFP::isValueValidForType(const Type *Ty, const APFloat& Val) { //===----------------------------------------------------------------------===// // Factory Function Implementation + +// The number of operands for each ConstantCreator::create method is +// determined by the ConstantTraits template. // ConstantCreator - A class that is used to create constants by // ValueMap*. This class should be partially specialized if there is // something strange that needs to be done to interface to the ctor for the // constant. // namespace llvm { + template<class ValType> + struct ConstantTraits; + + template<typename T, typename Alloc> + struct VISIBILITY_HIDDEN ConstantTraits< std::vector<T, Alloc> > { + static unsigned uses(const std::vector<T, Alloc>& v) { + return v.size(); + } + }; + template<class ConstantClass, class TypeClass, class ValType> struct VISIBILITY_HIDDEN ConstantCreator { static ConstantClass *create(const TypeClass *Ty, const ValType &V) { - unsigned FIXME = 0; // = traits<ValType>::uses(V) - return new(FIXME) ConstantClass(Ty, V); + return new(ConstantTraits<ValType>::uses(V)) ConstantClass(Ty, V); } }; diff --git a/lib/VMCore/Globals.cpp b/lib/VMCore/Globals.cpp index e75b1867a9..1a328d80f6 100644 --- a/lib/VMCore/Globals.cpp +++ b/lib/VMCore/Globals.cpp @@ -89,14 +89,13 @@ GlobalVariable::GlobalVariable(const Type *Ty, bool constant, LinkageTypes Link, Module *ParentModule, bool ThreadLocal, unsigned AddressSpace) : GlobalValue(PointerType::get(Ty, AddressSpace), Value::GlobalVariableVal, - &Initializer, InitVal != 0, Link, Name), + OperandTraits<GlobalVariable>::op_begin(this), + InitVal != 0, Link, Name), isConstantGlobal(constant), isThreadLocalSymbol(ThreadLocal) { if (InitVal) { assert(InitVal->getType() == Ty && "Initializer should be the same type as the GlobalVariable!"); - Initializer.init(InitVal, this); - } else { - Initializer.init(0, this); + Op<0>().init(InitVal, this); } LeakDetector::addGarbageObject(this); @@ -110,14 +109,13 @@ GlobalVariable::GlobalVariable(const Type *Ty, bool constant, LinkageTypes Link, GlobalVariable *Before, bool ThreadLocal, unsigned AddressSpace) : GlobalValue(PointerType::get(Ty, AddressSpace), Value::GlobalVariableVal, - &Initializer, InitVal != 0, Link, Name), + OperandTraits<GlobalVariable>::op_begin(this), + InitVal != 0, Link, Name), isConstantGlobal(constant), isThreadLocalSymbol(ThreadLocal) { if (InitVal) { assert(InitVal->getType() == Ty && "Initializer should be the same type as the GlobalVariable!"); - Initializer.init(InitVal, this); - } else { - Initializer.init(0, this); + Op<0>().init(InitVal, this); } LeakDetector::addGarbageObject(this); @@ -169,12 +167,12 @@ void GlobalVariable::replaceUsesOfWithOnConstant(Value *From, Value *To, GlobalAlias::GlobalAlias(const Type *Ty, LinkageTypes Link, const std::string &Name, Constant* aliasee, Module *ParentModule) - : GlobalValue(Ty, Value::GlobalAliasVal, &Aliasee, 1, Link, Name) { + : GlobalValue(Ty, Value::GlobalAliasVal, &Op<0>(), 1, Link, Name) { LeakDetector::addGarbageObject(this); if (aliasee) assert(aliasee->getType() == Ty && "Alias and aliasee types should match!"); - Aliasee.init(aliasee, this); + Op<0>().init(aliasee, this); if (ParentModule) ParentModule->getAliasList().push_back(this); diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 56bc8167c3..78e7b17a66 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -100,18 +100,21 @@ void CallSite::setDoesNotThrow(bool doesNotThrow) { TerminatorInst::~TerminatorInst() { } +//===----------------------------------------------------------------------===// +// UnaryInstruction Class +//===----------------------------------------------------------------------===// + // Out of line virtual method, so the vtable, etc has a home. UnaryInstruction::~UnaryInstruction() { } - //===----------------------------------------------------------------------===// // PHINode Class //===----------------------------------------------------------------------===// PHINode::PHINode(const PHINode &PN) : Instruction(PN.getType(), Instruction::PHI, - new Use[PN.getNumOperands()], PN.getNumOperands()), + allocHungoffUses(PN.getNumOperands()), PN.getNumOperands()), ReservedSpace(PN.getNumOperands()) { Use *OL = OperandList; for (unsigned i = 0, e = PN.getNumOperands(); i != e; i+=2) { @@ -121,7 +124,7 @@ PHINode::PHINode(const PHINode &PN) } PHINode::~PHINode() { - delete [] OperandList; + dropHungoffUses(OperandList); } // removeIncomingValue - Remove an incoming value. This is useful if a @@ -164,8 +167,9 @@ Value *PHINode::removeIncomingValue(unsigned Idx, bool DeletePHIIfEmpty) { /// 3. If NumOps == NumOperands, trim the reserved space. /// void PHINode::resizeOperands(unsigned NumOps) { + unsigned e = getNumOperands(); if (NumOps == 0) { - NumOps = (getNumOperands())*3/2; + NumOps = e*3/2; if (NumOps < 4) NumOps = 4; // 4 op PHI nodes are VERY common. } else if (NumOps*2 > NumOperands) { // No resize needed. @@ -177,14 +181,13 @@ void PHINode::resizeOperands(unsigned NumOps) { } ReservedSpace = NumOps; - Use *NewOps = new Use[NumOps]; Use *OldOps = OperandList; - for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + Use *NewOps = allocHungoffUses(NumOps); + for (unsigned i = 0; i != e; ++i) { NewOps[i].init(OldOps[i], this); - OldOps[i].set(0); } - delete [] OldOps; OperandList = NewOps; + if (OldOps) Use::zap(OldOps, OldOps + e, true); } /// hasConstantValue - If the specified PHI node always merges together the same @@ -241,12 +244,11 @@ Value *PHINode::hasConstantValue(bool AllowNonDominatingInstruction) const { //===----------------------------------------------------------------------===// CallInst::~CallInst() { - delete [] OperandList; } void CallInst::init(Value *Func, Value* const *Params, unsigned NumParams) { - NumOperands = NumParams+1; - Use *OL = OperandList = new Use[NumParams+1]; + assert(NumOperands == NumParams+1 && "NumOperands not set up?"); + Use *OL = OperandList; OL[0].init(Func, this); const FunctionType *FTy = @@ -265,8 +267,8 @@ void CallInst::init(Value *Func, Value* const *Params, unsigned NumParams) { } void CallInst::init(Value *Func, Value *Actual1, Value *Actual2) { - NumOperands = 3; - Use *OL = OperandList = new Use[3]; + assert(NumOperands == 3 && "NumOperands not set up?"); + Use *OL = OperandList; OL[0].init(Func, this); OL[1].init(Actual1, this); OL[2].init(Actual2, this); @@ -287,8 +289,8 @@ void CallInst::init(Value *Func, Value *Actual1, Value *Actual2) { } void CallInst::init(Value *Func, Value *Actual) { - NumOperands = 2; - Use *OL = OperandList = new Use[2]; + assert(NumOperands == 2 && "NumOperands not set up?"); + Use *OL = OperandList; OL[0].init(Func, this); OL[1].init(Actual, this); @@ -305,8 +307,8 @@ void CallInst::init(Value *Func, Value *Actual) { } void CallInst::init(Value *Func) { - NumOperands = 1; - Use *OL = OperandList = new Use[1]; + assert(NumOperands == 1 && "NumOperands not set up?"); + Use *OL = OperandList; OL[0].init(Func, this); const FunctionType *FTy = @@ -320,7 +322,9 @@ CallInst::CallInst(Value *Func, Value* Actual, const std::string &Name, Instruction *InsertBefore) : Instruction(cast<FunctionType>(cast<PointerType>(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, 0, 0, InsertBefore) { + Instruction::Call, + OperandTraits<CallInst>::op_end(this) - 2, + 2, InsertBefore) { init(Func, Actual); setName(Name); } @@ -329,7 +333,9 @@ CallInst::CallInst(Value *Func, Value* Actual, const std::string &Name, BasicBlock *InsertAtEnd) : Instruction(cast<FunctionType>(cast<PointerType>(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, 0, 0, InsertAtEnd) { + Instruction::Call, + OperandTraits<CallInst>::op_end(this) - 2, + 2, InsertAtEnd) { init(Func, Actual); setName(Name); } @@ -337,7 +343,9 @@ CallInst::CallInst(Value *Func, const std::string &Name, Instruction *InsertBefore) : Instruction(cast<FunctionType>(cast<PointerType>(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, 0, 0, InsertBefore) { + Instruction::Call, + OperandTraits<CallInst>::op_end(this) - 1, + 1, InsertBefore) { init(Func); setName(Name); } @@ -346,13 +354,16 @@ CallInst::CallInst(Value *Func, const std::string &Name, BasicBlock *InsertAtEnd) : Instruction(cast<FunctionType>(cast<PointerType>(Func->getType()) ->getElementType())->getReturnType(), - Instruction::Call, 0, 0, InsertAtEnd) { + Instruction::Call, + OperandTraits<CallInst>::op_end(this) - 1, + 1, InsertAtEnd) { init(Func); setName(Name); } CallInst::CallInst(const CallInst &CI) - : Instruction(CI.getType(), Instruction::Call, new Use[CI.getNumOperands()], + : Instruction(CI.getType(), Instruction::Call, + OperandTraits<CallInst>::op_end(this) - CI.getNumOperands(), CI.getNumOperands()) { setParamAttrs(CI.getParamAttrs()); SubclassData = CI.SubclassData; @@ -384,14 +395,10 @@ void CallInst::setDoesNotThrow(bool doesNotThrow) { // InvokeInst Implementation //===----------------------------------------------------------------------===// -InvokeInst::~InvokeInst() { - delete [] OperandList; -} - void InvokeInst::init(Value *Fn, BasicBlock *IfNormal, BasicBlock *IfException, Value* const *Args, unsigned NumArgs) { - NumOperands = 3+NumArgs; - Use *OL = OperandList = new Use[3+NumArgs]; + assert(NumOperands == 3+NumArgs && "NumOperands not set up?"); + Use *OL = OperandList; OL[0].init(Fn, this); OL[1].init(IfNormal, this); OL[2].init(IfException, this); @@ -414,7 +421,8 @@ void InvokeInst::init(Value *Fn, BasicBlock *IfNormal, BasicBlock *IfException, InvokeInst::InvokeInst(const InvokeInst &II) : TerminatorInst(II.getType(), Instruction::Invoke, - new Use[II.getNumOperands()], II.getNumOperands()) { + OperandTraits<InvokeInst>::op_end(this) - II.getNumOperands(), + II.getNumOperands()) { setParamAttrs(II.getParamAttrs()); SubclassData = II.SubclassData; Use *OL = OperandList, *InOL = II.OperandList; @@ -456,45 +464,51 @@ void InvokeInst::setDoesNotThrow(bool doesNotThrow) { ReturnInst::ReturnInst(const ReturnInst &RI) : TerminatorInst(Type::VoidTy, Instruction::Ret, - &RetVal, RI.getNumOperands()) { + OperandTraits<ReturnInst>::op_end(this) - RI.getNumOperands(), + RI.getNumOperands()) { unsigned N = RI.getNumOperands(); - if (N == 1) - RetVal.init(RI.RetVal, this); + if (N == 1) + Op<0>().init(RI.Op<0>(), this); else if (N) { - Use *OL = OperandList = new Use[N]; + Use *OL = OperandList; for (unsigned i = 0; i < N; ++i) OL[i].init(RI.getOperand(i), this); } } ReturnInst::ReturnInst(Value *retVal, Instruction *InsertBefore) - : TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, 0, InsertBefore) { + : TerminatorInst(Type::VoidTy, Instruction::Ret, + OperandTraits<ReturnInst>::op_end(this) - (retVal != 0), + retVal != 0, InsertBefore) { if (retVal) init(&retVal, 1); } ReturnInst::ReturnInst(Value *retVal, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, 0, InsertAtEnd) { + : TerminatorInst(Type::VoidTy, Instruction::Ret, + OperandTraits<ReturnInst>::op_end(this) - (retVal != 0), + retVal != 0, InsertAtEnd) { if (retVal) init(&retVal, 1); } ReturnInst::ReturnInst(BasicBlock *InsertAtEnd) - : TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, 0, InsertAtEnd) { + : TerminatorInst(Type::VoidTy, Instruction::Ret, + OperandTraits<ReturnInst>::op_end(this), + 0, InsertAtEnd) { } ReturnInst::ReturnInst(Value * const* retVals, unsigned N, Instruction *InsertBefore) - : TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, N, InsertBefore) { + : TerminatorInst(Type::VoidTy, Instruction::Ret, + OperandTraits<ReturnInst>::op_end(this) - N, + N, InsertBefore) { if (N != 0) init(retVals, N); } ReturnInst::ReturnInst(Value * const* retVals, unsigned N, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, N, InsertAtEnd) { - if (N != 0) - init(retVals, N); -} -ReturnInst::ReturnInst(Value * const* retVals, unsigned N) - : TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, N) { + : TerminatorInst(Type::VoidTy, Instruction::Ret, + OperandTraits<ReturnInst>::op_end(this) - N, + N, InsertAtEnd) { if (N != 0) init(retVals, N); } @@ -507,11 +521,11 @@ void ReturnInst::init(Value * const* retVals, unsigned N) { Value *V = *retVals; if (V->getType() == Type::VoidTy) return; - RetVal.init(V, this); + Op<0>().init(V, this); return; } - Use *OL = OperandList = new Use[NumOperands]; + Use *OL = OperandList; for (unsigned i = 0; i < NumOperands; ++i) { Value *V = *retVals++; assert(!isa<BasicBlock>(V) && @@ -537,8 +551,6 @@ BasicBlock *ReturnInst::getSuccessorV(unsigned idx) const { } ReturnInst::~ReturnInst() { - if (NumOperands > 1) - delete [] OperandList; } //===----------------------------------------------------------------------===// @@ -603,33 +615,41 @@ void BranchInst::AssertOK() { } BranchInst::BranchInst(BasicBlock *IfTrue, Instruction *InsertBefore) - : TerminatorInst(Type::VoidTy, Instruction::Br, Ops, 1, InsertBefore) { + : TerminatorInst(Type::VoidTy, Instruction::Br, + OperandTraits<BranchInst>::op_end(this) - 1, + 1, InsertBefore) { assert(IfTrue != 0 && "Branch destination may not be null!"); - Ops[0].init(reinterpret_cast<Value*>(IfTrue), this); + Op<0>().init(reinterpret_cast<Value*>(IfTrue), this); } BranchInst::BranchInst(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, Instruction *InsertBefore) -: TerminatorInst(Type::VoidTy, Instruction::Br, Ops, 3, InsertBefore) { - Ops[0].init(reinterpret_cast<Value*>(IfTrue), this); - Ops[1].init(reinterpret_cast<Value*>(IfFalse), this); - Ops[2].init(Cond, this); + : TerminatorInst(Type::VoidTy, Instruction::Br, + OperandTraits<BranchInst>::op_end(this) - 3, + 3, InsertBefore) { + Op<0>().init(reinterpret_cast<Value*>(IfTrue), this); + Op<1>().init(reinterpret_cast<Value*>(IfFalse), this); + Op<2>().init(Cond, this); #ifndef NDEBUG AssertOK(); #endif } BranchInst::BranchInst(BasicBlock *IfTrue, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::VoidTy, Instruction::Br, Ops, 1, InsertAtEnd) { + : TerminatorInst(Type::VoidTy, Instruction::Br, + OperandTraits<BranchInst>::op_end(this) - 1, + 1, InsertAtEnd) { assert(IfTrue != 0 && "Branch destination may not be null!"); - Ops[0].init(reinterpret_cast<Value*>(IfTrue), this); + Op<0>().init(reinterpret_cast<Value*>(IfTrue), this); } BranchInst::BranchInst(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::VoidTy, Instruction::Br, Ops, 3, InsertAtEnd) { - Ops[0].init(reinterpret_cast<Value*>(IfTrue), this); - Ops[1].init(reinterpret_cast<Value*>(IfFalse), this); - Ops[2].init(Cond, this); + : TerminatorInst(Type::VoidTy, Instruction::Br, + OperandTraits<BranchInst>::op_end(this) - 3, + 3, InsertAtEnd) { + Op<0>().init(reinterpret_cast<Value*>(IfTrue), this); + Op<1>().init(reinterpret_cast<Value*>(IfFalse), this); + Op<2>().init(Cond, this); #ifndef NDEBUG AssertOK(); #endif @@ -637,7 +657,9 @@ BranchInst::BranchInst(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, BranchInst::BranchInst(const BranchInst &BI) : - TerminatorInst(Type::VoidTy, Instruction::Br, Ops, BI.getNumOperands()) { + TerminatorInst(Type::VoidTy, Instruction::Br, + OperandTraits<BranchInst>::op_end(this) - BI.getNumOperands(), + BI.getNumOperands()) { OperandList[0].init(BI.getOperand(0), this); if (BI.getNumOperands() != 1) { assert(BI.getNumOperands() == 3 && "BR can have 1 or 3 operands!"); @@ -869,18 +891,24 @@ void StoreInst::AssertOK() { StoreInst::StoreInst(Value *val, Value *addr, Instruction *InsertBefore) - : Instruction(Type::VoidTy, Store, Ops, 2, InsertBefore) { - Ops[0].init(val, this); - Ops[1].init(addr, this); + : Instruction(Type::VoidTy, Store, + OperandTraits<StoreInst>::op_begin(this), + OperandTraits<StoreInst>::operands(this), + InsertBefore) { + Op<0>().init(val, this); + Op<1>().init(addr, this); setVolatile(false); setAlignment(0); AssertOK(); } StoreInst::StoreInst(Value *val, Value *addr, BasicBlock *InsertAtEnd) - : Instruction(Type::VoidTy, Store, Ops, 2, InsertAtEnd) { - Ops[0].init(val, this); - Ops[1].init(addr, this); + : Instruction(Type::VoidTy, Store, + OperandTraits<StoreInst>::op_begin(this), + OperandTraits<StoreInst>::operands(this), + InsertAtEnd) { + Op<0>().init(val, this); + Op<1>().init(addr, this); setVolatile(false); setAlignment(0); AssertOK(); @@ -888,9 +916,12 @@ StoreInst::StoreInst(Value *val, Value *addr, BasicBlock *InsertAtEnd) StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, Instruction *InsertBefore) - : Instruction(Type::VoidTy, Store, Ops, 2, InsertBefore) { - Ops[0].init(val, this); - Ops[1].init(addr, this); + : Instruction(Type::VoidTy, Store, + OperandTraits<StoreInst>::op_begin(this), + OperandTraits<StoreInst>::operands(this), + InsertBefore) { + Op<0>().init(val, this); + Op<1>().init(addr, this); setVolatile(isVolatile); setAlignment(0); AssertOK(); @@ -898,9 +929,12 @@ StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, unsigned Align, Instruction *InsertBefore) - : Instruction(Type::VoidTy, Store, Ops, 2, InsertBefore) { - Ops[0].init(val, this); - Ops[1].init(addr, this); + : Instruction(Type::VoidTy, Store, + OperandTraits<StoreInst>::op_begin(this), + OperandTraits<StoreInst>::operands(this), + InsertBefore) { + Op<0>().init(val, this); + Op<1>().init(addr, this); setVolatile(isVolatile); setAlignment(Align); AssertOK(); @@ -908,9 +942,12 @@ StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, unsigned Align, BasicBlock *InsertAtEnd) - : Instruction(Type::VoidTy, Store, Ops, 2, InsertAtEnd) { - Ops[0].init(val, this); - Ops[1].init(addr, this); + : Instruction(Type::VoidTy, Store, + OperandTraits<StoreInst>::op_begin(this), + OperandTraits<StoreInst>::operands(this), + InsertAtEnd) { + Op<0>().init(val, this); + Op<1>().init(addr, this); setVolatile(isVolatile); setAlignment(Align); AssertOK(); @@ -918,9 +955,12 @@ StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, BasicBlock *InsertAtEnd) - : Instruction(Type::VoidTy, Store, Ops, 2, InsertAtEnd) { - Ops[0].init(val, this); - Ops[1].init(addr, this); + : Instruction(Type::VoidTy, Store, + OperandTraits<StoreInst>::op_begin(this), + OperandTraits<StoreInst>::operands(this), + InsertAtEnd) { + Op<0>().init(val, this); + Op<1>().init(addr, this); setVolatile(isVolatile); setAlignment(0); AssertOK(); @@ -940,8 +980,8 @@ static unsigned retrieveAddrSpace(const Value *Val) { } void GetElementPtrInst::init(Value *Ptr, Value* const *Idx, unsigned NumIdx) { - NumOperands = 1+NumIdx; - Use *OL = OperandList = new Use[NumOperands]; + assert(NumOperands == 1+NumIdx && "NumOperands not initialized?"); + Use *OL = OperandList; OL[0].init(Ptr, this); for (unsigned i = 0; i != NumIdx; ++i) @@ -949,17 +989,29 @@ void GetElementPtrInst::init(Value *Ptr, Value* const *Idx, unsigned NumIdx) { } void GetElementPtrInst::init(Value *Ptr, Value *Idx) { - NumOperands = 2; - Use *OL = OperandList = new Use[2]; + assert(NumOperands == 2 && "NumOperands not initialized?"); + Use *OL = OperandList; OL[0].init(Ptr, this); OL[1].init(Idx, this); } +GetElementPtrInst::GetElementPtrInst(const GetElementPtrInst &GEPI) + : Instruction(reinterpret_cast<const Type*>(GEPI.getType()), GetElementPtr, + OperandTraits<GetElementPtrInst>::op_end(this) - GEPI.getNumOperands(), + GEPI.getNumOperands()) { + Use *OL = OperandList; + Use *GEPIOL = GEPI.OperandList; + for (unsigned i = 0, E = NumOperands; i != E; ++i) + OL[i].init(GEPIOL[i], this); +} + GetElementPtrInst::GetElementPtrInst(Value *Ptr, Value *Idx, const std::string &Name, Instruction *InBe) : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(),Idx)), retrieveAddrSpace(Ptr)), - GetElementPtr, 0, 0, InBe) { + GetElementPtr, + OperandTraits<GetElementPtrInst>::op_end(this) - 2, + 2, InBe) { init(Ptr, Idx); setName(Name); } @@ -968,15 +1020,13 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, Value *Idx, const std::string &Name, BasicBlock *IAE) : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(),Idx)), retrieveAddrSpace(Ptr)), - GetElementPtr, 0, 0, IAE) { + GetElementPtr, + OperandTraits<GetElementPtrInst>::op_end(this) - 2, + 2, IAE) { init(Ptr, Idx); setName(Name); } -GetElementPtrInst::~GetElementPtrInst() { - delete[] OperandList; -} - // getIndexedType - Returns the type of the element that would be loaded with // a load instruction with the specified parameters. // @@ -1067,11 +1117,13 @@ ExtractElementInst::ExtractElementInst(Value *Val, Value *Index, const std::string &Name, Instruction *InsertBef) : Instruction(cast<VectorType>(Val->getType())->getElementType(), - ExtractElement, Ops, 2, InsertBef) { + ExtractElement, + OperandTraits<ExtractElementInst>::op_begin(this), + 2, InsertBef) { assert(isValidOperands(Val, Index) && "Invalid extractelement instruction operands!"); - Ops[0].init(Val, this); - Ops[1].init(Index, this); + Op<0>().init(Val, this); + Op<1>().init(Index, this); setName(Name); } @@ -1079,12 +1131,14 @@ ExtractElementInst::ExtractElementInst(Value *Val, unsigned IndexV, const std::string &Name, Instruction *InsertBef) : Instruction(cast<VectorType>(Val->getType())->getElementType(), - ExtractElement, Ops, 2, InsertBef) { + ExtractElement, + OperandTraits<ExtractElementInst>::op_begin(this), + 2, InsertBef) { Constant *Index = ConstantInt::get(Type::Int32Ty, IndexV); assert(isValidOperands(Val, Index) && "Invalid extractelement instruction operands!"); - Ops[0].init(Val, this); - Ops[1].init(Index, this); + Op<0>().init(Val, this); + Op<1>().init(Index, this); setName(Name); } @@ -1093,12 +1147,14 @@ ExtractElementInst::ExtractElementInst(Value *Val, Value *Index, const std::string &Name, BasicBlock *InsertAE) : Instruction(cast<VectorType>(Val->getType())->getElementType(), - ExtractElement, Ops, 2, InsertAE) { + ExtractElement, + OperandTraits<ExtractElementInst>::op_begin(this), + 2, InsertAE) { assert(isValidOperands(Val, Index) && "Invalid extractelement instruction operands!"); - Ops[0].init(Val, this); - Ops[1].init(Index, this); + Op<0>().init(Val, this); + Op<1>().init(Index, this); setName(Name); } @@ -1106,13 +1162,15 @@ ExtractElementInst::ExtractElementInst(Value *Val, unsigned IndexV, const std::string &Name, BasicBlock *InsertAE) : Instruction(cast<VectorType>(Val->getType())->getElementType(), - ExtractElement, Ops, 2, InsertAE) { + ExtractElement, + OperandTraits<ExtractElementInst>::op_begin(this), + 2, InsertAE) { Constant *Index = ConstantInt::get(Type::Int32Ty, IndexV); assert(isValidOperands(Val, Index) && "Invalid extractelement instruction operands!"); - Ops[0].init(Val, this); - Ops[1].init(Index, this); + Op<0>().init(Val, this); + Op<1>().init(Index, this); setName(Name); } @@ -1129,33 +1187,38 @@ bool ExtractElementInst::isValidOperands(const Value *Val, const Value *Index) { //===----------------------------------------------------------------------===// InsertElementInst::InsertElementInst(const InsertElementInst &IE) - : Instruction(IE.getType(), InsertElement, Ops, 3) { - Ops[0].init(IE.Ops[0], this); - Ops[1].init(IE.Ops[1], this); - Ops[2].init(IE.Ops[2], this); + : Instruction(IE.getType(), InsertElement, + OperandTraits<InsertElementInst>::op_begin(this), 3) { + Op<0>().init(IE.Op<0>(), this); + Op<1>().init(IE.Op<1>(), this); + Op<2>().init(IE.Op<2>(), this); } InsertElementInst::InsertElementInst(Value *Vec, Value *Elt, Value *Index, const std::string &Name, Instruction *InsertBef) - : Instruction(Vec->getType(), InsertElement, Ops, 3, InsertBef) { + : Instruction(Vec->getType(), InsertElement, + OperandTraits<InsertElementInst>::op_begin(this), + 3, InsertBef) { assert(isValidOperands(Vec, Elt, Index) && "Invalid insertelement instruction operands!"); - Ops[0].init(Vec, this); - Ops[1].init(Elt, this); - Ops[2].init(Index, this); + Op<0>().init(Vec, this); + Op<1>().init(Elt, this); + Op<2>().init(Index, this); setName(Name); } InsertElementInst::InsertElementInst(Value *Vec, Value *Elt, unsigned IndexV, const std::string &Name, Instruction *InsertBef) - : Instruction(Vec->getType(), InsertElement, Ops, 3, InsertBef) { + : Instruction(Vec->getType(), InsertElement, + OperandTraits<InsertElementInst>::op_begin(this), + 3, InsertBef) { Constant *Index = ConstantInt::get(Type::Int32Ty, IndexV); assert(isValidOperands(Vec, Elt, Index) && "Invalid insertelement instruction operands!"); - Ops[0].init(Vec, this); - Ops[1].init(Elt, this); - Ops[2].init(Index, this); + Op<0>().init(Vec, this); + Op<1>().init(Elt, this); + Op<2>().init(Index, this); setName(Name); } @@ -1163,27 +1226,31 @@ InsertElementInst::InsertElementInst(Value *Vec, Value *Elt, unsigned IndexV, InsertElementInst::InsertElementInst(Value *Vec, Value *Elt, Value *Index, const std::string &Name, BasicBlock *InsertAE) - : Instruction(Vec->getType(), InsertElement, Ops, 3, InsertAE) { + : Instruction(Vec->getType(), InsertElement, + OperandTraits<InsertElementInst>::op_begin(this), + 3, InsertAE) { assert(isValidOperands(Vec, Elt, Index) && "Invalid insertelement instruction operands!"); - Ops[0].init(Vec, this); - Ops[1].init(Elt, this); - Ops[2].init(Index, this); + Op<0>().init(Vec, this); + Op<1>().init(Elt, this); + Op<2>().init(Index, this); setName(Name); } InsertElementInst::InsertElementInst(Value *Vec, Value *Elt, unsigned IndexV, const std::string &Name, BasicBlock *InsertAE) -: Instruction(Vec->getType(), InsertElement, Ops, 3, InsertAE) { +: Instruction(Vec->getType(), InsertElement, + OperandTraits<InsertElementInst>::op_begin(this), + 3, InsertAE) { Constant *Index = ConstantInt::get(Type::Int32Ty, IndexV); assert(isValidOperands(Vec, Elt, Index) && "Invalid insertelement instruction operands!"); - Ops[0].init(Vec, this); - Ops[1].init(Elt, this); - Ops[2].init(Index, this); + Op<0>().init(Vec, this); + Op<1>().init(Elt, this); + Op<2>().init(Index, this); setName(Name); } @@ -1206,34 +1273,42 @@ bool InsertElementInst::isValidOperands(const Value *Vec, const Value *Elt, //===----------------------------------------------------------------------===// ShuffleVectorInst::ShuffleVectorInst(const ShuffleVectorInst &SV) - : Instruction(SV.getType(), ShuffleVector, Ops, 3) { - Ops[0].init(SV.Ops[0], this); - Ops[1].init(SV.Ops[1], this); - Ops[2].init(SV.Ops[2], this); + : Instruction(SV.getType(), ShuffleVector, + OperandTraits<ShuffleVectorInst>::op_begin(this), + OperandTraits<ShuffleVectorInst>::operands(this)) { + Op<0>().init(SV.Op<0>(), this); + Op<1>().init(SV.Op<1>(), this); + Op<2>().init(SV.Op<2>(), this); } ShuffleVectorInst::ShuffleVectorInst(Value *V1, Value *V2, Value *Mask, const std::string &Name, Instruction *InsertBefore) - : Instruction(V1->getType(), ShuffleVector, Ops, 3, InsertBefore) { + : Instruction(V1->getType(), ShuffleVector, + OperandTraits<ShuffleVectorInst>::op_begin(this), + OperandTraits<ShuffleVectorInst>::operands(this), + InsertBefore) { assert(isValidOperands(V1, V2, Mask) && "Invalid shuffle vector instruction operands!"); - Ops[0].init(V1, this); - Ops[1].init(V2, this); - Ops[2].init(Mask, this); + Op<0>().init(V1, this); + Op<1>().init(V2, this); + Op<2>().init(Mask, this); setName(Name); } ShuffleVectorInst::ShuffleVectorInst(Value *V1, Value *V2, Value *Mask, const std::string &Name, BasicBlock *InsertAtEnd) - : Instruction(V1->getType(), ShuffleVector, Ops, 3, InsertAtEnd) { + : Instruction(V1->getType(), ShuffleVector, + OperandTraits<ShuffleVectorInst>::op_begin(this), + OperandTraits<ShuffleVectorInst>::operands(this), + InsertAtEnd) { assert(isValidOperands(V1, V2, Mask) && "Invalid shuffle vector instruction operands!"); - Ops[0].init(V1, this); - Ops[1].init(V2, this); - Ops[2].init(Mask, this); + Op<0>().init(V1, this); + Op<1>().init(V2, this); + Op<2>().init(Mask, this); setName(Name); } @@ -1275,9 +1350,12 @@ int ShuffleVectorInst::getMaskValue(unsigned i) const { BinaryOperator::BinaryOperator(BinaryOps iType, Value *S1, Value *S2, const Type *Ty, const std::string &Name, Instruction *InsertBefore) - : Instruction(Ty, iType, Ops, 2, InsertBefore) { - Ops[0].init(S1, this); - Ops[1].init(S2, this); + : Instruction(Ty, iType, + OperandTraits<BinaryOperator>::op_begin(this), + OperandTraits<BinaryOperator>::operands(this), + InsertBefore) { + Op<0>().init(S1, this); + Op<1>().init(S2, this); init(iType); setName(Name); } @@ -1285,9 +1363,12 @@ BinaryOperator::BinaryOperator(BinaryOps iType, Value *S1, Value *S2, BinaryOperator::BinaryOperator(BinaryOps iType, Value *S1, Value *S2, const Type *Ty, const std::string &Name, BasicBlock *InsertAtEnd) - : Instruction(Ty, iType, Ops, 2, InsertAtEnd) { - Ops[0].init(S1, this); - Ops[1].init(S2, this); + : Instruction(Ty, iType, + OperandTraits<BinaryOperator>::op_begin(this), + OperandTraits<BinaryOperator>::operands(this), + InsertAtEnd) { + Op<0>().init(S1, this); + Op<1>().init(S2, this); init(iType); setName(Name); } @@ -1482,7 +1563,7 @@ const Value *BinaryOperator::getNotArgument(const Value *BinOp) { bool BinaryOperator::swapOperands() { if (!isCommutative()) return true; // Can't commute operands - std::swap(Ops[0], Ops[1]); + std::swap(Op<0>(), Op<1>()); return false; } @@ -2254,9 +2335,12 @@ BitCastInst::BitCastInst( CmpInst::CmpInst(OtherOps op, unsigned short predicate, Value *LHS, Value *RHS, const std::string &Name, Instruction *InsertBefore) - : Instruction(Type::Int1Ty, op, Ops, 2, InsertBefore) { - Ops[0].init(LHS, this); - Ops[1].init(RHS, this); + : Instruction(Type::Int1Ty, op, + OperandTraits<CmpInst>::op_begin(this), + OperandTraits<CmpInst>::operands(this), + InsertBefore) { + Op<0>().init(LHS, this); + Op<1>().init(RHS, this); SubclassData = predicate; setName(Name); if (op == Instruction::ICmp) { @@ -2283,12 +2367,15 @@ CmpInst::CmpInst(OtherOps op, unsigned short predicate, Value *LHS, Value *RHS, assert(Op0Ty->isFloatingPoint() && "Invalid operand types for FCmp instruction"); } - + CmpInst::CmpInst(OtherOps op, unsigned short predicate, Value *LHS, Value *RHS, const std::string &Name, BasicBlock *InsertAtEnd) - : Instruction(Type::Int1Ty, op, Ops, 2, InsertAtEnd) { - Ops[0].init(LHS, this); - Ops[1].init(RHS, this); + : Instruction(Type::Int1Ty, op, + OperandTraits<CmpInst>::op_begin(this), + OperandTraits<CmpInst>::operands(this), + InsertAtEnd) { + Op<0>().init(LHS, this); + Op<1>().init(RHS, this); SubclassData = predicate; setName(Name); if (op == Instruction::ICmp) { @@ -2548,7 +2635,7 @@ void SwitchInst::init(Value *Value, BasicBlock *Default, unsigned NumCases) { assert(Value && Default); ReservedSpace = 2+NumCases*2; NumOperands = 2; - OperandList = new Use[ReservedSpace]; + OperandList = allocHungoffUses(ReservedSpace); OperandList[0].init(Value, this); OperandList[1].init(Default, this); @@ -2576,7 +2663,7 @@ SwitchInst::SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, SwitchInst::SwitchInst(const SwitchInst &SI) : TerminatorInst(Type::VoidTy, Instruction::Switch, - new Use[SI.getNumOperands()], SI.getNumOperands()) { + allocHungoffUses(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); @@ -2585,7 +2672,7 @@ SwitchInst::SwitchInst(const SwitchInst &SI) } SwitchInst::~SwitchInst() { - delete [] OperandList; + dropHungoffUses(OperandList); } @@ -2632,13 +2719,14 @@ void SwitchInst::removeCase(unsigned idx) { /// 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. +/// of operation. This grows the number of ops by 3 times. /// 2. If NumOps > NumOperands, reserve space for NumOps operands. /// 3. If NumOps == NumOperands, trim the reserved space. /// void SwitchInst::resizeOperands(unsigned NumOps) { + unsigned e = getNumOperands(); if (NumOps == 0) { - NumOps = getNumOperands()/2*6; + NumOps = e*3; } else if (NumOps*2 > NumOperands) { // No resize needed. if (ReservedSpace >= NumOps) return; @@ -2649,14 +2737,13 @@ void SwitchInst::resizeOperands(unsigned NumOps) { } ReservedSpace = NumOps; - Use *NewOps = new Use[NumOps]; + Use *NewOps = allocHungoffUses(NumOps); Use *OldOps = OperandList; - for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + for (unsigned i = 0; i != e; ++i) { NewOps[i].init(OldOps[i], this); - OldOps[i].set(0); } - delete [] OldOps; OperandList = NewOps; + if (OldOps) Use::zap(OldOps, OldOps + e, true); } @@ -2678,9 +2765,12 @@ GetResultInst::GetResultInst(Value *Aggregate, unsigned Index, const std::string &Name, Instruction *InsertBef) : Instruction(cast<StructType>(Aggregate->getType())->getElementType(Index), - GetResult, &Aggr, 1, InsertBef) { + GetResult, + OperandTraits<GetResultInst>::op_begin(this), + OperandTraits<GetResultInst>::operands(this), + InsertBef) { assert(isValidOperands(Aggregate, Index) && "Invalid GetResultInst operands!"); - Aggr.init(Aggregate, this); + Op<0>().init(Aggregate, this); Idx = Index; setName(Name); } @@ -2714,14 +2804,14 @@ GetElementPtrInst *GetElementPtrInst::clone() const { } BinaryOperator *BinaryOperator::clone() const { - return create(getOpcode(), Ops[0], Ops[1]); + return create(getOpcode(), Op<0>(), Op<1>()); } FCmpInst* FCmpInst::clone() const { - return new FCmpInst(getPredicate(), Ops[0], Ops[1]); + return new FCmpInst(getPredicate(), Op<0>(), Op<1>()); } ICmpInst* ICmpInst::clone() const { - return new ICmpInst(getPredicate(), Ops[0], Ops[1]); + return new ICmpInst(getPredicate(), Op<0>(), Op<1>()); } MallocInst *MallocInst::clone() const { return new MallocInst(*this); } @@ -2757,7 +2847,7 @@ ShuffleVectorInst *ShuffleVectorInst::clone() const { PHINode *PHINode::clone() const { return new PHINode(*this); } ReturnInst *ReturnInst::clone() const { return new(getNumOperands()) ReturnInst(*this); } BranchInst *BranchInst::clone() const { return new(getNumOperands()) BranchInst(*this); } -SwitchInst *SwitchInst::clone() const { return new(getNumOperands()) SwitchInst(*this); } +SwitchInst *SwitchInst::clone() const { return new SwitchInst(*this); } InvokeInst *InvokeInst::clone() const { return new(getNumOperands()) InvokeInst(*this); } UnwindInst *UnwindInst::clone() const { return new UnwindInst(); } UnreachableInst *UnreachableInst::clone() const { return new UnreachableInst();} diff --git a/lib/VMCore/Use.cpp b/lib/VMCore/Use.cpp new file mode 100644 index 0000000000..a510d1a41c --- /dev/null +++ b/lib/VMCore/Use.cpp @@ -0,0 +1,131 @@ +//===-- Use.cpp - Implement the Use class -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the algorithm for finding the User of a Use. +// +//===----------------------------------------------------------------------===// + +#include "llvm/User.h" + +namespace llvm { + +//===----------------------------------------------------------------------===// +// Use getImpliedUser Implementation +//===----------------------------------------------------------------------===// + +const Use *Use::getImpliedUser() const { + const Use *Current = this; + + while (true) { + unsigned Tag = extractTag<PrevPtrTag, fullStopTag>((Current++)->Prev); + switch (Tag) { + case zeroDigitTag: + case oneDigitTag: + continue; + + case stopTag: { + ++Current; + ptrdiff_t Offset = 1; + while (true) { + unsigned Tag = extractTag<PrevPtrTag, fullStopTag>(Current->Prev); + switch (Tag) { + case zeroDigitTag: + case oneDigitTag: + ++Current; + Offset = (Offset << 1) + Tag; + continue; + default: + return Current + Offset; + } + } + } + + case fullStopTag: + return Current; + } + } +} + +//===----------------------------------------------------------------------===// +// Use initTags Implementation +//===----------------------------------------------------------------------===// + +Use *Use::initTags(Use * const Start, Use *Stop, ptrdiff_t Done) { + ptrdiff_t Count = Done; + while (Start != Stop) { + --Stop; + Stop->Val = 0; + if (!Count) { + Stop->Prev = reinterpret_cast<Use**>(Done == 0 ? fullStopTag : stopTag); + ++Done; + Count = Done; + } else { + Stop->Prev = reinterpret_cast<Use**>(Count & 1); + Count >>= 1; + ++Done; + } + } + + return Start; +} + +//===----------------------------------------------------------------------===// +// Use zap Implementation +//===----------------------------------------------------------------------===// + +void Use::zap(Use *Start, const Use *Stop, bool del) { + if (del) { + while (Start != Stop) { + (--Stop)->~Use(); + } + ::operator delete(Start); + return; + } + + while (Start != Stop) { + (Start++)->set(0); + } +} + +//===----------------------------------------------------------------------===// +// AugmentedUse layout struct +//===----------------------------------------------------------------------===// + +struct AugmentedUse : Use { + User *ref; + AugmentedUse(); // not implemented +}; + + +//===----------------------------------------------------------------------===// +// Use getUser Implementation +//===----------------------------------------------------------------------===// + +User *Use::getUser() const { + const Use *End = getImpliedUser(); + User *She = static_cast<const AugmentedUse*>(End - 1)->ref; + She = extractTag<Tag, tagOne>(She) + ? llvm::stripTag<tagOne>(She) + : reinterpret_cast<User*>(const_cast<Use*>(End)); + + return She; +} + +//===----------------------------------------------------------------------===// +// User allocHungoffUses Implementation +//===----------------------------------------------------------------------===// + +Use *User::allocHungoffUses(unsigned N) const { + Use *Begin = static_cast<Use*>(::operator new(sizeof(Use) * N + sizeof(AugmentedUse) - sizeof(Use))); + Use *End = Begin + N; + static_cast<AugmentedUse&>(End[-1]).ref = addTag(this, tagOne); + return Use::initTags(Begin, End); +} + +} // End llvm namespace |