MemoryLocation.h 13 KB

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