LLVM的Value

在 LLVM 中,Value是所有可以作为表达式操作数的 IR(中间表示)实体的基类,是 LLVM IR 类型系统和指令系统的核心概念。它代表了一个 “值”,可以是常量、变量、指令结果、函数参数等,几乎所有在 IR 中参与计算或被引用的实体都继承自Value。Value的类定义如下:

//===----------------------------------------------------------------------===//
//                                 Value Class
//===----------------------------------------------------------------------===//

/// LLVM Value Representation
///
/// This is a very important LLVM class. It is the base class of all values
/// computed by a program that may be used as operands to other values. Value is
/// the super class of other important classes such as Instruction and Function.
/// All Values have a Type. Type is not a subclass of Value. Some values can
/// have a name and they belong to some Module.  Setting the name on the Value
/// automatically updates the module's symbol table.
///
/// Every value has a "use list" that keeps track of which other Values are
/// using this Value.  A Value can also have an arbitrary number of ValueHandle
/// objects that watch it and listen to RAUW and Destroy events.  See
/// llvm/IR/ValueHandle.h for details.
class Value {
  Type *VTy;
  Use *UseList;

  friend class ValueAsMetadata; // Allow access to IsUsedByMD.
  friend class ValueHandleBase;

  const unsigned char SubclassID;   // Subclass identifier (for isa/dyn_cast)
  unsigned char HasValueHandle : 1; // Has a ValueHandle pointing to this?

protected:
  /// Hold subclass data that can be dropped.
  ///
  /// This member is similar to SubclassData, however it is for holding
  /// information which may be used to aid optimization, but which may be
  /// cleared to zero without affecting conservative interpretation.
  unsigned char SubclassOptionalData : 7;

private:
  /// Hold arbitrary subclass data.
  ///
  /// This member is defined by this class, but is not used for anything.
  /// Subclasses can use it to hold whatever state they find useful.  This
  /// field is initialized to zero by the ctor.
  unsigned short SubclassData;

protected:
  /// The number of operands in the subclass.
  ///
  /// This member is defined by this class, but not used for anything.
  /// Subclasses can use it to store their number of operands, if they have
  /// any.
  ///
  /// This is stored here to save space in User on 64-bit hosts.  Since most
  /// instances of Value have operands, 32-bit hosts aren't significantly
  /// affected.
  ///
  /// Note, this should *NOT* be used directly by any class other than User.
  /// User uses this value to find the Use list.
  enum : unsigned { NumUserOperandsBits = 27 };
  unsigned NumUserOperands : NumUserOperandsBits;

  // Use the same type as the bitfield above so that MSVC will pack them.
  unsigned IsUsedByMD : 1;
  unsigned HasName : 1;
  unsigned HasMetadata : 1; // Has metadata attached to this?
  unsigned HasHungOffUses : 1;
  unsigned HasDescriptor : 1;

private:
  template <typename UseT> // UseT == 'Use' or 'const Use'
  class use_iterator_impl {
    friend class Value;

    UseT *U;

    explicit use_iterator_impl(UseT *u) : U(u) {}

  public:
    using iterator_category = std::forward_iterator_tag;
    using value_type = UseT *;
    using difference_type = std::ptrdiff_t;
    using pointer = value_type *;
    using reference = value_type &;

    use_iterator_impl() : U() {}

    bool operator==(const use_iterator_impl &x) const { return U == x.U; }
    bool operator!=(const use_iterator_impl &x) const { return !operator==(x); }

    use_iterator_impl &operator++() { // Preincrement
      assert(U && "Cannot increment end iterator!");
      U = U->getNext();
      return *this;
    }

    use_iterator_impl operator++(int) { // Postincrement
      auto tmp = *this;
      ++*this;
      return tmp;
    }

    UseT &operator*() const {
      assert(U && "Cannot dereference end iterator!");
      return *U;
    }

    UseT *operator->() const { return &operator*(); }

    operator use_iterator_impl<const UseT>() const {
      return use_iterator_impl<const UseT>(U);
    }
  };

