File indexing completed on 2026-05-10 08:44:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #ifndef LLVM_IR_USER_H
0019 #define LLVM_IR_USER_H
0020
0021 #include "llvm/ADT/iterator.h"
0022 #include "llvm/ADT/iterator_range.h"
0023 #include "llvm/IR/Use.h"
0024 #include "llvm/IR/Value.h"
0025 #include "llvm/Support/Casting.h"
0026 #include "llvm/Support/Compiler.h"
0027 #include "llvm/Support/ErrorHandling.h"
0028 #include <cassert>
0029 #include <cstddef>
0030 #include <cstdint>
0031 #include <iterator>
0032
0033 namespace llvm {
0034
0035 template <typename T> class ArrayRef;
0036 template <typename T> class MutableArrayRef;
0037
0038
0039
0040
0041 template <class>
0042 struct OperandTraits;
0043
0044 class User : public Value {
0045 friend struct HungoffOperandTraits;
0046 template <class ConstantClass> friend struct ConstantAggrKeyType;
0047
0048 LLVM_ATTRIBUTE_ALWAYS_INLINE static void *
0049 allocateFixedOperandUser(size_t, unsigned, unsigned);
0050
0051 protected:
0052
0053
0054 void *operator new(size_t Size) = delete;
0055
0056
0057 struct HungOffOperandsAllocMarker {};
0058
0059
0060 struct IntrusiveOperandsAllocMarker {
0061
0062 const unsigned NumOps;
0063 };
0064
0065
0066 struct IntrusiveOperandsAndDescriptorAllocMarker {
0067
0068 const unsigned NumOps;
0069
0070
0071 const unsigned DescBytes;
0072 };
0073
0074
0075
0076
0077
0078
0079 struct AllocInfo {
0080 public:
0081 const unsigned NumOps : NumUserOperandsBits;
0082 const bool HasHungOffUses : 1;
0083 const bool HasDescriptor : 1;
0084
0085 AllocInfo() = delete;
0086
0087 constexpr AllocInfo(const HungOffOperandsAllocMarker)
0088 : NumOps(0), HasHungOffUses(true), HasDescriptor(false) {}
0089
0090 constexpr AllocInfo(const IntrusiveOperandsAllocMarker Alloc)
0091 : NumOps(Alloc.NumOps), HasHungOffUses(false), HasDescriptor(false) {}
0092
0093 constexpr AllocInfo(const IntrusiveOperandsAndDescriptorAllocMarker Alloc)
0094 : NumOps(Alloc.NumOps), HasHungOffUses(false),
0095 HasDescriptor(Alloc.DescBytes != 0) {}
0096 };
0097
0098
0099
0100
0101
0102 void *operator new(size_t Size, HungOffOperandsAllocMarker);
0103
0104
0105
0106
0107 void *operator new(size_t Size, IntrusiveOperandsAllocMarker allocTrait);
0108
0109
0110
0111
0112 void *operator new(size_t Size,
0113 IntrusiveOperandsAndDescriptorAllocMarker allocTrait);
0114
0115 User(Type *ty, unsigned vty, AllocInfo AllocInfo) : Value(ty, vty) {
0116 assert(AllocInfo.NumOps < (1u << NumUserOperandsBits) &&
0117 "Too many operands");
0118 NumUserOperands = AllocInfo.NumOps;
0119 assert((!AllocInfo.HasDescriptor || !AllocInfo.HasHungOffUses) &&
0120 "Cannot have both hung off uses and a descriptor");
0121 HasHungOffUses = AllocInfo.HasHungOffUses;
0122 HasDescriptor = AllocInfo.HasDescriptor;
0123
0124
0125 assert((!AllocInfo.HasHungOffUses || !getOperandList()) &&
0126 "Error in initializing hung off uses for User");
0127 }
0128
0129
0130
0131
0132
0133 void allocHungoffUses(unsigned N, bool IsPhi = false);
0134
0135
0136
0137 void growHungoffUses(unsigned N, bool IsPhi = false);
0138
0139 protected:
0140 ~User() = default;
0141
0142 public:
0143 User(const User &) = delete;
0144
0145
0146 void operator delete(void *Usr);
0147
0148 void operator delete(void *Usr, HungOffOperandsAllocMarker) {
0149
0150
0151
0152
0153
0154 User::operator delete(Usr);
0155
0156 #ifndef LLVM_ENABLE_EXCEPTIONS
0157 llvm_unreachable("Constructor throws?");
0158 #endif
0159 }
0160
0161 void operator delete(void *Usr, IntrusiveOperandsAllocMarker) {
0162
0163
0164
0165
0166 User::operator delete(Usr);
0167
0168 #ifndef LLVM_ENABLE_EXCEPTIONS
0169 llvm_unreachable("Constructor throws?");
0170 #endif
0171 }
0172
0173 void operator delete(void *Usr, IntrusiveOperandsAndDescriptorAllocMarker) {
0174
0175
0176
0177
0178 User::operator delete(Usr);
0179
0180 #ifndef LLVM_ENABLE_EXCEPTIONS
0181 llvm_unreachable("Constructor throws?");
0182 #endif
0183 }
0184
0185 protected:
0186 template <int Idx, typename U> static Use &OpFrom(const U *that) {
0187 return Idx < 0
0188 ? OperandTraits<U>::op_end(const_cast<U*>(that))[Idx]
0189 : OperandTraits<U>::op_begin(const_cast<U*>(that))[Idx];
0190 }
0191
0192 template <int Idx> Use &Op() {
0193 return OpFrom<Idx>(this);
0194 }
0195 template <int Idx> const Use &Op() const {
0196 return OpFrom<Idx>(this);
0197 }
0198
0199 private:
0200 const Use *getHungOffOperands() const {
0201 return *(reinterpret_cast<const Use *const *>(this) - 1);
0202 }
0203
0204 Use *&getHungOffOperands() { return *(reinterpret_cast<Use **>(this) - 1); }
0205
0206 const Use *getIntrusiveOperands() const {
0207 return reinterpret_cast<const Use *>(this) - NumUserOperands;
0208 }
0209
0210 Use *getIntrusiveOperands() {
0211 return reinterpret_cast<Use *>(this) - NumUserOperands;
0212 }
0213
0214 void setOperandList(Use *NewList) {
0215 assert(HasHungOffUses &&
0216 "Setting operand list only required for hung off uses");
0217 getHungOffOperands() = NewList;
0218 }
0219
0220 public:
0221 const Use *getOperandList() const {
0222 return HasHungOffUses ? getHungOffOperands() : getIntrusiveOperands();
0223 }
0224 Use *getOperandList() {
0225 return const_cast<Use *>(static_cast<const User *>(this)->getOperandList());
0226 }
0227
0228 Value *getOperand(unsigned i) const {
0229 assert(i < NumUserOperands && "getOperand() out of range!");
0230 return getOperandList()[i];
0231 }
0232
0233 void setOperand(unsigned i, Value *Val) {
0234 assert(i < NumUserOperands && "setOperand() out of range!");
0235 assert((!isa<Constant>((const Value*)this) ||
0236 isa<GlobalValue>((const Value*)this)) &&
0237 "Cannot mutate a constant with setOperand!");
0238 getOperandList()[i] = Val;
0239 }
0240
0241 const Use &getOperandUse(unsigned i) const {
0242 assert(i < NumUserOperands && "getOperandUse() out of range!");
0243 return getOperandList()[i];
0244 }
0245 Use &getOperandUse(unsigned i) {
0246 assert(i < NumUserOperands && "getOperandUse() out of range!");
0247 return getOperandList()[i];
0248 }
0249
0250 unsigned getNumOperands() const { return NumUserOperands; }
0251
0252
0253 ArrayRef<const uint8_t> getDescriptor() const;
0254
0255
0256 MutableArrayRef<uint8_t> getDescriptor();
0257
0258
0259
0260
0261 void setNumHungOffUseOperands(unsigned NumOps) {
0262 assert(HasHungOffUses && "Must have hung off uses to use this method");
0263 assert(NumOps < (1u << NumUserOperandsBits) && "Too many operands");
0264 NumUserOperands = NumOps;
0265 }
0266
0267
0268
0269
0270 bool isDroppable() const;
0271
0272
0273
0274
0275 using op_iterator = Use*;
0276 using const_op_iterator = const Use*;
0277 using op_range = iterator_range<op_iterator>;
0278 using const_op_range = iterator_range<const_op_iterator>;
0279
0280 op_iterator op_begin() { return getOperandList(); }
0281 const_op_iterator op_begin() const { return getOperandList(); }
0282 op_iterator op_end() {
0283 return getOperandList() + NumUserOperands;
0284 }
0285 const_op_iterator op_end() const {
0286 return getOperandList() + NumUserOperands;
0287 }
0288 op_range operands() {
0289 return op_range(op_begin(), op_end());
0290 }
0291 const_op_range operands() const {
0292 return const_op_range(op_begin(), op_end());
0293 }
0294
0295
0296 struct value_op_iterator
0297 : iterator_adaptor_base<value_op_iterator, op_iterator,
0298 std::random_access_iterator_tag, Value *,
0299 ptrdiff_t, Value *, Value *> {
0300 explicit value_op_iterator(Use *U = nullptr) : iterator_adaptor_base(U) {}
0301
0302 Value *operator*() const { return *I; }
0303 Value *operator->() const { return operator*(); }
0304 };
0305
0306 value_op_iterator value_op_begin() {
0307 return value_op_iterator(op_begin());
0308 }
0309 value_op_iterator value_op_end() {
0310 return value_op_iterator(op_end());
0311 }
0312 iterator_range<value_op_iterator> operand_values() {
0313 return make_range(value_op_begin(), value_op_end());
0314 }
0315
0316 struct const_value_op_iterator
0317 : iterator_adaptor_base<const_value_op_iterator, const_op_iterator,
0318 std::random_access_iterator_tag, const Value *,
0319 ptrdiff_t, const Value *, const Value *> {
0320 explicit const_value_op_iterator(const Use *U = nullptr) :
0321 iterator_adaptor_base(U) {}
0322
0323 const Value *operator*() const { return *I; }
0324 const Value *operator->() const { return operator*(); }
0325 };
0326
0327 const_value_op_iterator value_op_begin() const {
0328 return const_value_op_iterator(op_begin());
0329 }
0330 const_value_op_iterator value_op_end() const {
0331 return const_value_op_iterator(op_end());
0332 }
0333 iterator_range<const_value_op_iterator> operand_values() const {
0334 return make_range(value_op_begin(), value_op_end());
0335 }
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345 void dropAllReferences() {
0346 for (Use &U : operands())
0347 U.set(nullptr);
0348 }
0349
0350
0351
0352
0353
0354 bool replaceUsesOfWith(Value *From, Value *To);
0355
0356
0357 static bool classof(const Value *V) {
0358 return isa<Instruction>(V) || isa<Constant>(V);
0359 }
0360 };
0361
0362
0363 static_assert(alignof(Use) >= alignof(User),
0364 "Alignment is insufficient after objects prepended to User");
0365 static_assert(alignof(Use *) >= alignof(User),
0366 "Alignment is insufficient after objects prepended to User");
0367
0368 template<> struct simplify_type<User::op_iterator> {
0369 using SimpleType = Value*;
0370
0371 static SimpleType getSimplifiedValue(User::op_iterator &Val) {
0372 return Val->get();
0373 }
0374 };
0375 template<> struct simplify_type<User::const_op_iterator> {
0376 using SimpleType = Value*;
0377
0378 static SimpleType getSimplifiedValue(User::const_op_iterator &Val) {
0379 return Val->get();
0380 }
0381 };
0382
0383 }
0384
0385 #endif