1 //===- MemoryLocation.h - Memory location descriptions ----------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// This file provides utility analysis objects describing memory locations. 10 /// These are used both by the Alias Analysis infrastructure and more 11 /// specialized memory analysis layers. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_ANALYSIS_MEMORYLOCATION_H 16 #define LLVM_ANALYSIS_MEMORYLOCATION_H 17 18 #include "llvm/ADT/DenseMapInfo.h" 19 #include "llvm/IR/Metadata.h" 20 #include "llvm/Support/Compiler.h" 21 #include "llvm/Support/TypeSize.h" 22 23 #include <optional> 24 25 namespace llvm { 26 27 class CallBase; 28 class Instruction; 29 class LoadInst; 30 class StoreInst; 31 class MemTransferInst; 32 class MemIntrinsic; 33 class AtomicCmpXchgInst; 34 class AtomicRMWInst; 35 class AnyMemTransferInst; 36 class AnyMemIntrinsic; 37 class TargetLibraryInfo; 38 class VAArgInst; 39 40 // Represents the size of a MemoryLocation. Logically, it's an 41 // std::optional<uint63_t> that also carries a bit to represent whether the 42 // integer it contains, N, is 'precise'. Precise, in this context, means that we 43 // know that the area of storage referenced by the given MemoryLocation must be 44 // precisely N bytes. An imprecise value is formed as the union of two or more 45 // precise values, and can conservatively represent all of the values unioned 46 // into it. Importantly, imprecise values are an *upper-bound* on the size of a 47 // MemoryLocation. 48 // 49 // Concretely, a precise MemoryLocation is (%p, 4) in 50 // store i32 0, i32* %p 51 // 52 // Since we know that %p must be at least 4 bytes large at this point. 53 // Otherwise, we have UB. An example of an imprecise MemoryLocation is (%p, 4) 54 // at the memcpy in 55 // 56 // %n = select i1 %foo, i64 1, i64 4 57 // call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %baz, i64 %n, i32 1, 58 // i1 false) 59 // 60 // ...Since we'll copy *up to* 4 bytes into %p, but we can't guarantee that 61 // we'll ever actually do so. 62 // 63 // If asked to represent a pathologically large value, this will degrade to 64 // std::nullopt. 65 // Store Scalable information in bit 62 of Value. Scalable information is 66 // required to do Alias Analysis on Scalable quantities 67 class LocationSize { 68 enum : uint64_t { 69 BeforeOrAfterPointer = ~uint64_t(0), 70 ScalableBit = uint64_t(1) << 62, 71 AfterPointer = (BeforeOrAfterPointer - 1) & ~ScalableBit, 72 MapEmpty = BeforeOrAfterPointer - 2, 73 MapTombstone = BeforeOrAfterPointer - 3, 74 ImpreciseBit = uint64_t(1) << 63, 75 76 // The maximum value we can represent without falling back to 'unknown'. 77 MaxValue = (MapTombstone - 1) & ~(ImpreciseBit | ScalableBit), 78 }; 79 80 uint64_t Value; 81 LocationSize(uint64_t Raw)82 constexpr LocationSize(uint64_t Raw) : Value(Raw) {} LocationSize(uint64_t Raw,bool Scalable)83 constexpr LocationSize(uint64_t Raw, bool Scalable) 84 : Value(Raw > MaxValue ? AfterPointer 85 : Raw | (Scalable ? ScalableBit : uint64_t(0))) {} 86 87 static_assert(AfterPointer & ImpreciseBit, 88 "AfterPointer is imprecise by definition."); 89 static_assert(BeforeOrAfterPointer & ImpreciseBit, 90 "BeforeOrAfterPointer is imprecise by definition."); 91 static_assert(~(MaxValue & ScalableBit), "Max value don't have bit 62 set"); 92 93 public: 94 // Create non-scalable LocationSize precise(uint64_t Value)95 static LocationSize precise(uint64_t Value) { 96 return LocationSize(Value, false /*Scalable*/); 97 } precise(TypeSize Value)98 static LocationSize precise(TypeSize Value) { 99 return LocationSize(Value.getKnownMinValue(), Value.isScalable()); 100 } 101 upperBound(uint64_t Value)102 static LocationSize upperBound(uint64_t Value) { 103 // You can't go lower than 0, so give a precise result. 104 if (LLVM_UNLIKELY(Value == 0)) 105 return precise(0); 106 if (LLVM_UNLIKELY(Value > MaxValue)) 107 return afterPointer(); 108 return LocationSize(Value | ImpreciseBit); 109 } upperBound(TypeSize Value)110 static LocationSize upperBound(TypeSize Value) { 111 if (Value.isScalable()) 112 return afterPointer(); 113 return upperBound(Value.getFixedValue()); 114 } 115 116 /// Any location after the base pointer (but still within the underlying 117 /// object). afterPointer()118 constexpr static LocationSize afterPointer() { 119 return LocationSize(AfterPointer); 120 } 121 122 /// Any location before or after the base pointer (but still within the 123 /// underlying object). beforeOrAfterPointer()124 constexpr static LocationSize beforeOrAfterPointer() { 125 return LocationSize(BeforeOrAfterPointer); 126 } 127 128 // Sentinel values, generally used for maps. mapTombstone()129 constexpr static LocationSize mapTombstone() { 130 return LocationSize(MapTombstone); 131 } mapEmpty()132 constexpr static LocationSize mapEmpty() { 133 return LocationSize(MapEmpty); 134 } 135 136 // Returns a LocationSize that can correctly represent either `*this` or 137 // `Other`. unionWith(LocationSize Other)138 LocationSize unionWith(LocationSize Other) const { 139 if (Other == *this) 140 return *this; 141 142 if (Value == BeforeOrAfterPointer || Other.Value == BeforeOrAfterPointer) 143 return beforeOrAfterPointer(); 144 if (Value == AfterPointer || Other.Value == AfterPointer) 145 return afterPointer(); 146 if (isScalable() || Other.isScalable()) 147 return afterPointer(); 148 149 return upperBound(std::max(getValue(), Other.getValue())); 150 } 151 hasValue()152 bool hasValue() const { 153 return Value != AfterPointer && Value != BeforeOrAfterPointer; 154 } isScalable()155 bool isScalable() const { return (Value & ScalableBit); } 156 getValue()157 TypeSize getValue() const { 158 assert(hasValue() && "Getting value from an unknown LocationSize!"); 159 assert((Value & ~(ImpreciseBit | ScalableBit)) < MaxValue && 160 "Scalable bit of value should be masked"); 161 return {Value & ~(ImpreciseBit | ScalableBit), isScalable()}; 162 } 163 164 // Returns whether or not this value is precise. Note that if a value is 165 // precise, it's guaranteed to not be unknown. isPrecise()166 bool isPrecise() const { return (Value & ImpreciseBit) == 0; } 167 168 // Convenience method to check if this LocationSize's value is 0. isZero()169 bool isZero() const { 170 return hasValue() && getValue().getKnownMinValue() == 0; 171 } 172 173 /// Whether accesses before the base pointer are possible. mayBeBeforePointer()174 bool mayBeBeforePointer() const { return Value == BeforeOrAfterPointer; } 175 176 bool operator==(const LocationSize &Other) const { 177 return Value == Other.Value; 178 } 179 bool operator==(const TypeSize &Other) const { 180 return (*this == LocationSize::precise(Other)); 181 } 182 bool operator==(uint64_t Other) const { 183 return (*this == LocationSize::precise(Other)); 184 } 185 186 bool operator!=(const LocationSize &Other) const { return !(*this == Other); } 187 bool operator!=(const TypeSize &Other) const { return !(*this == Other); } 188 bool operator!=(uint64_t Other) const { return !(*this == Other); } 189 190 // Ordering operators are not provided, since it's unclear if there's only one 191 // reasonable way to compare: 192 // - values that don't exist against values that do, and 193 // - precise values to imprecise values 194 195 LLVM_ABI void print(raw_ostream &OS) const; 196 197 // Returns an opaque value that represents this LocationSize. Cannot be 198 // reliably converted back into a LocationSize. toRaw()199 uint64_t toRaw() const { return Value; } 200 }; 201 202 inline raw_ostream &operator<<(raw_ostream &OS, LocationSize Size) { 203 Size.print(OS); 204 return OS; 205 } 206 207 /// Representation for a specific memory location. 208 /// 209 /// This abstraction can be used to represent a specific location in memory. 210 /// The goal of the location is to represent enough information to describe 211 /// abstract aliasing, modification, and reference behaviors of whatever 212 /// value(s) are stored in memory at the particular location. 213 /// 214 /// The primary user of this interface is LLVM's Alias Analysis, but other 215 /// memory analyses such as MemoryDependence can use it as well. 216 class MemoryLocation { 217 public: 218 /// UnknownSize - This is a special value which can be used with the 219 /// size arguments in alias queries to indicate that the caller does not 220 /// know the sizes of the potential memory references. 221 enum : uint64_t { UnknownSize = ~UINT64_C(0) }; 222 223 /// The address of the start of the location. 224 const Value *Ptr; 225 226 /// The maximum size of the location, in address-units, or 227 /// UnknownSize if the size is not known. 228 /// 229 /// Note that an unknown size does not mean the pointer aliases the entire 230 /// virtual address space, because there are restrictions on stepping out of 231 /// one object and into another. See 232 /// http://llvm.org/docs/LangRef.html#pointeraliasing 233 LocationSize Size; 234 235 /// The metadata nodes which describes the aliasing of the location (each 236 /// member is null if that kind of information is unavailable). 237 AAMDNodes AATags; 238 print(raw_ostream & OS)239 void print(raw_ostream &OS) const { OS << *Ptr << " " << Size << "\n"; } 240 241 /// Return a location with information about the memory reference by the given 242 /// instruction. 243 LLVM_ABI static MemoryLocation get(const LoadInst *LI); 244 LLVM_ABI static MemoryLocation get(const StoreInst *SI); 245 LLVM_ABI static MemoryLocation get(const VAArgInst *VI); 246 LLVM_ABI static MemoryLocation get(const AtomicCmpXchgInst *CXI); 247 LLVM_ABI static MemoryLocation get(const AtomicRMWInst *RMWI); get(const Instruction * Inst)248 static MemoryLocation get(const Instruction *Inst) { 249 return *MemoryLocation::getOrNone(Inst); 250 } 251 LLVM_ABI static std::optional<MemoryLocation> 252 getOrNone(const Instruction *Inst); 253 254 /// Return a location representing the source of a memory transfer. 255 LLVM_ABI static MemoryLocation getForSource(const MemTransferInst *MTI); 256 LLVM_ABI static MemoryLocation getForSource(const AnyMemTransferInst *MTI); 257 258 /// Return a location representing the destination of a memory set or 259 /// transfer. 260 LLVM_ABI static MemoryLocation getForDest(const MemIntrinsic *MI); 261 LLVM_ABI static MemoryLocation getForDest(const AnyMemIntrinsic *MI); 262 LLVM_ABI static std::optional<MemoryLocation> 263 getForDest(const CallBase *CI, const TargetLibraryInfo &TLI); 264 265 /// Return a location representing a particular argument of a call. 266 LLVM_ABI static MemoryLocation getForArgument(const CallBase *Call, 267 unsigned ArgIdx, 268 const TargetLibraryInfo *TLI); getForArgument(const CallBase * Call,unsigned ArgIdx,const TargetLibraryInfo & TLI)269 static MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx, 270 const TargetLibraryInfo &TLI) { 271 return getForArgument(Call, ArgIdx, &TLI); 272 } 273 274 /// Return a location that may access any location after Ptr, while remaining 275 /// within the underlying object. 276 static MemoryLocation getAfter(const Value *Ptr, 277 const AAMDNodes &AATags = AAMDNodes()) { 278 return MemoryLocation(Ptr, LocationSize::afterPointer(), AATags); 279 } 280 281 /// Return a location that may access any location before or after Ptr, while 282 /// remaining within the underlying object. 283 static MemoryLocation 284 getBeforeOrAfter(const Value *Ptr, const AAMDNodes &AATags = AAMDNodes()) { 285 return MemoryLocation(Ptr, LocationSize::beforeOrAfterPointer(), AATags); 286 } 287 MemoryLocation()288 MemoryLocation() : Ptr(nullptr), Size(LocationSize::beforeOrAfterPointer()) {} 289 290 explicit MemoryLocation(const Value *Ptr, LocationSize Size, 291 const AAMDNodes &AATags = AAMDNodes()) Ptr(Ptr)292 : Ptr(Ptr), Size(Size), AATags(AATags) {} 293 explicit MemoryLocation(const Value *Ptr, TypeSize Size, 294 const AAMDNodes &AATags = AAMDNodes()) Ptr(Ptr)295 : Ptr(Ptr), Size(LocationSize::precise(Size)), AATags(AATags) {} 296 explicit MemoryLocation(const Value *Ptr, uint64_t Size, 297 const AAMDNodes &AATags = AAMDNodes()) Ptr(Ptr)298 : Ptr(Ptr), Size(LocationSize::precise(Size)), AATags(AATags) {} 299 getWithNewPtr(const Value * NewPtr)300 MemoryLocation getWithNewPtr(const Value *NewPtr) const { 301 MemoryLocation Copy(*this); 302 Copy.Ptr = NewPtr; 303 return Copy; 304 } 305 getWithNewSize(LocationSize NewSize)306 MemoryLocation getWithNewSize(LocationSize NewSize) const { 307 MemoryLocation Copy(*this); 308 Copy.Size = NewSize; 309 return Copy; 310 } getWithNewSize(uint64_t NewSize)311 MemoryLocation getWithNewSize(uint64_t NewSize) const { 312 return getWithNewSize(LocationSize::precise(NewSize)); 313 } getWithNewSize(TypeSize NewSize)314 MemoryLocation getWithNewSize(TypeSize NewSize) const { 315 return getWithNewSize(LocationSize::precise(NewSize)); 316 } 317 getWithoutAATags()318 MemoryLocation getWithoutAATags() const { 319 MemoryLocation Copy(*this); 320 Copy.AATags = AAMDNodes(); 321 return Copy; 322 } 323 324 bool operator==(const MemoryLocation &Other) const { 325 return Ptr == Other.Ptr && Size == Other.Size && AATags == Other.AATags; 326 } 327 }; 328 329 // Specialize DenseMapInfo. 330 template <> struct DenseMapInfo<LocationSize> { 331 static inline LocationSize getEmptyKey() { return LocationSize::mapEmpty(); } 332 static inline LocationSize getTombstoneKey() { 333 return LocationSize::mapTombstone(); 334 } 335 static unsigned getHashValue(const LocationSize &Val) { 336 return DenseMapInfo<uint64_t>::getHashValue(Val.toRaw()); 337 } 338 static bool isEqual(const LocationSize &LHS, const LocationSize &RHS) { 339 return LHS == RHS; 340 } 341 }; 342 343 template <> struct DenseMapInfo<MemoryLocation> { 344 static inline MemoryLocation getEmptyKey() { 345 return MemoryLocation(DenseMapInfo<const Value *>::getEmptyKey(), 346 DenseMapInfo<LocationSize>::getEmptyKey()); 347 } 348 static inline MemoryLocation getTombstoneKey() { 349 return MemoryLocation(DenseMapInfo<const Value *>::getTombstoneKey(), 350 DenseMapInfo<LocationSize>::getTombstoneKey()); 351 } 352 static unsigned getHashValue(const MemoryLocation &Val) { 353 return DenseMapInfo<const Value *>::getHashValue(Val.Ptr) ^ 354 DenseMapInfo<LocationSize>::getHashValue(Val.Size) ^ 355 DenseMapInfo<AAMDNodes>::getHashValue(Val.AATags); 356 } 357 static bool isEqual(const MemoryLocation &LHS, const MemoryLocation &RHS) { 358 return LHS == RHS; 359 } 360 }; 361 } // namespace llvm 362 363 #endif 364