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
isNoModRef(const ModRefInfo MRI)39 [[nodiscard]] inline bool isNoModRef(const ModRefInfo MRI) {
40 return MRI == ModRefInfo::NoModRef;
41 }
isModOrRefSet(const ModRefInfo MRI)42 [[nodiscard]] inline bool isModOrRefSet(const ModRefInfo MRI) {
43 return MRI != ModRefInfo::NoModRef;
44 }
isModAndRefSet(const ModRefInfo MRI)45 [[nodiscard]] inline bool isModAndRefSet(const ModRefInfo MRI) {
46 return MRI == ModRefInfo::ModRef;
47 }
isModSet(const ModRefInfo MRI)48 [[nodiscard]] inline bool isModSet(const ModRefInfo MRI) {
49 return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Mod);
50 }
isRefSet(const ModRefInfo MRI)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
getLocationPos(Location Loc)82 static uint32_t getLocationPos(Location Loc) {
83 return (uint32_t)Loc * BitsPerLoc;
84 }
85
MemoryEffectsBase(uint32_t Data)86 MemoryEffectsBase(uint32_t Data) : Data(Data) {}
87
setModRef(Location Loc,ModRefInfo MR)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.
locations()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.
MemoryEffectsBase(Location Loc,ModRefInfo MR)102 MemoryEffectsBase(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); }
103
104 /// Create MemoryEffectsBase that can access any location with the given
105 /// ModRefInfo.
MemoryEffectsBase(ModRefInfo MR)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.
unknown()112 static MemoryEffectsBase unknown() {
113 return MemoryEffectsBase(ModRefInfo::ModRef);
114 }
115
116 /// Create MemoryEffectsBase that cannot read or write any memory.
none()117 static MemoryEffectsBase none() {
118 return MemoryEffectsBase(ModRefInfo::NoModRef);
119 }
120
121 /// Create MemoryEffectsBase that can read any memory.
readOnly()122 static MemoryEffectsBase readOnly() {
123 return MemoryEffectsBase(ModRefInfo::Ref);
124 }
125
126 /// Create MemoryEffectsBase that can write any memory.
writeOnly()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).
createFromIntValue(uint32_t Data)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).
toIntValue()160 uint32_t toIntValue() const {
161 return Data;
162 }
163
164 /// Get ModRefInfo for the given Location.
getModRef(Location Loc)165 ModRefInfo getModRef(Location Loc) const {
166 return ModRefInfo((Data >> getLocationPos(Loc)) & LocMask);
167 }
168
169 /// Get new MemoryEffectsBase with modified ModRefInfo for Loc.
getWithModRef(Location Loc,ModRefInfo MR)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.
getWithoutLoc(Location 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.
getModRef()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.
doesNotAccessMemory()192 bool doesNotAccessMemory() const { return Data == 0; }
193
194 /// Whether this function only (at most) reads memory.
onlyReadsMemory()195 bool onlyReadsMemory() const { return !isModSet(getModRef()); }
196
197 /// Whether this function only (at most) writes memory.
onlyWritesMemory()198 bool onlyWritesMemory() const { return !isRefSet(getModRef()); }
199
200 /// Whether this function only (at most) accesses argument memory.
onlyAccessesArgPointees()201 bool onlyAccessesArgPointees() const {
202 return getWithoutLoc(Location::ArgMem).doesNotAccessMemory();
203 }
204
205 /// Whether this function may access argument memory.
doesAccessArgPointees()206 bool doesAccessArgPointees() const {
207 return isModOrRefSet(getModRef(Location::ArgMem));
208 }
209
210 /// Whether this function only (at most) accesses inaccessible memory.
onlyAccessesInaccessibleMem()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.
onlyAccessesInaccessibleOrArgMem()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