  template <typename UserTy> // UserTy == 'User' or 'const User'
  class user_iterator_impl {
    use_iterator_impl<Use> UI;
    explicit user_iterator_impl(Use *U) : UI(U) {}
    friend class Value;

  public:
    using iterator_category = std::forward_iterator_tag;
    using value_type = UserTy *;
    using difference_type = std::ptrdiff_t;
    using pointer = value_type *;
    using reference = value_type &;

    user_iterator_impl() = default;

    bool operator==(const user_iterator_impl &x) const { return UI == x.UI; }
    bool operator!=(const user_iterator_impl &x) const { return !operator==(x); }

    /// Returns true if this iterator is equal to user_end() on the value.
    bool atEnd() const { return *this == user_iterator_impl(); }

    user_iterator_impl &operator++() { // Preincrement
      ++UI;
      return *this;
    }

    user_iterator_impl operator++(int) { // Postincrement
      auto tmp = *this;
      ++*this;
      return tmp;
    }

    // Retrieve a pointer to the current User.
    UserTy *operator*() const {
      return UI->getUser();
    }

    UserTy *operator->() const { return operator*(); }

    operator user_iterator_impl<const UserTy>() const {
      return user_iterator_impl<const UserTy>(*UI);
    }

    Use &getUse() const { return *UI; }
  };

protected:
  Value(Type *Ty, unsigned scid);

  /// Value's destructor should be virtual by design, but that would require
  /// that Value and all of its subclasses have a vtable that effectively
  /// duplicates the information in the value ID. As a size optimization, the
  /// destructor has been protected, and the caller should manually call
  /// deleteValue.
  ~Value(); // Use deleteValue() to delete a generic Value.

public:
  Value(const Value &) = delete;
  Value &operator=(const Value &) = delete;

  /// Delete a pointer to a generic Value.
  void deleteValue();

  /// Support for debugging, callable in GDB: V->dump()
  void dump() const;

  /// Implement operator<< on Value.
  /// @{
  void print(raw_ostream &O, bool IsForDebug = false) const;
  void print(raw_ostream &O, ModuleSlotTracker &MST,
             bool IsForDebug = false) const;
  /// @}

  /// Print the name of this Value out to the specified raw_ostream.
  ///
  /// This is useful when you just want to print 'int %reg126', not the
  /// instruction that generated it. If you specify a Module for context, then
  /// even constanst get pretty-printed; for example, the type of a null
  /// pointer is printed symbolically.
  /// @{
  void printAsOperand(raw_ostream &O, bool PrintType = true,
                      const Module *M = nullptr) const;
  void printAsOperand(raw_ostream &O, bool PrintType,
                      ModuleSlotTracker &MST) const;
  /// @}

  /// All values are typed, get the type of this value.
  Type *getType() const { return VTy; }

  /// All values hold a context through their type.
  LLVMContext &getContext() const;

  // All values can potentially be named.
  bool hasName() const { return HasName; }
  ValueName *getValueName() const;
  void setValueName(ValueName *VN);

private:
  void destroyValueName();
  enum class ReplaceMetadataUses { No, Yes };
  void doRAUW(Value *New, ReplaceMetadataUses);
  void setNameImpl(const Twine &Name);

public:
  /// Return a constant reference to the value's name.
  ///
  /// This guaranteed to return the same reference as long as the value is not
  /// modified.  If the value has a name, this does a hashtable lookup, so it's
  /// not free.
  StringRef getName() const;

  /// Change the name of the value.
  ///
  /// Choose a new unique name if the provided name is taken.
  ///
  /// \param Name The new name; or "" if the value's name should be removed.
  void setName(const Twine &Name);

  /// Transfer the name from V to this value.
  ///
  /// After taking V's name, sets V's name to empty.
  ///
  /// \note It is an error to call V->takeName(V).
  void takeName(Value *V);

#ifndef NDEBUG
  std::string getNameOrAsOperand() const;
#endif

