1 //===--- ModRef.h - Memory effect modelling ---------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Definitions of ModRefInfo and MemoryEffects, which are used to 10 // describe the memory effects of instructions. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_SUPPORT_MODREF_H 15 #define LLVM_SUPPORT_MODREF_H 16 17 #include "llvm/ADT/BitmaskEnum.h" 18 #include "llvm/ADT/Sequence.h" 19 #include "llvm/Support/raw_ostream.h" 20 21 namespace llvm { 22 23 /// Flags indicating whether a memory access modifies or references memory. 24 /// 25 /// This is no access at all, a modification, a reference, or both 26 /// a modification and a reference. 27 enum class ModRefInfo : uint8_t { 28 /// The access neither references nor modifies the value stored in memory. 29 NoModRef = 0, 30 /// The access may reference the value stored in memory. 31 Ref = 1, 32 /// The access may modify the value stored in memory. 33 Mod = 2, 34 /// The access may reference and may modify the value stored in memory. 35 ModRef = Ref | Mod, 36 LLVM_MARK_AS_BITMASK_ENUM(ModRef), 37 }; 38 39 [[nodiscard]] inline bool isNoModRef(const ModRefInfo MRI) { 40 return MRI == ModRefInfo::NoModRef; 41 } 42 [[nodiscard]] inline bool isModOrRefSet(const ModRefInfo MRI) { 43 return MRI != ModRefInfo::NoModRef; 44 } 45 [[nodiscard]] inline bool isModAndRefSet(const ModRefInfo MRI) { 46 return MRI == ModRefInfo::ModRef; 47 } 48 [[nodiscard]] inline bool isModSet(const ModRefInfo MRI) { 49 return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Mod); 50 } 51 [[nodiscard]] inline bool isRefSet(const ModRefInfo MRI) { 52 return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Ref); 53 } 54 55 /// Debug print ModRefInfo. 56 raw_ostream &operator<<(raw_ostream &OS, ModRefInfo MR); 57 58 /// The locations at which a function might access memory. 59 enum class IRMemLocation { 60 /// Access to memory via argument pointers. 61 ArgMem = 0, 62 /// Memory that is inaccessible via LLVM IR. 63 InaccessibleMem = 1, 64 /// Any other memory. 65 Other = 2, 66 67 /// Helpers to iterate all locations in the MemoryEffectsBase class. 68 First = ArgMem, 69 Last = Other, 70 }; 71 72 template <typename LocationEnum> class MemoryEffectsBase { 73 public: 74 using Location = LocationEnum; 75 76 private: 77 uint32_t Data = 0; 78 79 static constexpr uint32_t BitsPerLoc = 2; 80 static constexpr uint32_t LocMask = (1 << BitsPerLoc) - 1; 81 82 static uint32_t getLocationPos(Location Loc) { 83 return (uint32_t)Loc * BitsPerLoc; 84 } 85 86 MemoryEffectsBase(uint32_t Data) : Data(Data) {} 87 88 void setModRef(Location Loc, ModRefInfo MR) { 89 Data &= ~(LocMask << getLocationPos(Loc)); 90 Data |= static_cast<uint32_t>(MR) << getLocationPos(Loc); 91 } 92 93 public: 94 /// Returns iterator over all supported location kinds. 95 static auto locations() { 96 return enum_seq_inclusive(Location::First, Location::Last, 97 force_iteration_on_noniterable_enum); 98 } 99 100 /// Create MemoryEffectsBase that can access only the given location with the 101 /// given ModRefInfo. 102 MemoryEffectsBase(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); } 103 104 /// Create MemoryEffectsBase that can access any location with the given 105 /// ModRefInfo. 106 explicit MemoryEffectsBase(ModRefInfo MR) { 107 for (Location Loc : locations()) 108 setModRef(Loc, MR); 109 } 110 111 /// Create MemoryEffectsBase that can read and write any memory. 112 static MemoryEffectsBase unknown() { 113 return MemoryEffectsBase(ModRefInfo::ModRef); 114 } 115 116 /// Create MemoryEffectsBase that cannot read or write any memory. 117 static MemoryEffectsBase none() { 118 return MemoryEffectsBase(ModRefInfo::NoModRef); 119 } 120 121 /// Create MemoryEffectsBase that can read any memory. 122 static MemoryEffectsBase readOnly() { 123 return MemoryEffectsBase(ModRefInfo::Ref); 124 } 125 126 /// Create MemoryEffectsBase that can write any memory. 127 static MemoryEffectsBase writeOnly() { 128 return MemoryEffectsBase(ModRefInfo::Mod); 129 } 130 131 /// Create MemoryEffectsBase that can only access argument memory. 132 static MemoryEffectsBase argMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { 133 return MemoryEffectsBase(Location::ArgMem, MR); 134 } 135 136 /// Create MemoryEffectsBase that can only access inaccessible memory. 137 static MemoryEffectsBase 138 inaccessibleMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { 139 return MemoryEffectsBase(Location::InaccessibleMem, MR); 140 } 141 142 /// Create MemoryEffectsBase that can only access inaccessible or argument 143 /// memory. 144 static MemoryEffectsBase 145 inaccessibleOrArgMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { 146 MemoryEffectsBase FRMB = none(); 147 FRMB.setModRef(Location::ArgMem, MR); 148 FRMB.setModRef(Location::InaccessibleMem, MR); 149 return FRMB; 150 } 151 152 /// Create MemoryEffectsBase from an encoded integer value (used by memory 153 /// attribute). 154 static MemoryEffectsBase createFromIntValue(uint32_t Data) { 155 return MemoryEffectsBase(Data); 156 } 157 158 /// Convert MemoryEffectsBase into an encoded integer value (used by memory 159 /// attribute). 160 uint32_t toIntValue() const { 161 return Data; 162 } 163 164 /// Get ModRefInfo for the given Location. 165 ModRefInfo getModRef(Location Loc) const { 166 return ModRefInfo((Data >> getLocationPos(Loc)) & LocMask); 167 } 168 169 /// Get new MemoryEffectsBase with modified ModRefInfo for Loc. 170 MemoryEffectsBase getWithModRef(Location Loc, ModRefInfo MR) const { 171 MemoryEffectsBase ME = *this; 172 ME.setModRef(Loc, MR); 173 return ME; 174 } 175 176 /// Get new MemoryEffectsBase with NoModRef on the given Loc. 177 MemoryEffectsBase getWithoutLoc(Location Loc) const { 178 MemoryEffectsBase ME = *this; 179 ME.setModRef(Loc, ModRefInfo::NoModRef); 180 return ME; 181 } 182 183 /// Get ModRefInfo for any location. 184 ModRefInfo getModRef() const { 185 ModRefInfo MR = ModRefInfo::NoModRef; 186 for (Location Loc : locations()) 187 MR |= getModRef(Loc); 188 return MR; 189 } 190 191 /// Whether this function accesses no memory. 192 bool doesNotAccessMemory() const { return Data == 0; } 193 194 /// Whether this function only (at most) reads memory. 195 bool onlyReadsMemory() const { return !isModSet(getModRef()); } 196 197 /// Whether this function only (at most) writes memory. 198 bool onlyWritesMemory() const { return !isRefSet(getModRef()); } 199 200 /// Whether this function only (at most) accesses argument memory. 201 bool onlyAccessesArgPointees() const { 202 return getWithoutLoc(Location::ArgMem).doesNotAccessMemory(); 203 } 204 205 /// Whether this function may access argument memory. 206 bool doesAccessArgPointees() const { 207 return isModOrRefSet(getModRef(Location::ArgMem)); 208 } 209 210 /// Whether this function only (at most) accesses inaccessible memory. 211 bool onlyAccessesInaccessibleMem() const { 212 return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory(); 213 } 214 215 /// Whether this function only (at most) accesses argument and inaccessible 216 /// memory. 217 bool onlyAccessesInaccessibleOrArgMem() const { 218 return getWithoutLoc(Location::InaccessibleMem) 219 .getWithoutLoc(Location::ArgMem) 220 .doesNotAccessMemory(); 221 } 222 223 /// Intersect with other MemoryEffectsBase. 224 MemoryEffectsBase operator&(MemoryEffectsBase Other) const { 225 return MemoryEffectsBase(Data & Other.Data); 226 } 227 228 /// Intersect (in-place) with other MemoryEffectsBase. 229 MemoryEffectsBase &operator&=(MemoryEffectsBase Other) { 230 Data &= Other.Data; 231 return *this; 232 } 233 234 /// Union with other MemoryEffectsBase. 235 MemoryEffectsBase operator|(MemoryEffectsBase Other) const { 236 return MemoryEffectsBase(Data | Other.Data); 237 } 238 239 /// Union (in-place) with other MemoryEffectsBase. 240 MemoryEffectsBase &operator|=(MemoryEffectsBase Other) { 241 Data |= Other.Data; 242 return *this; 243 } 244 245 /// Subtract other MemoryEffectsBase. 246 MemoryEffectsBase operator-(MemoryEffectsBase Other) const { 247 return MemoryEffectsBase(Data & ~Other.Data); 248 } 249 250 /// Subtract (in-place) with other MemoryEffectsBase. 251 MemoryEffectsBase &operator-=(MemoryEffectsBase Other) { 252 Data &= ~Other.Data; 253 return *this; 254 } 255 256 /// Check whether this is the same as other MemoryEffectsBase. 257 bool operator==(MemoryEffectsBase Other) const { return Data == Other.Data; } 258 259 /// Check whether this is different from other MemoryEffectsBase. 260 bool operator!=(MemoryEffectsBase Other) const { return !operator==(Other); } 261 }; 262 263 /// Summary of how a function affects memory in the program. 264 /// 265 /// Loads from constant globals are not considered memory accesses for this 266 /// interface. Also, functions may freely modify stack space local to their 267 /// invocation without having to report it through these interfaces. 268 using MemoryEffects = MemoryEffectsBase<IRMemLocation>; 269 270 /// Debug print MemoryEffects. 271 raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB); 272 273 // Legacy alias. 274 using FunctionModRefBehavior = MemoryEffects; 275 276 } // namespace llvm 277 278 #endif 279