#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 {
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.
/// 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
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);
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!");
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
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());
}
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.
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;