  /// Change all uses of this to point to a new Value.
  ///
  /// Go through the uses list for this definition and make each use point to
  /// "V" instead of "this".  After this completes, 'this's use list is
  /// guaranteed to be empty.
  void replaceAllUsesWith(Value *V);

  /// Change non-metadata uses of this to point to a new Value.
  ///
  /// Go through the uses list for this definition and make each use point to
  /// "V" instead of "this". This function skips metadata entries in the list.
  void replaceNonMetadataUsesWith(Value *V);

  /// Go through the uses list for this definition and make each use point
  /// to "V" if the callback ShouldReplace returns true for the given Use.
  /// Unlike replaceAllUsesWith() this function does not support basic block
  /// values.
  void replaceUsesWithIf(Value *New,
                         llvm::function_ref<bool(Use &U)> ShouldReplace);

  /// replaceUsesOutsideBlock - Go through the uses list for this definition and
  /// make each use point to "V" instead of "this" when the use is outside the
  /// block. 'This's use list is expected to have at least one element.
  /// Unlike replaceAllUsesWith() this function does not support basic block
  /// values.
  void replaceUsesOutsideBlock(Value *V, BasicBlock *BB);

  //----------------------------------------------------------------------
  // Methods for handling the chain of uses of this Value.
  //
  // Materializing a function can introduce new uses, so these methods come in
  // two variants:
  // The methods that start with materialized_ check the uses that are
  // currently known given which functions are materialized. Be very careful
  // when using them since you might not get all uses.
  // The methods that don't start with materialized_ assert that modules is
  // fully materialized.
  void assertModuleIsMaterializedImpl() const;
  // This indirection exists so we can keep assertModuleIsMaterializedImpl()
  // around in release builds of Value.cpp to be linked with other code built
  // in debug mode. But this avoids calling it in any of the release built code.
  void assertModuleIsMaterialized() const {
#ifndef NDEBUG
    assertModuleIsMaterializedImpl();
#endif
  }

  bool use_empty() const {
    assertModuleIsMaterialized();
    return UseList == nullptr;
  }

  bool materialized_use_empty() const {
    return UseList == nullptr;
  }

  using use_iterator = use_iterator_impl<Use>;
  using const_use_iterator = use_iterator_impl<const Use>;

  use_iterator materialized_use_begin() { return use_iterator(UseList); }
  const_use_iterator materialized_use_begin() const {
    return const_use_iterator(UseList);
  }
  use_iterator use_begin() {
    assertModuleIsMaterialized();
    return materialized_use_begin();
  }
  const_use_iterator use_begin() const {
    assertModuleIsMaterialized();
    return materialized_use_begin();
  }
  use_iterator use_end() { return use_iterator(); }
  const_use_iterator use_end() const { return const_use_iterator(); }
  iterator_range<use_iterator> materialized_uses() {
    return make_range(materialized_use_begin(), use_end());
  }
  iterator_range<const_use_iterator> materialized_uses() const {
    return make_range(materialized_use_begin(), use_end());
  }
  iterator_range<use_iterator> uses() {
    assertModuleIsMaterialized();
    return materialized_uses();
  }
  iterator_range<const_use_iterator> uses() const {
    assertModuleIsMaterialized();
    return materialized_uses();
  }

  bool user_empty() const {
    assertModuleIsMaterialized();
    return UseList == nullptr;
  }

  using user_iterator = user_iterator_impl<User>;
  using const_user_iterator = user_iterator_impl<const User>;

  user_iterator materialized_user_begin() { return user_iterator(UseList); }
  const_user_iterator materialized_user_begin() const {
    return const_user_iterator(UseList);
  }
  user_iterator user_begin() {
    assertModuleIsMaterialized();
    return materialized_user_begin();
  }
  const_user_iterator user_begin() const {
    assertModuleIsMaterialized();
    return materialized_user_begin();
  }
  user_iterator user_end() { return user_iterator(); }
  const_user_iterator user_end() const { return const_user_iterator(); }
  User *user_back() {
    assertModuleIsMaterialized();
    return *materialized_user_begin();
  }
  const User *user_back() const {
    assertModuleIsMaterialized();
    return *materialized_user_begin();
  }
  iterator_range<user_iterator> materialized_users() {
    return make_range(materialized_user_begin(), user_end());
  }
  iterator_range<const_user_iterator> materialized_users() const {
    return make_range(materialized_user_begin(), user_end());
  }
  iterator_range<user_iterator> users() {
    assertModuleIsMaterialized();
    return materialized_users();
  }
  iterator_range<const_user_iterator> users() const {
    assertModuleIsMaterialized();
    return materialized_users();
  }

