Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:14

0001 //===- MemoryLocation.h - Memory location descriptions ----------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 /// This file provides utility analysis objects describing memory locations.
0010 /// These are used both by the Alias Analysis infrastructure and more
0011 /// specialized memory analysis layers.
0012 ///
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_ANALYSIS_MEMORYLOCATION_H
0016 #define LLVM_ANALYSIS_MEMORYLOCATION_H
0017 
0018 #include "llvm/ADT/DenseMapInfo.h"
0019 #include "llvm/IR/Metadata.h"
0020 #include "llvm/Support/TypeSize.h"
0021 
0022 #include <optional>
0023 
0024 namespace llvm {
0025 
0026 class CallBase;
0027 class Instruction;
0028 class LoadInst;
0029 class StoreInst;
0030 class MemTransferInst;
0031 class MemIntrinsic;
0032 class AtomicCmpXchgInst;
0033 class AtomicMemTransferInst;
0034 class AtomicMemIntrinsic;
0035 class AtomicRMWInst;
0036 class AnyMemTransferInst;
0037 class AnyMemIntrinsic;
0038 class TargetLibraryInfo;
0039 class VAArgInst;
0040 
0041 // Represents the size of a MemoryLocation. Logically, it's an
0042 // std::optional<uint63_t> that also carries a bit to represent whether the
0043 // integer it contains, N, is 'precise'. Precise, in this context, means that we
0044 // know that the area of storage referenced by the given MemoryLocation must be
0045 // precisely N bytes. An imprecise value is formed as the union of two or more
0046 // precise values, and can conservatively represent all of the values unioned
0047 // into it. Importantly, imprecise values are an *upper-bound* on the size of a
0048 // MemoryLocation.
0049 //
0050 // Concretely, a precise MemoryLocation is (%p, 4) in
0051 // store i32 0, i32* %p
0052 //
0053 // Since we know that %p must be at least 4 bytes large at this point.
0054 // Otherwise, we have UB. An example of an imprecise MemoryLocation is (%p, 4)
0055 // at the memcpy in
0056 //
0057 //   %n = select i1 %foo, i64 1, i64 4
0058 //   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %baz, i64 %n, i32 1,
0059 //                                        i1 false)
0060 //
0061 // ...Since we'll copy *up to* 4 bytes into %p, but we can't guarantee that
0062 // we'll ever actually do so.
0063 //
0064 // If asked to represent a pathologically large value, this will degrade to
0065 // std::nullopt.
0066 // Store Scalable information in bit 62 of Value. Scalable information is
0067 // required to do Alias Analysis on Scalable quantities
0068 class LocationSize {
0069   enum : uint64_t {
0070     BeforeOrAfterPointer = ~uint64_t(0),
0071     ScalableBit = uint64_t(1) << 62,
0072     AfterPointer = (BeforeOrAfterPointer - 1) & ~ScalableBit,
0073     MapEmpty = BeforeOrAfterPointer - 2,
0074     MapTombstone = BeforeOrAfterPointer - 3,
0075     ImpreciseBit = uint64_t(1) << 63,
0076 
0077     // The maximum value we can represent without falling back to 'unknown'.
0078     MaxValue = (MapTombstone - 1) & ~(ImpreciseBit | ScalableBit),
0079   };
0080 
0081   uint64_t Value;
0082 
0083   // Hack to support implicit construction. This should disappear when the
0084   // public LocationSize ctor goes away.
0085   enum DirectConstruction { Direct };
0086 
0087   constexpr LocationSize(uint64_t Raw, DirectConstruction) : Value(Raw) {}
0088   constexpr LocationSize(uint64_t Raw, bool Scalable)
0089       : Value(Raw > MaxValue ? AfterPointer
0090                              : Raw | (Scalable ? ScalableBit : uint64_t(0))) {}
0091 
0092   static_assert(AfterPointer & ImpreciseBit,
0093                 "AfterPointer is imprecise by definition.");
0094   static_assert(BeforeOrAfterPointer & ImpreciseBit,
0095                 "BeforeOrAfterPointer is imprecise by definition.");
0096   static_assert(~(MaxValue & ScalableBit), "Max value don't have bit 62 set");
0097 
0098 public:
0099   // FIXME: Migrate all users to construct via either `precise` or `upperBound`,
0100   // to make it more obvious at the callsite the kind of size that they're
0101   // providing.
0102   //
0103   // Since the overwhelming majority of users of this provide precise values,
0104   // this assumes the provided value is precise.
0105   constexpr LocationSize(uint64_t Raw)
0106       : Value(Raw > MaxValue ? AfterPointer : Raw) {}
0107   // Create non-scalable LocationSize
0108   static LocationSize precise(uint64_t Value) {
0109     return LocationSize(Value, false /*Scalable*/);
0110   }
0111   static LocationSize precise(TypeSize Value) {
0112     return LocationSize(Value.getKnownMinValue(), Value.isScalable());
0113   }
0114 
0115   static LocationSize upperBound(uint64_t Value) {
0116     // You can't go lower than 0, so give a precise result.
0117     if (LLVM_UNLIKELY(Value == 0))
0118       return precise(0);
0119     if (LLVM_UNLIKELY(Value > MaxValue))
0120       return afterPointer();
0121     return LocationSize(Value | ImpreciseBit, Direct);
0122   }
0123   static LocationSize upperBound(TypeSize Value) {
0124     if (Value.isScalable())
0125       return afterPointer();
0126     return upperBound(Value.getFixedValue());
0127   }
0128 
0129   /// Any location after the base pointer (but still within the underlying
0130   /// object).
0131   constexpr static LocationSize afterPointer() {
0132     return LocationSize(AfterPointer, Direct);
0133   }
0134 
0135   /// Any location before or after the base pointer (but still within the
0136   /// underlying object).
0137   constexpr static LocationSize beforeOrAfterPointer() {
0138     return LocationSize(BeforeOrAfterPointer, Direct);
0139   }
0140 
0141   // Sentinel values, generally used for maps.
0142   constexpr static LocationSize mapTombstone() {
0143     return LocationSize(MapTombstone, Direct);
0144   }
0145   constexpr static LocationSize mapEmpty() {
0146     return LocationSize(MapEmpty, Direct);
0147   }
0148 
0149   // Returns a LocationSize that can correctly represent either `*this` or
0150   // `Other`.
0151   LocationSize unionWith(LocationSize Other) const {
0152     if (Other == *this)
0153       return *this;
0154 
0155     if (Value == BeforeOrAfterPointer || Other.Value == BeforeOrAfterPointer)
0156       return beforeOrAfterPointer();
0157     if (Value == AfterPointer || Other.Value == AfterPointer)
0158       return afterPointer();
0159     if (isScalable() || Other.isScalable())
0160       return afterPointer();
0161 
0162     return upperBound(std::max(getValue(), Other.getValue()));
0163   }
0164 
0165   bool hasValue() const {
0166     return Value != AfterPointer && Value != BeforeOrAfterPointer;
0167   }
0168   bool isScalable() const { return (Value & ScalableBit); }
0169 
0170   TypeSize getValue() const {
0171     assert(hasValue() && "Getting value from an unknown LocationSize!");
0172     assert((Value & ~(ImpreciseBit | ScalableBit)) < MaxValue &&
0173            "Scalable bit of value should be masked");
0174     return {Value & ~(ImpreciseBit | ScalableBit), isScalable()};
0175   }
0176 
0177   // Returns whether or not this value is precise. Note that if a value is
0178   // precise, it's guaranteed to not be unknown.
0179   bool isPrecise() const { return (Value & ImpreciseBit) == 0; }
0180 
0181   // Convenience method to check if this LocationSize's value is 0.
0182   bool isZero() const {
0183     return hasValue() && getValue().getKnownMinValue() == 0;
0184   }
0185 
0186   /// Whether accesses before the base pointer are possible.
0187   bool mayBeBeforePointer() const { return Value == BeforeOrAfterPointer; }
0188 
0189   bool operator==(const LocationSize &Other) const {
0190     return Value == Other.Value;
0191   }
0192 
0193   bool operator==(const TypeSize &Other) const {
0194     return hasValue() && getValue() == Other;
0195   }
0196 
0197   bool operator!=(const LocationSize &Other) const { return !(*this == Other); }
0198 
0199   bool operator!=(const TypeSize &Other) const { return !(*this == Other); }
0200 
0201   // Ordering operators are not provided, since it's unclear if there's only one
0202   // reasonable way to compare:
0203   // - values that don't exist against values that do, and
0204   // - precise values to imprecise values
0205 
0206   void print(raw_ostream &OS) const;
0207 
0208   // Returns an opaque value that represents this LocationSize. Cannot be
0209   // reliably converted back into a LocationSize.
0210   uint64_t toRaw() const { return Value; }
0211 };
0212 
0213 inline raw_ostream &operator<<(raw_ostream &OS, LocationSize Size) {
0214   Size.print(OS);
0215   return OS;
0216 }
0217 
0218 /// Representation for a specific memory location.
0219 ///
0220 /// This abstraction can be used to represent a specific location in memory.
0221 /// The goal of the location is to represent enough information to describe
0222 /// abstract aliasing, modification, and reference behaviors of whatever
0223 /// value(s) are stored in memory at the particular location.
0224 ///
0225 /// The primary user of this interface is LLVM's Alias Analysis, but other
0226 /// memory analyses such as MemoryDependence can use it as well.
0227 class MemoryLocation {
0228 public:
0229   /// UnknownSize - This is a special value which can be used with the
0230   /// size arguments in alias queries to indicate that the caller does not
0231   /// know the sizes of the potential memory references.
0232   enum : uint64_t { UnknownSize = ~UINT64_C(0) };
0233 
0234   /// The address of the start of the location.
0235   const Value *Ptr;
0236 
0237   /// The maximum size of the location, in address-units, or
0238   /// UnknownSize if the size is not known.
0239   ///
0240   /// Note that an unknown size does not mean the pointer aliases the entire
0241   /// virtual address space, because there are restrictions on stepping out of
0242   /// one object and into another. See
0243   /// http://llvm.org/docs/LangRef.html#pointeraliasing
0244   LocationSize Size;
0245 
0246   /// The metadata nodes which describes the aliasing of the location (each
0247   /// member is null if that kind of information is unavailable).
0248   AAMDNodes AATags;
0249 
0250   void print(raw_ostream &OS) const { OS << *Ptr << " " << Size << "\n"; }
0251 
0252   /// Return a location with information about the memory reference by the given
0253   /// instruction.
0254   static MemoryLocation get(const LoadInst *LI);
0255   static MemoryLocation get(const StoreInst *SI);
0256   static MemoryLocation get(const VAArgInst *VI);
0257   static MemoryLocation get(const AtomicCmpXchgInst *CXI);
0258   static MemoryLocation get(const AtomicRMWInst *RMWI);
0259   static MemoryLocation get(const Instruction *Inst) {
0260     return *MemoryLocation::getOrNone(Inst);
0261   }
0262   static std::optional<MemoryLocation> getOrNone(const Instruction *Inst);
0263 
0264   /// Return a location representing the source of a memory transfer.
0265   static MemoryLocation getForSource(const MemTransferInst *MTI);
0266   static MemoryLocation getForSource(const AtomicMemTransferInst *MTI);
0267   static MemoryLocation getForSource(const AnyMemTransferInst *MTI);
0268 
0269   /// Return a location representing the destination of a memory set or
0270   /// transfer.
0271   static MemoryLocation getForDest(const MemIntrinsic *MI);
0272   static MemoryLocation getForDest(const AtomicMemIntrinsic *MI);
0273   static MemoryLocation getForDest(const AnyMemIntrinsic *MI);
0274   static std::optional<MemoryLocation> getForDest(const CallBase *CI,
0275                                                   const TargetLibraryInfo &TLI);
0276 
0277   /// Return a location representing a particular argument of a call.
0278   static MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx,
0279                                        const TargetLibraryInfo *TLI);
0280   static MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx,
0281                                        const TargetLibraryInfo &TLI) {
0282     return getForArgument(Call, ArgIdx, &TLI);
0283   }
0284 
0285   /// Return a location that may access any location after Ptr, while remaining
0286   /// within the underlying object.
0287   static MemoryLocation getAfter(const Value *Ptr,
0288                                  const AAMDNodes &AATags = AAMDNodes()) {
0289     return MemoryLocation(Ptr, LocationSize::afterPointer(), AATags);
0290   }
0291 
0292   /// Return a location that may access any location before or after Ptr, while
0293   /// remaining within the underlying object.
0294   static MemoryLocation
0295   getBeforeOrAfter(const Value *Ptr, const AAMDNodes &AATags = AAMDNodes()) {
0296     return MemoryLocation(Ptr, LocationSize::beforeOrAfterPointer(), AATags);
0297   }
0298 
0299   MemoryLocation() : Ptr(nullptr), Size(LocationSize::beforeOrAfterPointer()) {}
0300 
0301   explicit MemoryLocation(const Value *Ptr, LocationSize Size,
0302                           const AAMDNodes &AATags = AAMDNodes())
0303       : Ptr(Ptr), Size(Size), AATags(AATags) {}
0304 
0305   MemoryLocation getWithNewPtr(const Value *NewPtr) const {
0306     MemoryLocation Copy(*this);
0307     Copy.Ptr = NewPtr;
0308     return Copy;
0309   }
0310 
0311   MemoryLocation getWithNewSize(LocationSize NewSize) const {
0312     MemoryLocation Copy(*this);
0313     Copy.Size = NewSize;
0314     return Copy;
0315   }
0316 
0317   MemoryLocation getWithoutAATags() const {
0318     MemoryLocation Copy(*this);
0319     Copy.AATags = AAMDNodes();
0320     return Copy;
0321   }
0322 
0323   bool operator==(const MemoryLocation &Other) const {
0324     return Ptr == Other.Ptr && Size == Other.Size && AATags == Other.AATags;
0325   }
0326 };
0327 
0328 // Specialize DenseMapInfo.
0329 template <> struct DenseMapInfo<LocationSize> {
0330   static inline LocationSize getEmptyKey() { return LocationSize::mapEmpty(); }
0331   static inline LocationSize getTombstoneKey() {
0332     return LocationSize::mapTombstone();
0333   }
0334   static unsigned getHashValue(const LocationSize &Val) {
0335     return DenseMapInfo<uint64_t>::getHashValue(Val.toRaw());
0336   }
0337   static bool isEqual(const LocationSize &LHS, const LocationSize &RHS) {
0338     return LHS == RHS;
0339   }
0340 };
0341 
0342 template <> struct DenseMapInfo<MemoryLocation> {
0343   static inline MemoryLocation getEmptyKey() {
0344     return MemoryLocation(DenseMapInfo<const Value *>::getEmptyKey(),
0345                           DenseMapInfo<LocationSize>::getEmptyKey());
0346   }
0347   static inline MemoryLocation getTombstoneKey() {
0348     return MemoryLocation(DenseMapInfo<const Value *>::getTombstoneKey(),
0349                           DenseMapInfo<LocationSize>::getTombstoneKey());
0350   }
0351   static unsigned getHashValue(const MemoryLocation &Val) {
0352     return DenseMapInfo<const Value *>::getHashValue(Val.Ptr) ^
0353            DenseMapInfo<LocationSize>::getHashValue(Val.Size) ^
0354            DenseMapInfo<AAMDNodes>::getHashValue(Val.AATags);
0355   }
0356   static bool isEqual(const MemoryLocation &LHS, const MemoryLocation &RHS) {
0357     return LHS == RHS;
0358   }
0359 };
0360 } // namespace llvm
0361 
0362 #endif