X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FIR%2FUser.h;h=78a3b43c86d25de29ca4bed28e0d84499c4abad7;hb=2b762697564ca1e12e0e974e93ceeb4c3420505c;hp=df6034d0b481546023099ecad32e8f1a901733ab;hpb=0aae8ce09fd6c337b5c4398eadcad75e7bb3eda2;p=oota-llvm.git diff --git a/include/llvm/IR/User.h b/include/llvm/IR/User.h index df6034d0b48..78a3b43c86d 100644 --- a/include/llvm/IR/User.h +++ b/include/llvm/IR/User.h @@ -19,9 +19,11 @@ #ifndef LLVM_IR_USER_H #define LLVM_IR_USER_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Value.h" +#include "llvm/Support/AlignOf.h" #include "llvm/Support/ErrorHandling.h" namespace llvm { @@ -34,38 +36,58 @@ struct OperandTraits; class User : public Value { User(const User &) = delete; - void *operator new(size_t) = delete; template friend struct HungoffOperandTraits; virtual void anchor(); + + LLVM_ATTRIBUTE_ALWAYS_INLINE inline static void * + allocateFixedOperandUser(size_t, unsigned, unsigned); + protected: - /// \brief This is a pointer to the array of Uses for this User. + /// Allocate a User with an operand pointer co-allocated. + /// + /// This is used for subclasses which need to allocate a variable number + /// of operands, ie, 'hung off uses'. + void *operator new(size_t Size); + + /// Allocate a User with the operands co-allocated. /// - /// For nodes of fixed arity (e.g. a binary operator) this array will live - /// prefixed to some derived class instance. 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; + /// This is used for subclasses which have a fixed number of operands. + void *operator new(size_t Size, unsigned Us); - void *operator new(size_t s, unsigned Us); - User(Type *ty, unsigned vty, Use *OpList, unsigned NumOps) - : Value(ty, vty), OperandList(OpList) { - NumOperands = NumOps; + /// Allocate a User with the operands co-allocated. If DescBytes is non-zero + /// then allocate an additional DescBytes bytes before the operands. These + /// bytes can be accessed by calling getDescriptor. + /// + /// DescBytes needs to be divisible by sizeof(void *). The allocated + /// descriptor, if any, is aligned to sizeof(void *) bytes. + /// + /// This is used for subclasses which have a fixed number of operands. + void *operator new(size_t Size, unsigned Us, unsigned DescBytes); + + User(Type *ty, unsigned vty, Use *, unsigned NumOps) + : Value(ty, vty) { + assert(NumOps < (1u << NumUserOperandsBits) && "Too many operands"); + NumUserOperands = NumOps; + // If we have hung off uses, then the operand list should initially be + // null. + assert((!HasHungOffUses || !getOperandList()) && + "Error in initializing hung off uses for User"); } /// \brief Allocate the array of Uses, followed by a pointer /// (with bottom bit set) to the User. /// \param IsPhi identifies callers which are phi nodes and which need /// N BasicBlock* allocated along with N - Use *allocHungoffUses(unsigned N, bool IsPhi = false); - void dropHungoffUses() { - Use::zap(OperandList, OperandList + NumOperands, true); - OperandList = nullptr; - // Reset NumOperands so User::operator delete() does the right thing. - NumOperands = 0; - } + void allocHungoffUses(unsigned N, bool IsPhi = false); + + /// \brief Grow the number of hung off uses. Note that allocHungoffUses + /// should be called if there are no uses. + void growHungoffUses(unsigned N, bool IsPhi = false); + public: - ~User() override { Use::zap(OperandList, OperandList + NumOperands); } + ~User() override { + } /// \brief Free memory allocated for User and Use objects. void operator delete(void *Usr); /// \brief Placement delete - required by std, but never called. @@ -88,28 +110,87 @@ protected: template const Use &Op() const { return OpFrom(this); } +private: + Use *&getHungOffOperands() { return *(reinterpret_cast(this) - 1); } + + Use *getIntrusiveOperands() { + return reinterpret_cast(this) - NumUserOperands; + } + + void setOperandList(Use *NewList) { + assert(HasHungOffUses && + "Setting operand list only required for hung off uses"); + getHungOffOperands() = NewList; + } public: + Use *getOperandList() { + return HasHungOffUses ? getHungOffOperands() : getIntrusiveOperands(); + } + const Use *getOperandList() const { + return const_cast(this)->getOperandList(); + } Value *getOperand(unsigned i) const { - assert(i < NumOperands && "getOperand() out of range!"); - return OperandList[i]; + assert(i < NumUserOperands && "getOperand() out of range!"); + return getOperandList()[i]; } void setOperand(unsigned i, Value *Val) { - assert(i < NumOperands && "setOperand() out of range!"); + assert(i < NumUserOperands && "setOperand() out of range!"); assert((!isa((const Value*)this) || isa((const Value*)this)) && "Cannot mutate a constant with setOperand!"); - OperandList[i] = Val; + getOperandList()[i] = Val; } const Use &getOperandUse(unsigned i) const { - assert(i < NumOperands && "getOperandUse() out of range!"); - return OperandList[i]; + assert(i < NumUserOperands && "getOperandUse() out of range!"); + return getOperandList()[i]; } Use &getOperandUse(unsigned i) { - assert(i < NumOperands && "getOperandUse() out of range!"); - return OperandList[i]; + assert(i < NumUserOperands && "getOperandUse() out of range!"); + return getOperandList()[i]; } - unsigned getNumOperands() const { return NumOperands; } + unsigned getNumOperands() const { return NumUserOperands; } + + /// Returns the descriptor co-allocated with this User instance. + ArrayRef getDescriptor() const; + + /// Returns the descriptor co-allocated with this User instance. + MutableArrayRef getDescriptor(); + + /// Set the number of operands on a GlobalVariable. + /// + /// GlobalVariable always allocates space for a single operands, but + /// doesn't always use it. + /// + /// FIXME: As that the number of operands is used to find the start of + /// the allocated memory in operator delete, we need to always think we have + /// 1 operand before delete. + void setGlobalVariableNumOperands(unsigned NumOps) { + assert(NumOps <= 1 && "GlobalVariable can only have 0 or 1 operands"); + NumUserOperands = NumOps; + } + + /// Set the number of operands on a Function. + /// + /// Function always allocates space for a single operands, but + /// doesn't always use it. + /// + /// FIXME: As that the number of operands is used to find the start of + /// the allocated memory in operator delete, we need to always think we have + /// 1 operand before delete. + void setFunctionNumOperands(unsigned NumOps) { + assert(NumOps <= 1 && "Function can only have 0 or 1 operands"); + NumUserOperands = NumOps; + } + + /// \brief Subclasses with hung off uses need to manage the operand count + /// themselves. In these instances, the operand count isn't used to find the + /// OperandList, so there's no issue in having the operand count change. + void setNumHungOffUseOperands(unsigned NumOps) { + assert(HasHungOffUses && "Must have hung off uses to use this method"); + assert(NumOps < (1u << NumUserOperandsBits) && "Too many operands"); + NumUserOperands = NumOps; + } // --------------------------------------------------------------------------- // Operand Iterator interface... @@ -119,14 +200,18 @@ public: typedef iterator_range op_range; typedef iterator_range const_op_range; - inline op_iterator op_begin() { return OperandList; } - inline const_op_iterator op_begin() const { return OperandList; } - inline op_iterator op_end() { return OperandList+NumOperands; } - inline const_op_iterator op_end() const { return OperandList+NumOperands; } - inline op_range operands() { + op_iterator op_begin() { return getOperandList(); } + const_op_iterator op_begin() const { return getOperandList(); } + op_iterator op_end() { + return getOperandList() + NumUserOperands; + } + const_op_iterator op_end() const { + return getOperandList() + NumUserOperands; + } + op_range operands() { return op_range(op_begin(), op_end()); } - inline const_op_range operands() const { + const_op_range operands() const { return const_op_range(op_begin(), op_end()); } @@ -141,13 +226,13 @@ public: Value *operator->() const { return operator*(); } }; - inline value_op_iterator value_op_begin() { + value_op_iterator value_op_begin() { return value_op_iterator(op_begin()); } - inline value_op_iterator value_op_end() { + value_op_iterator value_op_end() { return value_op_iterator(op_end()); } - inline iterator_range operand_values() { + iterator_range operand_values() { return iterator_range(value_op_begin(), value_op_end()); } @@ -175,6 +260,11 @@ public: return isa(V) || isa(V); } }; +// Either Use objects, or a Use pointer can be prepended to User. +static_assert(AlignOf::Alignment >= AlignOf::Alignment, + "Alignment is insufficient after objects prepended to User"); +static_assert(AlignOf::Alignment >= AlignOf::Alignment, + "Alignment is insufficient after objects prepended to User"); template<> struct simplify_type { typedef Value* SimpleType;