  /// Return true if there is exactly one use of this value.
  ///
  /// This is specialized because it is a common request and does not require
  /// traversing the whole use list.
  bool hasOneUse() const { return hasSingleElement(uses()); }

  /// Return true if this Value has exactly N uses.
  bool hasNUses(unsigned N) const;

  /// Return true if this value has N uses or more.
  ///
  /// This is logically equivalent to getNumUses() >= N.
  bool hasNUsesOrMore(unsigned N) const;

  /// Return true if there is exactly one user of this value.
  ///
  /// Note that this is not the same as "has one use". If a value has one use,
  /// then there certainly is a single user. But if value has several uses,
  /// it is possible that all uses are in a single user, or not.
  ///
  /// This check is potentially costly, since it requires traversing,
  /// in the worst case, the whole use list of a value.
  bool hasOneUser() const;

  /// Return true if there is exactly one use of this value that cannot be
  /// dropped.
  Use *getSingleUndroppableUse();
  const Use *getSingleUndroppableUse() const {
    return const_cast<Value *>(this)->getSingleUndroppableUse();
  }

  /// Return true if there is exactly one unique user of this value that cannot be
  /// dropped (that user can have multiple uses of this value).
  User *getUniqueUndroppableUser();
  const User *getUniqueUndroppableUser() const {
    return const_cast<Value *>(this)->getUniqueUndroppableUser();
  }

  /// Return true if there this value.
  ///
  /// This is specialized because it is a common request and does not require
  /// traversing the whole use list.
  bool hasNUndroppableUses(unsigned N) const;

  /// Return true if this value has N uses or more.
  ///
  /// This is logically equivalent to getNumUses() >= N.
  bool hasNUndroppableUsesOrMore(unsigned N) const;

  /// Remove every uses that can safely be removed.
  ///
  /// This will remove for example uses in llvm.assume.
  /// This should be used when performing want to perform a tranformation but
  /// some Droppable uses pervent it.
  /// This function optionally takes a filter to only remove some droppable
  /// uses.
  void dropDroppableUses(llvm::function_ref<bool(const Use *)> ShouldDrop =
                             [](const Use *) { return true; });

  /// Remove every use of this value in \p User that can safely be removed.
  void dropDroppableUsesIn(User &Usr);

  /// Remove the droppable use \p U.
  static void dropDroppableUse(Use &U);

  /// Check if this value is used in the specified basic block.
  bool isUsedInBasicBlock(const BasicBlock *BB) const;

  /// This method computes the number of uses of this Value.
  ///
  /// This is a linear time operation.  Use hasOneUse, hasNUses, or
  /// hasNUsesOrMore to check for specific values.
  unsigned getNumUses() const;

  /// This method should only be used by the Use class.
  void addUse(Use &U) { U.addToList(&UseList); }

  /// Concrete subclass of this.
  ///
  /// An enumeration for keeping track of the concrete subclass of Value that
  /// is actually instantiated. Values of this enumeration are kept in the
  /// Value classes SubclassID field. They are used for concrete type
  /// identification.
  enum ValueTy {
#define HANDLE_VALUE(Name) Name##Val,
#include "llvm/IR/Value.def"

    // Markers:
#define HANDLE_CONSTANT_MARKER(Marker, Constant) Marker = Constant##Val,
#include "llvm/IR/Value.def"
  };

