blob: becfd27712490d8e3d368c5f15a767d0e2091f94 [file] [log] [blame]
//===--- ModRef.h - Memory effect modelling ---------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// Definitions of ModRefInfo and MemoryEffects, which are used to
// describe the memory effects of instructions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_IR_MODREF_H
#define LLVM_IR_MODREF_H
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
/// Flags indicating whether a memory access modifies or references memory.
///
/// This is no access at all, a modification, a reference, or both
/// a modification and a reference.
enum class ModRefInfo : uint8_t {
/// The access neither references nor modifies the value stored in memory.
NoModRef = 0,
/// The access may reference the value stored in memory.
Ref = 1,
/// The access may modify the value stored in memory.
Mod = 2,
/// The access may reference and may modify the value stored in memory.
ModRef = Ref | Mod,
LLVM_MARK_AS_BITMASK_ENUM(ModRef),
};
[[nodiscard]] inline bool isNoModRef(const ModRefInfo MRI) {
return MRI == ModRefInfo::NoModRef;
}
[[nodiscard]] inline bool isModOrRefSet(const ModRefInfo MRI) {
return MRI != ModRefInfo::NoModRef;
}
[[nodiscard]] inline bool isModAndRefSet(const ModRefInfo MRI) {
return MRI == ModRefInfo::ModRef;
}
[[nodiscard]] inline bool isModSet(const ModRefInfo MRI) {
return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Mod);
}
[[nodiscard]] inline bool isRefSet(const ModRefInfo MRI) {
return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Ref);
}
/// Debug print ModRefInfo.
raw_ostream &operator<<(raw_ostream &OS, ModRefInfo MR);
/// Summary of how a function affects memory in the program.
///
/// Loads from constant globals are not considered memory accesses for this
/// interface. Also, functions may freely modify stack space local to their
/// invocation without having to report it through these interfaces.
class MemoryEffects {
public:
/// The locations at which a function might access memory.
enum Location {
/// Access to memory via argument pointers.
ArgMem = 0,
/// Memory that is inaccessible via LLVM IR.
InaccessibleMem = 1,
/// Any other memory.
Other = 2,
};
private:
uint32_t Data = 0;
static constexpr uint32_t BitsPerLoc = 2;
static constexpr uint32_t LocMask = (1 << BitsPerLoc) - 1;
static uint32_t getLocationPos(Location Loc) {
return (uint32_t)Loc * BitsPerLoc;
}
MemoryEffects(uint32_t Data) : Data(Data) {}
void setModRef(Location Loc, ModRefInfo MR) {
Data &= ~(LocMask << getLocationPos(Loc));
Data |= static_cast<uint32_t>(MR) << getLocationPos(Loc);
}
friend raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB);
public:
/// Returns iterator over all supported location kinds.
static auto locations() {
return enum_seq_inclusive(Location::ArgMem, Location::Other,
force_iteration_on_noniterable_enum);
}
/// Create MemoryEffects that can access only the given location with the
/// given ModRefInfo.
MemoryEffects(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); }
/// Create MemoryEffects that can access any location with the given
/// ModRefInfo.
explicit MemoryEffects(ModRefInfo MR) {
for (Location Loc : locations())
setModRef(Loc, MR);
}
/// Create MemoryEffects that can read and write any memory.
static MemoryEffects unknown() {
return MemoryEffects(ModRefInfo::ModRef);
}
/// Create MemoryEffects that cannot read or write any memory.
static MemoryEffects none() {
return MemoryEffects(ModRefInfo::NoModRef);
}
/// Create MemoryEffects that can read any memory.
static MemoryEffects readOnly() {
return MemoryEffects(ModRefInfo::Ref);
}
/// Create MemoryEffects that can write any memory.
static MemoryEffects writeOnly() {
return MemoryEffects(ModRefInfo::Mod);
}
/// Create MemoryEffects that can only access argument memory.
static MemoryEffects argMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
return MemoryEffects(ArgMem, MR);
}
/// Create MemoryEffects that can only access inaccessible memory.
static MemoryEffects inaccessibleMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
return MemoryEffects(InaccessibleMem, MR);
}
/// Create MemoryEffects that can only access inaccessible or argument memory.
static MemoryEffects
inaccessibleOrArgMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
MemoryEffects FRMB = none();
FRMB.setModRef(ArgMem, MR);
FRMB.setModRef(InaccessibleMem, MR);
return FRMB;
}
/// Create MemoryEffects from an encoded integer value (used by memory
/// attribute).
static MemoryEffects createFromIntValue(uint32_t Data) {
return MemoryEffects(Data);
}
/// Convert MemoryEffects into an encoded integer value (used by memory
/// attribute).
uint32_t toIntValue() const {
return Data;
}
/// Get ModRefInfo for the given Location.
ModRefInfo getModRef(Location Loc) const {
return ModRefInfo((Data >> getLocationPos(Loc)) & LocMask);
}
/// Get new MemoryEffects with modified ModRefInfo for Loc.
MemoryEffects getWithModRef(Location Loc, ModRefInfo MR) const {
MemoryEffects ME = *this;
ME.setModRef(Loc, MR);
return ME;
}
/// Get new MemoryEffects with NoModRef on the given Loc.
MemoryEffects getWithoutLoc(Location Loc) const {
MemoryEffects ME = *this;
ME.setModRef(Loc, ModRefInfo::NoModRef);
return ME;
}
/// Get ModRefInfo for any location.
ModRefInfo getModRef() const {
ModRefInfo MR = ModRefInfo::NoModRef;
for (Location Loc : locations())
MR |= getModRef(Loc);
return MR;
}
/// Whether this function accesses no memory.
bool doesNotAccessMemory() const { return Data == 0; }
/// Whether this function only (at most) reads memory.
bool onlyReadsMemory() const { return !isModSet(getModRef()); }
/// Whether this function only (at most) writes memory.
bool onlyWritesMemory() const { return !isRefSet(getModRef()); }
/// Whether this function only (at most) accesses argument memory.
bool onlyAccessesArgPointees() const {
return getWithoutLoc(ArgMem).doesNotAccessMemory();
}
/// Whether this function may access argument memory.
bool doesAccessArgPointees() const {
return isModOrRefSet(getModRef(ArgMem));
}
/// Whether this function only (at most) accesses inaccessible memory.
bool onlyAccessesInaccessibleMem() const {
return getWithoutLoc(InaccessibleMem).doesNotAccessMemory();
}
/// Whether this function only (at most) accesses argument and inaccessible
/// memory.
bool onlyAccessesInaccessibleOrArgMem() const {
return isNoModRef(getModRef(Other));
}
/// Intersect with other MemoryEffects.
MemoryEffects operator&(MemoryEffects Other) const {
return MemoryEffects(Data & Other.Data);
}
/// Intersect (in-place) with other MemoryEffects.
MemoryEffects &operator&=(MemoryEffects Other) {
Data &= Other.Data;
return *this;
}
/// Union with other MemoryEffects.
MemoryEffects operator|(MemoryEffects Other) const {
return MemoryEffects(Data | Other.Data);
}
/// Union (in-place) with other MemoryEffects.
MemoryEffects &operator|=(MemoryEffects Other) {
Data |= Other.Data;
return *this;
}
/// Check whether this is the same as other MemoryEffects.
bool operator==(MemoryEffects Other) const {
return Data == Other.Data;
}
/// Check whether this is different from other MemoryEffects.
bool operator!=(MemoryEffects Other) const {
return !operator==(Other);
}
};
/// Debug print MemoryEffects.
raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB);
// Legacy alias.
using FunctionModRefBehavior = MemoryEffects;
} // namespace llvm
#endif