X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FIR%2FUser.h;h=885ae197d2283439bd58f57081db81fa369064d2;hb=638b75bca2096456dce341ddc159d038c7e94712;hp=abe68221df7b0f5a0088111f587a8beeaf0d4e77;hpb=ec0f0bc6afa8d2c1f427ec55264fc78738b83ef6;p=oota-llvm.git diff --git a/include/llvm/IR/User.h b/include/llvm/IR/User.h index abe68221df7..885ae197d22 100644 --- a/include/llvm/IR/User.h +++ b/include/llvm/IR/User.h @@ -19,57 +19,82 @@ #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 { -/// OperandTraits - Compile-time customization of -/// operand-related allocators and accessors -/// for use of the User class +/// \brief Compile-time customization of User operands. +/// +/// Customizes operand-related allocators and accessors. template struct OperandTraits; class User : public Value { - User(const User &) LLVM_DELETED_FUNCTION; - void *operator new(size_t) LLVM_DELETED_FUNCTION; + User(const User &) = delete; template friend struct HungoffOperandTraits; virtual void anchor(); + + LLVM_ATTRIBUTE_ALWAYS_INLINE inline static void * + allocateFixedOperandUser(size_t, unsigned, unsigned); + protected: - /// OperandList - This is a pointer to the array of Uses for this User. - /// 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; - - /// NumOperands - The number of values used by 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. /// - unsigned NumOperands; - - void *operator new(size_t s, unsigned Us); - User(Type *ty, unsigned vty, Use *OpList, unsigned NumOps) - : Value(ty, vty), OperandList(OpList), NumOperands(NumOps) {} - Use *allocHungoffUses(unsigned) const; - void dropHungoffUses() { - Use::zap(OperandList, OperandList + NumOperands, true); - OperandList = nullptr; - // Reset NumOperands so User::operator delete() does the right thing. - NumOperands = 0; + /// This is used for subclasses which have a fixed number of operands. + void *operator new(size_t Size, unsigned Us); + + /// 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 + 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() { - Use::zap(OperandList, OperandList + NumOperands); + ~User() override { } - /// operator delete - free memory allocated for User and Use objects + /// \brief Free memory allocated for User and Use objects. void operator delete(void *Usr); - /// placement delete - required by std, but never called. + /// \brief Placement delete - required by std, but never called. void operator delete(void*, unsigned) { llvm_unreachable("Constructor throws?"); } - /// placement delete - required by std, but never called. + /// \brief Placement delete - required by std, but never called. void operator delete(void*, unsigned, bool) { llvm_unreachable("Constructor throws?"); } @@ -85,28 +110,74 @@ 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 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; } - unsigned getNumOperands() const { return NumOperands; } + /// \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... @@ -116,75 +187,59 @@ 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()); } - /// Convenience iterator for directly iterating over the Values in the - /// OperandList - class value_op_iterator : public std::iterator { - op_iterator OI; - public: - explicit value_op_iterator(Use *U) : OI(U) {} - - bool operator==(const value_op_iterator &x) const { - return OI == x.OI; - } - bool operator!=(const value_op_iterator &x) const { - return !operator==(x); - } - - /// Iterator traversal: forward iteration only - value_op_iterator &operator++() { // Preincrement - ++OI; - return *this; - } - value_op_iterator operator++(int) { // Postincrement - value_op_iterator tmp = *this; ++*this; return tmp; - } - - /// Retrieve a pointer to the current Value. - Value *operator*() const { - return *OI; - } + /// \brief Iterator for directly iterating over the operand Values. + struct value_op_iterator + : iterator_adaptor_base { + explicit value_op_iterator(Use *U = nullptr) : iterator_adaptor_base(U) {} + Value *operator*() const { return *I; } 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() { - return iterator_range(value_op_begin(), value_op_end()); + iterator_range operand_values() { + return make_range(value_op_begin(), value_op_end()); } - // dropAllReferences() - This function is in charge of "letting go" of all - // objects that this User refers to. This allows one to - // 'delete' a whole class at a time, even though there may be circular - // references... First all references are dropped, and all use counts go to - // zero. Then everything is deleted for real. Note that no operations are - // valid on an object that has "dropped all references", except operator - // delete. - // + /// \brief Drop all references to operands. + /// + /// This function is in charge of "letting go" of all objects that this User + /// refers to. This allows one to 'delete' a whole class at a time, even + /// though there may be circular references... First all references are + /// dropped, and all use counts go to zero. Then everything is deleted for + /// real. Note that no operations are valid on an object that has "dropped + /// all references", except operator delete. void dropAllReferences() { for (Use &U : operands()) U.set(nullptr); } - /// replaceUsesOfWith - Replaces all references to the "From" definition with - /// references to the "To" definition. + /// \brief Replace uses of one Value with another. /// + /// Replaces all references to the "From" definition with references to the + /// "To" definition. void replaceUsesOfWith(Value *From, Value *To); // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -192,6 +247,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;