#ifndef LLVM_ANALYSIS_MEMORYLOCATION_H
#define LLVM_ANALYSIS_MEMORYLOCATION_H
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/TypeSize.h"
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;
class LocationSize {
enum : uint64_t {
BeforeOrAfterPointer = ~uint64_t(0),
AfterPointer = BeforeOrAfterPointer - 1,
MapEmpty = BeforeOrAfterPointer - 2,
MapTombstone = BeforeOrAfterPointer - 3,
ImpreciseBit = uint64_t(1) << 63,
MaxValue = (MapTombstone - 1) & ~ImpreciseBit,
};
uint64_t Value;
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:
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.getFixedSize());
}
static LocationSize upperBound(uint64_t Value) {
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.getFixedSize());
}
constexpr static LocationSize afterPointer() {
return LocationSize(AfterPointer, Direct);
}
constexpr static LocationSize beforeOrAfterPointer() {
return LocationSize(BeforeOrAfterPointer, Direct);
}
constexpr static LocationSize mapTombstone() {
return LocationSize(MapTombstone, Direct);
}
constexpr static LocationSize mapEmpty() {
return LocationSize(MapEmpty, Direct);
}
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;
}
bool isPrecise() const {
return (Value & ImpreciseBit) == 0;
}
bool isZero() const { return hasValue() && getValue() == 0; }
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);
}
void print(raw_ostream &OS) const;
uint64_t toRaw() const { return Value; }
};
inline raw_ostream &operator<<(raw_ostream &OS, LocationSize Size) {
Size.print(OS);
return OS;
}
class MemoryLocation {
public:
enum : uint64_t { UnknownSize = ~UINT64_C(0) };
const Value *Ptr;
LocationSize Size;
AAMDNodes AATags;
void print(raw_ostream &OS) const { OS << *Ptr << " " << Size << "\n"; }
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 Optional<MemoryLocation> getOrNone(const Instruction *Inst);
static MemoryLocation getForSource(const MemTransferInst *MTI);
static MemoryLocation getForSource(const AtomicMemTransferInst *MTI);
static MemoryLocation getForSource(const AnyMemTransferInst *MTI);
static MemoryLocation getForDest(const MemIntrinsic *MI);
static MemoryLocation getForDest(const AtomicMemIntrinsic *MI);
static MemoryLocation getForDest(const AnyMemIntrinsic *MI);
static Optional<MemoryLocation> getForDest(const CallBase *CI,
const TargetLibraryInfo &TLI);
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);
}
static MemoryLocation getAfter(const Value *Ptr,
const AAMDNodes &AATags = AAMDNodes()) {
return MemoryLocation(Ptr, LocationSize::afterPointer(), AATags);
}
static MemoryLocation
getBeforeOrAfter(const Value *Ptr, const AAMDNodes &AATags = AAMDNodes()) {
return MemoryLocation(Ptr, LocationSize::beforeOrAfterPointer(), AATags);
}
static uint64_t getSizeOrUnknown(const TypeSize &T) {
return T.isScalable() ? UnknownSize : T.getFixedSize();
}
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;
}
};
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