  /// Return an ID for the concrete type of this object.
  ///
  /// This is used to implement the classof checks.  This should not be used
  /// for any other purpose, as the values may change as LLVM evolves.  Also,
  /// note that for instructions, the Instruction's opcode is added to
  /// InstructionVal. So this means three things:
  /// # there is no value with code InstructionVal (no opcode==0).
  /// # there are more possible values for the value type than in ValueTy enum.
  /// # the InstructionVal enumerator must be the highest valued enumerator in
  ///   the ValueTy enum.
  unsigned getValueID() const {
    return SubclassID;
  }

  /// Return the raw optional flags value contained in this value.
  ///
  /// This should only be used when testing two Values for equivalence.
  unsigned getRawSubclassOptionalData() const {
    return SubclassOptionalData;
  }

  /// Clear the optional flags contained in this value.
  void clearSubclassOptionalData() {
    SubclassOptionalData = 0;
  }

  /// Check the optional flags for equality.
  bool hasSameSubclassOptionalData(const Value *V) const {
    return SubclassOptionalData == V->SubclassOptionalData;
  }

  /// Return true if there is a value handle associated with this value.
  bool hasValueHandle() const { return HasValueHandle; }

  /// Return true if there is metadata referencing this value.
  bool isUsedByMetadata() const { return IsUsedByMD; }

protected:
  /// Get the current metadata attachments for the given kind, if any.
  ///
  /// These functions require that the value have at most a single attachment
  /// of the given kind, and return \c nullptr if such an attachment is missing.
  /// @{
  MDNode *getMetadata(unsigned KindID) const;
  MDNode *getMetadata(StringRef Kind) const;
  /// @}

  /// Appends all attachments with the given ID to \c MDs in insertion order.
  /// If the Value has no attachments with the given ID, or if ID is invalid,
  /// leaves MDs unchanged.
  /// @{
  void getMetadata(unsigned KindID, SmallVectorImpl<MDNode *> &MDs) const;
  void getMetadata(StringRef Kind, SmallVectorImpl<MDNode *> &MDs) const;
  /// @}

  /// Appends all metadata attached to this value to \c MDs, sorting by
  /// KindID. The first element of each pair returned is the KindID, the second
  /// element is the metadata value. Attachments with the same ID appear in
  /// insertion order.
  void
  getAllMetadata(SmallVectorImpl<std::pair<unsigned, MDNode *>> &MDs) const;

  /// Return true if this value has any metadata attached to it.
  bool hasMetadata() const { return (bool)HasMetadata; }

  /// Return true if this value has the given type of metadata attached.
  /// @{
  bool hasMetadata(unsigned KindID) const {
    return getMetadata(KindID) != nullptr;
  }
  bool hasMetadata(StringRef Kind) const {
    return getMetadata(Kind) != nullptr;
  }
  /// @}

  /// Set a particular kind of metadata attachment.
  ///
  /// Sets the given attachment to \c MD, erasing it if \c MD is \c nullptr or
  /// replacing it if it already exists.
  /// @{
  void setMetadata(unsigned KindID, MDNode *Node);
  void setMetadata(StringRef Kind, MDNode *Node);
  /// @}

  /// Add a metadata attachment.
  /// @{
  void addMetadata(unsigned KindID, MDNode &MD);
  void addMetadata(StringRef Kind, MDNode &MD);
  /// @}

  /// Erase all metadata attachments with the given kind.
  ///
  /// \returns true if any metadata was removed.
  bool eraseMetadata(unsigned KindID);

  /// Erase all metadata attached to this Value.
  void clearMetadata();

public:
  /// Return true if this value is a swifterror value.
  ///
  /// swifterror values can be either a function argument or an alloca with a
  /// swifterror attribute.
  bool isSwiftError() const;

  /// Strip off pointer casts, all-zero GEPs and address space casts.
  ///
  /// Returns the original uncasted value.  If this is called on a non-pointer
  /// value, it returns 'this'.
  const Value *stripPointerCasts() const;
  Value *stripPointerCasts() {
    return const_cast<Value *>(
        static_cast<const Value *>(this)->stripPointerCasts());
  }

