diff options
Diffstat (limited to 'include/llvm/IR/User.h')
-rw-r--r-- | include/llvm/IR/User.h | 149 |
1 files changed, 112 insertions, 37 deletions
diff --git a/include/llvm/IR/User.h b/include/llvm/IR/User.h index 455900566afd..41d57703ab01 100644 --- a/include/llvm/IR/User.h +++ b/include/llvm/IR/User.h @@ -22,6 +22,7 @@ #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,33 +35,45 @@ struct OperandTraits; class User : public Value { User(const User &) = delete; - void *operator new(size_t) = delete; template <unsigned> friend struct HungoffOperandTraits; virtual void anchor(); + 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; - } - 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; + : 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() 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. @@ -83,28 +96,81 @@ protected: template <int Idx> const Use &Op() const { return OpFrom<Idx>(this); } +private: + Use *&getHungOffOperands() { return *(reinterpret_cast<Use **>(this) - 1); } + + Use *getIntrusiveOperands() { + return reinterpret_cast<Use *>(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<User *>(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<Constant>((const Value*)this) || isa<GlobalValue>((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; } + + /// 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... @@ -114,14 +180,18 @@ public: typedef iterator_range<op_iterator> op_range; typedef iterator_range<const_op_iterator> 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()); } @@ -136,13 +206,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<value_op_iterator> operand_values() { + iterator_range<value_op_iterator> operand_values() { return iterator_range<value_op_iterator>(value_op_begin(), value_op_end()); } @@ -170,6 +240,11 @@ public: return isa<Instruction>(V) || isa<Constant>(V); } }; +// Either Use objects, or a Use pointer can be prepended to User. +static_assert(AlignOf<Use>::Alignment >= AlignOf<User>::Alignment, + "Alignment is insufficient after objects prepended to User"); +static_assert(AlignOf<Use *>::Alignment >= AlignOf<User>::Alignment, + "Alignment is insufficient after objects prepended to User"); template<> struct simplify_type<User::op_iterator> { typedef Value* SimpleType; @@ -184,6 +259,6 @@ template<> struct simplify_type<User::const_op_iterator> { } }; -} // End llvm namespace +} // namespace llvm #endif |