123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- MemoryLocation.h - Memory location descriptions ----------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- /// \file
- /// This file provides utility analysis objects describing memory locations.
- /// These are used both by the Alias Analysis infrastructure and more
- /// specialized memory analysis layers.
- ///
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_ANALYSIS_MEMORYLOCATION_H
- #define LLVM_ANALYSIS_MEMORYLOCATION_H
- #include "llvm/ADT/DenseMapInfo.h"
- #include "llvm/IR/Metadata.h"
- #include "llvm/Support/TypeSize.h"
- #include <optional>
- namespace llvm {
- class CallBase;
- class Instruction;
- class LoadInst;
- class StoreInst;
- class MemTransferInst;
- class MemIntrinsic;
- class AtomicCmpXchgInst;
- class AtomicMemTransferInst;
- class AtomicMemIntrinsic;
- class AtomicRMWInst;
- class AnyMemTransferInst;
- class AnyMemIntrinsic;
- class TargetLibraryInfo;
- class VAArgInst;
- class Value;
- // Represents the size of a MemoryLocation. Logically, it's an
- // std::optional<uint63_t> that also carries a bit to represent whether the
- // integer it contains, N, is 'precise'. Precise, in this context, means that we
- // know that the area of storage referenced by the given MemoryLocation must be
- // precisely N bytes. An imprecise value is formed as the union of two or more
- // precise values, and can conservatively represent all of the values unioned
- // into it. Importantly, imprecise values are an *upper-bound* on the size of a
- // MemoryLocation.
- //
- // Concretely, a precise MemoryLocation is (%p, 4) in
- // store i32 0, i32* %p
- //
- // Since we know that %p must be at least 4 bytes large at this point.
- // Otherwise, we have UB. An example of an imprecise MemoryLocation is (%p, 4)
- // at the memcpy in
- //
- // %n = select i1 %foo, i64 1, i64 4
- // call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %baz, i64 %n, i32 1,
- // i1 false)
- //
- // ...Since we'll copy *up to* 4 bytes into %p, but we can't guarantee that
- // we'll ever actually do so.
- //
- // If asked to represent a pathologically large value, this will degrade to
- // std::nullopt.
- class LocationSize {
- enum : uint64_t {
- BeforeOrAfterPointer = ~uint64_t(0),
- AfterPointer = BeforeOrAfterPointer - 1,
- MapEmpty = BeforeOrAfterPointer - 2,
- MapTombstone = BeforeOrAfterPointer - 3,
- ImpreciseBit = uint64_t(1) << 63,
- // The maximum value we can represent without falling back to 'unknown'.
- MaxValue = (MapTombstone - 1) & ~ImpreciseBit,
- };
- uint64_t Value;
- // Hack to support implicit construction. This should disappear when the
- // public LocationSize ctor goes away.
- enum DirectConstruction { Direct };
- constexpr LocationSize(uint64_t Raw, DirectConstruction): Value(Raw) {}
- static_assert(AfterPointer & ImpreciseBit,
- "AfterPointer is imprecise by definition.");
- static_assert(BeforeOrAfterPointer & ImpreciseBit,
- "BeforeOrAfterPointer is imprecise by definition.");
- public:
- // FIXME: Migrate all users to construct via either `precise` or `upperBound`,
- // to make it more obvious at the callsite the kind of size that they're
- // providing.
- //
- // Since the overwhelming majority of users of this provide precise values,
- // this assumes the provided value is precise.
- constexpr LocationSize(uint64_t Raw)
- : Value(Raw > MaxValue ? AfterPointer : Raw) {}
- static LocationSize precise(uint64_t Value) { return LocationSize(Value); }
- static LocationSize precise(TypeSize Value) {
- if (Value.isScalable())
- return afterPointer();
- return precise(Value.getFixedValue());
- }
- static LocationSize upperBound(uint64_t Value) {
- // You can't go lower than 0, so give a precise result.
- if (LLVM_UNLIKELY(Value == 0))
- return precise(0);
- if (LLVM_UNLIKELY(Value > MaxValue))
- return afterPointer();
- return LocationSize(Value | ImpreciseBit, Direct);
- }
- static LocationSize upperBound(TypeSize Value) {
- if (Value.isScalable())
- return afterPointer();
- return upperBound(Value.getFixedValue());
- }
- /// Any location after the base pointer (but still within the underlying
- /// object).
- constexpr static LocationSize afterPointer() {
- return LocationSize(AfterPointer, Direct);
- }
- /// Any location before or after the base pointer (but still within the
- /// underlying object).
- constexpr static LocationSize beforeOrAfterPointer() {
- return LocationSize(BeforeOrAfterPointer, Direct);
- }
- // Sentinel values, generally used for maps.
- constexpr static LocationSize mapTombstone() {
- return LocationSize(MapTombstone, Direct);
- }
- constexpr static LocationSize mapEmpty() {
- return LocationSize(MapEmpty, Direct);
- }
- // Returns a LocationSize that can correctly represent either `*this` or
- // `Other`.
- LocationSize unionWith(LocationSize Other) const {
- if (Other == *this)
- return *this;
- if (Value == BeforeOrAfterPointer || Other.Value == BeforeOrAfterPointer)
- return beforeOrAfterPointer();
- if (Value == AfterPointer || Other.Value == AfterPointer)
- return afterPointer();
- return upperBound(std::max(getValue(), Other.getValue()));
- }
- bool hasValue() const {
- return Value != AfterPointer && Value != BeforeOrAfterPointer;
- }
- uint64_t getValue() const {
- assert(hasValue() && "Getting value from an unknown LocationSize!");
- return Value & ~ImpreciseBit;
- }
- // Returns whether or not this value is precise. Note that if a value is
- // precise, it's guaranteed to not be unknown.
- bool isPrecise() const {
- return (Value & ImpreciseBit) == 0;
- }
- // Convenience method to check if this LocationSize's value is 0.
- bool isZero() const { return hasValue() && getValue() == 0; }
- /// Whether accesses before the base pointer are possible.
- bool mayBeBeforePointer() const { return Value == BeforeOrAfterPointer; }
- bool operator==(const LocationSize &Other) const {
- return Value == Other.Value;
- }
- bool operator!=(const LocationSize &Other) const {
- return !(*this == Other);
- }
- // Ordering operators are not provided, since it's unclear if there's only one
- // reasonable way to compare:
- // - values that don't exist against values that do, and
- // - precise values to imprecise values
- void print(raw_ostream &OS) const;
- // Returns an opaque value that represents this LocationSize. Cannot be
- // reliably converted back into a LocationSize.
- uint64_t toRaw() const { return Value; }
- };
- inline raw_ostream &operator<<(raw_ostream &OS, LocationSize Size) {
- Size.print(OS);
- return OS;
- }
- /// Representation for a specific memory location.
- ///
- /// This abstraction can be used to represent a specific location in memory.
- /// The goal of the location is to represent enough information to describe
- /// abstract aliasing, modification, and reference behaviors of whatever
- /// value(s) are stored in memory at the particular location.
- ///
- /// The primary user of this interface is LLVM's Alias Analysis, but other
- /// memory analyses such as MemoryDependence can use it as well.
- class MemoryLocation {
- public:
- /// UnknownSize - This is a special value which can be used with the
- /// size arguments in alias queries to indicate that the caller does not
- /// know the sizes of the potential memory references.
- enum : uint64_t { UnknownSize = ~UINT64_C(0) };
- /// The address of the start of the location.
- const Value *Ptr;
- /// The maximum size of the location, in address-units, or
- /// UnknownSize if the size is not known.
- ///
- /// Note that an unknown size does not mean the pointer aliases the entire
- /// virtual address space, because there are restrictions on stepping out of
- /// one object and into another. See
- /// http://llvm.org/docs/LangRef.html#pointeraliasing
- LocationSize Size;
- /// The metadata nodes which describes the aliasing of the location (each
- /// member is null if that kind of information is unavailable).
- AAMDNodes AATags;
- void print(raw_ostream &OS) const { OS << *Ptr << " " << Size << "\n"; }
- /// Return a location with information about the memory reference by the given
- /// instruction.
- static MemoryLocation get(const LoadInst *LI);
- static MemoryLocation get(const StoreInst *SI);
- static MemoryLocation get(const VAArgInst *VI);
- static MemoryLocation get(const AtomicCmpXchgInst *CXI);
- static MemoryLocation get(const AtomicRMWInst *RMWI);
- static MemoryLocation get(const Instruction *Inst) {
- return *MemoryLocation::getOrNone(Inst);
- }
- static std::optional<MemoryLocation> getOrNone(const Instruction *Inst);
- /// Return a location representing the source of a memory transfer.
- static MemoryLocation getForSource(const MemTransferInst *MTI);
- static MemoryLocation getForSource(const AtomicMemTransferInst *MTI);
- static MemoryLocation getForSource(const AnyMemTransferInst *MTI);
- /// Return a location representing the destination of a memory set or
- /// transfer.
- static MemoryLocation getForDest(const MemIntrinsic *MI);
- static MemoryLocation getForDest(const AtomicMemIntrinsic *MI);
- static MemoryLocation getForDest(const AnyMemIntrinsic *MI);
- static std::optional<MemoryLocation> getForDest(const CallBase *CI,
- const TargetLibraryInfo &TLI);
- /// Return a location representing a particular argument of a call.
- static MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx,
- const TargetLibraryInfo *TLI);
- static MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx,
- const TargetLibraryInfo &TLI) {
- return getForArgument(Call, ArgIdx, &TLI);
- }
- /// Return a location that may access any location after Ptr, while remaining
- /// within the underlying object.
- static MemoryLocation getAfter(const Value *Ptr,
- const AAMDNodes &AATags = AAMDNodes()) {
- return MemoryLocation(Ptr, LocationSize::afterPointer(), AATags);
- }
- /// Return a location that may access any location before or after Ptr, while
- /// remaining within the underlying object.
- static MemoryLocation
- getBeforeOrAfter(const Value *Ptr, const AAMDNodes &AATags = AAMDNodes()) {
- return MemoryLocation(Ptr, LocationSize::beforeOrAfterPointer(), AATags);
- }
- // Return the exact size if the exact size is known at compiletime,
- // otherwise return MemoryLocation::UnknownSize.
- static uint64_t getSizeOrUnknown(const TypeSize &T) {
- return T.isScalable() ? UnknownSize : T.getFixedValue();
- }
- MemoryLocation() : Ptr(nullptr), Size(LocationSize::beforeOrAfterPointer()) {}
- explicit MemoryLocation(const Value *Ptr, LocationSize Size,
- const AAMDNodes &AATags = AAMDNodes())
- : Ptr(Ptr), Size(Size), AATags(AATags) {}
- MemoryLocation getWithNewPtr(const Value *NewPtr) const {
- MemoryLocation Copy(*this);
- Copy.Ptr = NewPtr;
- return Copy;
- }
- MemoryLocation getWithNewSize(LocationSize NewSize) const {
- MemoryLocation Copy(*this);
- Copy.Size = NewSize;
- return Copy;
- }
- MemoryLocation getWithoutAATags() const {
- MemoryLocation Copy(*this);
- Copy.AATags = AAMDNodes();
- return Copy;
- }
- bool operator==(const MemoryLocation &Other) const {
- return Ptr == Other.Ptr && Size == Other.Size && AATags == Other.AATags;
- }
- };
- // Specialize DenseMapInfo.
- template <> struct DenseMapInfo<LocationSize> {
- static inline LocationSize getEmptyKey() {
- return LocationSize::mapEmpty();
- }
- static inline LocationSize getTombstoneKey() {
- return LocationSize::mapTombstone();
- }
- static unsigned getHashValue(const LocationSize &Val) {
- return DenseMapInfo<uint64_t>::getHashValue(Val.toRaw());
- }
- static bool isEqual(const LocationSize &LHS, const LocationSize &RHS) {
- return LHS == RHS;
- }
- };
- template <> struct DenseMapInfo<MemoryLocation> {
- static inline MemoryLocation getEmptyKey() {
- return MemoryLocation(DenseMapInfo<const Value *>::getEmptyKey(),
- DenseMapInfo<LocationSize>::getEmptyKey());
- }
- static inline MemoryLocation getTombstoneKey() {
- return MemoryLocation(DenseMapInfo<const Value *>::getTombstoneKey(),
- DenseMapInfo<LocationSize>::getTombstoneKey());
- }
- static unsigned getHashValue(const MemoryLocation &Val) {
- return DenseMapInfo<const Value *>::getHashValue(Val.Ptr) ^
- DenseMapInfo<LocationSize>::getHashValue(Val.Size) ^
- DenseMapInfo<AAMDNodes>::getHashValue(Val.AATags);
- }
- static bool isEqual(const MemoryLocation &LHS, const MemoryLocation &RHS) {
- return LHS == RHS;
- }
- };
- }
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|