  /// Strip off pointer casts, all-zero GEPs, address space casts, and aliases.
  ///
  /// Returns the original uncasted value.  If this is called on a non-pointer
  /// value, it returns 'this'.
  const Value *stripPointerCastsAndAliases() const;
  Value *stripPointerCastsAndAliases() {
    return const_cast<Value *>(
        static_cast<const Value *>(this)->stripPointerCastsAndAliases());
  }

  /// Strip off pointer casts, all-zero GEPs and address space casts
  /// but ensures the representation of the result stays the same.
  ///
  /// Returns the original uncasted value with the same representation. If this
  /// is called on a non-pointer value, it returns 'this'.
  const Value *stripPointerCastsSameRepresentation() const;
  Value *stripPointerCastsSameRepresentation() {
    return const_cast<Value *>(static_cast<const Value *>(this)
                                   ->stripPointerCastsSameRepresentation());
  }

  /// Strip off pointer casts, all-zero GEPs, single-argument phi nodes and
  /// invariant group info.
  ///
  /// Returns the original uncasted value.  If this is called on a non-pointer
  /// value, it returns 'this'. This function should be used only in
  /// Alias analysis.
  const Value *stripPointerCastsForAliasAnalysis() const;
  Value *stripPointerCastsForAliasAnalysis() {
    return const_cast<Value *>(static_cast<const Value *>(this)
                                   ->stripPointerCastsForAliasAnalysis());
  }

  /// Strip off pointer casts and all-constant inbounds GEPs.
  ///
  /// Returns the original pointer value.  If this is called on a non-pointer
  /// value, it returns 'this'.
  const Value *stripInBoundsConstantOffsets() const;
  Value *stripInBoundsConstantOffsets() {
    return const_cast<Value *>(
              static_cast<const Value *>(this)->stripInBoundsConstantOffsets());
  }

