[IR] Move optional data in llvm::Function into a hungoff uselist
[oota-llvm.git] / include / llvm / IR / User.h
index 743eefb707790914e7f0bea80903be6b6e810636..885ae197d2283439bd58f57081db81fa369064d2 100644 (file)
 #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 {
@@ -37,14 +39,9 @@ class User : public Value {
   template <unsigned>
   friend struct HungoffOperandTraits;
   virtual void anchor();
-protected:
-  /// \brief 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 *LegacyOperandList;
+
+  LLVM_ATTRIBUTE_ALWAYS_INLINE inline static void *
+  allocateFixedOperandUser(size_t, unsigned, unsigned);
 
 protected:
   /// Allocate a User with an operand pointer co-allocated.
@@ -58,11 +55,24 @@ protected:
   /// This is used for subclasses which have a fixed number of operands.
   void *operator new(size_t Size, unsigned Us);
 
-  User(Type *ty, unsigned vty, Use *OpList, unsigned 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) {
-    setOperandList(OpList);
     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
@@ -77,14 +87,6 @@ protected:
 
 public:
   ~User() override {
-    // drop the hung off uses.
-    Use::zap(getOperandList(), getOperandList() + NumUserOperands,
-             HasHungOffUses);
-    if (HasHungOffUses) {
-      setOperandList(nullptr);
-      // Reset NumOperands so User::operator delete() does the right thing.
-      NumUserOperands = 0;
-    }
   }
   /// \brief Free memory allocated for User and Use objects.
   void operator delete(void *Usr);
@@ -109,12 +111,23 @@ protected:
     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) {
-    LegacyOperandList = NewList;
+    assert(HasHungOffUses &&
+           "Setting operand list only required for hung off uses");
+    getHungOffOperands() = NewList;
   }
 public:
-  Use *getOperandList() const {
-    return LegacyOperandList;
+  Use *getOperandList() {
+    return HasHungOffUses ? getHungOffOperands() : getIntrusiveOperands();
+  }
+  const Use *getOperandList() const {
+    return const_cast<User *>(this)->getOperandList();
   }
   Value *getOperand(unsigned i) const {
     assert(i < NumUserOperands && "getOperand() out of range!");
@@ -138,6 +151,12 @@ public:
 
   unsigned getNumOperands() const { return NumUserOperands; }
 
+  /// Returns the descriptor co-allocated with this User instance.
+  ArrayRef<const uint8_t> getDescriptor() const;
+
+  /// Returns the descriptor co-allocated with this User instance.
+  MutableArrayRef<uint8_t> getDescriptor();
+
   /// Set the number of operands on a GlobalVariable.
   ///
   /// GlobalVariable always allocates space for a single operands, but
@@ -168,18 +187,18 @@ public:
   typedef iterator_range<op_iterator> op_range;
   typedef iterator_range<const_op_iterator> const_op_range;
 
-  inline op_iterator       op_begin()       { return getOperandList(); }
-  inline const_op_iterator op_begin() const { return getOperandList(); }
-  inline op_iterator       op_end()         {
+  op_iterator       op_begin()       { return getOperandList(); }
+  const_op_iterator op_begin() const { return getOperandList(); }
+  op_iterator       op_end()         {
     return getOperandList() + NumUserOperands;
   }
-  inline const_op_iterator op_end()   const {
+  const_op_iterator op_end()   const {
     return getOperandList() + NumUserOperands;
   }
-  inline op_range operands() {
+  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());
   }
 
@@ -194,14 +213,14 @@ 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() {
-    return iterator_range<value_op_iterator>(value_op_begin(), value_op_end());
+  iterator_range<value_op_iterator> operand_values() {
+    return make_range(value_op_begin(), value_op_end());
   }
 
   /// \brief Drop all references to operands.
@@ -228,6 +247,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;