//===--- 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