  /// Accumulate the constant offset this value has compared to a base pointer.
  /// Only 'getelementptr' instructions (GEPs) are accumulated but other
  /// instructions, e.g., casts, are stripped away as well.
  /// The accumulated constant offset is added to \p Offset and the base
  /// pointer is returned.
  ///
  /// The APInt \p Offset has to have a bit-width equal to the IntPtr type for
  /// the address space of 'this' pointer value, e.g., use
  /// DataLayout::getIndexTypeSizeInBits(Ty).
  ///
  /// If \p AllowNonInbounds is true, offsets in GEPs are stripped and
  /// accumulated even if the GEP is not "inbounds".
  ///
  /// If \p AllowInvariantGroup is true then this method also looks through
  /// strip.invariant.group and launder.invariant.group intrinsics.
  ///
  /// If \p ExternalAnalysis is provided it will be used to calculate a offset
  /// when a operand of GEP is not constant.
  /// For example, for a value \p ExternalAnalysis might try to calculate a
  /// lower bound. If \p ExternalAnalysis is successful, it should return true.
  ///
  /// If this is called on a non-pointer value, it returns 'this' and the
  /// \p Offset is not modified.
  ///
  /// Note that this function will never return a nullptr. It will also never
  /// manipulate the \p Offset in a way that would not match the difference
  /// between the underlying value and the returned one. Thus, if no constant
  /// offset was found, the returned value is the underlying one and \p Offset
  /// is unchanged.
  const Value *stripAndAccumulateConstantOffsets(
      const DataLayout &DL, APInt &Offset, bool AllowNonInbounds,
      bool AllowInvariantGroup = false,
      function_ref<bool(Value &Value, APInt &Offset)> ExternalAnalysis =
          nullptr) const;
  Value *stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset,
                                           bool AllowNonInbounds,
                                           bool AllowInvariantGroup = false) {
    return const_cast<Value *>(
        static_cast<const Value *>(this)->stripAndAccumulateConstantOffsets(
            DL, Offset, AllowNonInbounds, AllowInvariantGroup));
  }

  /// This is a wrapper around stripAndAccumulateConstantOffsets with the
  /// in-bounds requirement set to false.
  const Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL,
                                                         APInt &Offset) const {
    return stripAndAccumulateConstantOffsets(DL, Offset,
                                             /* AllowNonInbounds */ false);
  }
  Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL,
                                                   APInt &Offset) {
    return stripAndAccumulateConstantOffsets(DL, Offset,
                                             /* AllowNonInbounds */ false);
  }

  /// Strip off pointer casts and inbounds GEPs.
  ///
  /// Returns the original pointer value.  If this is called on a non-pointer
  /// value, it returns 'this'.
  const Value *stripInBoundsOffsets(function_ref<void(const Value *)> Func =
                                        [](const Value *) {}) const;
  inline Value *stripInBoundsOffsets(function_ref<void(const Value *)> Func =
                                  [](const Value *) {}) {
    return const_cast<Value *>(
        static_cast<const Value *>(this)->stripInBoundsOffsets(Func));
  }

  /// If this ptr is provably equal to \p Other plus a constant offset, return
  /// that offset in bytes. Essentially `ptr this` subtract `ptr Other`.
  std::optional<int64_t> getPointerOffsetFrom(const Value *Other,
                                              const DataLayout &DL) const;

  /// Return true if the memory object referred to by V can by freed in the
  /// scope for which the SSA value defining the allocation is statically
  /// defined.  E.g.  deallocation after the static scope of a value does not
  /// count, but a deallocation before that does.
  bool canBeFreed() const;

  /// Returns the number of bytes known to be dereferenceable for the
  /// pointer value.
  ///
  /// If CanBeNull is set by this function the pointer can either be null or be
  /// dereferenceable up to the returned number of bytes.
  ///
  /// IF CanBeFreed is true, the pointer is known to be dereferenceable at
  /// point of definition only.  Caller must prove that allocation is not
  /// deallocated between point of definition and use.
  uint64_t getPointerDereferenceableBytes(const DataLayout &DL,
                                          bool &CanBeNull,
                                          bool &CanBeFreed) const;

  /// Returns an alignment of the pointer value.
  ///
  /// Returns an alignment which is either specified explicitly, e.g. via
  /// align attribute of a function argument, or guaranteed by DataLayout.
  Align getPointerAlignment(const DataLayout &DL) const;

  /// Translate PHI node to its predecessor from the given basic block.
  ///
  /// If this value is a PHI node with CurBB as its parent, return the value in
  /// the PHI node corresponding to PredBB.  If not, return ourself.  This is
  /// useful if you want to know the value something has in a predecessor
  /// block.
  const Value *DoPHITranslation(const BasicBlock *CurBB,
                                const BasicBlock *PredBB) const;
  Value *DoPHITranslation(const BasicBlock *CurBB, const BasicBlock *PredBB) {
    return const_cast<Value *>(
             static_cast<const Value *>(this)->DoPHITranslation(CurBB, PredBB));
  }

  /// The maximum alignment for instructions.
  ///
  /// This is the greatest alignment value supported by load, store, and alloca
  /// instructions, and global values.
  static constexpr unsigned MaxAlignmentExponent = 32;
  static constexpr uint64_t MaximumAlignment = 1ULL << MaxAlignmentExponent;

  /// Mutate the type of this Value to be of the specified type.
  ///
  /// Note that this is an extremely dangerous operation which can create
  /// completely invalid IR very easily.  It is strongly recommended that you
  /// recreate IR objects with the right types instead of mutating them in
  /// place.
  void mutateType(Type *Ty) {
    VTy = Ty;
  }

  /// Sort the use-list.
  ///
  /// Sorts the Value's use-list by Cmp using a stable mergesort.  Cmp is
  /// expected to compare two \a Use references.
  template <class Compare> void sortUseList(Compare Cmp);

  /// Reverse the use-list.
  void reverseUseList();

