aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/IR/User.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/IR/User.h')
-rw-r--r--include/llvm/IR/User.h149
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