MemoryLocation.h 13 KB

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