private:
  /// Merge two lists together.
  ///
  /// Merges \c L and \c R using \c Cmp.  To enable stable sorts, always pushes
  /// "equal" items from L before items from R.
  ///
  /// \return the first element in the list.
  ///
  /// \note Completely ignores \a Use::Prev (doesn't read, doesn't update).
  template <class Compare>
  static Use *mergeUseLists(Use *L, Use *R, Compare Cmp) {
    Use *Merged;
    Use **Next = &Merged;

    while (true) {
      if (!L) {
        *Next = R;
        break;
      }
      if (!R) {
        *Next = L;
        break;
      }
      if (Cmp(*R, *L)) {
        *Next = R;
        Next = &R->Next;
        R = R->Next;
      } else {
        *Next = L;
        Next = &L->Next;
        L = L->Next;
      }
    }

    return Merged;
  }

protected:
  unsigned short getSubclassDataFromValue() const { return SubclassData; }
  void setValueSubclassData(unsigned short D) { SubclassData = D; }
};

核心特性

  1. 类型关联:每个Value都有一个明确的类型(Type*),通过getType()方法获取,LLVM IR 是强类型的,操作Value时必须遵守类型规则。

  2. 使用列表Value会跟踪所有使用它的地方(即 “用户”,User对象),通过use_begin()use_end()可以遍历其所有用途,这对分析和转换 IR 至关重要(例如删除未使用的值)。

  3. 名称标识Value可以有一个可选的名称(字符串),主要用于 IR 的可读输出(如.ll文件),但不影响语义。匿名值会自动生成编号(如%0%1)。

主要子类

Value有许多重要子类,覆盖了 LLVM IR 中的各种值类型:

  1. Constant:表示编译期已知的常量,如:

    • ConstantInt:整数常量(如i32 42
    • ConstantFP:浮点数常量(如double 3.14
    • ConstantArray:数组常量
    • ConstantPointerNull:空指针常量
  2. Argument:函数的形式参数,是函数入口处可访问的Value

  3. Instruction:指令的结果(如加法、加载、存储等操作的输出),例如:

    • :加法指令的结果(%add = add i32 %a, %b中的%add
    • LoadInst:从内存加载的值
    • CallInst:函数调用的返回值
  4. BasicBlock:基本块本身也是一种Value,可被分支指令(如br)引用(作为跳转目标)。

  5. Function:函数本身可作为值被引用(如函数指针、间接调用)。

  6. GlobalValue:全局作用域的值,如GlobalVariable(全局变量)和Function(函数本质上是全局实体)。

实例

通过一个实例进一步说明其功能:

#include "llvm/IR/Value.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"

using namespace llvm;

void analyzeValue(Value *V) {
  // 获取值的类型
  Type *Ty = V->getType();
  errs() << "Value type: " << *Ty << "\n";

  // 检查值的名称
  if (V->hasName()) {
    errs() << "Name: " << V->getName() << "\n";
  } else {
    errs() << "No name (anonymous)\n";
  }

  // 检查值的类型(通过动态类型判断)
  if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
    errs() << "It's a constant integer: " << CI->getSExtValue() << "\n";
  } else if (Argument *Arg = dyn_cast<Argument>(V)) {
    errs() << "It's a function argument, index: " << Arg->getArgNo() << "\n";
  } else if (Instruction *I = dyn_cast<Instruction>(V)) {
    errs() << "It's an instruction: " << *I << "\n";
  }

  // 遍历所有使用该值的地方
  errs() << "Uses:\n";
  for (User *U : V->users()) {
    errs() << "  Used by: " << *U << "\n";
  }
}

通过该实例可以看到各种各样的用法。

关键意义

  • IR 的基本构建块:所有计算和数据流都围绕Value展开,指令消费Value并产生新的Value
  • 分析与优化的基础:Pass(优化或分析组件)通过操作Value的属性(类型、用途、常量性等)实现功能,例如:
    • 常量传播 Pass 识别并替换Constant的使用
    • 死代码消除 Pass 删除未被任何User引用的Value
  • 类型安全保障Value的强类型特性确保 IR 操作符合类型规则,避免语义错误。

理解Value及其子类是掌握 LLVM IR 和开发 LLVM Pass 的基础,几乎所有 LLVM IR 相关操作都会直接或间接涉及Value

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值