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_IR_MODREF_H
15 #define LLVM_IR_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 /// Summary of how a function affects memory in the program.
59 ///
60 /// Loads from constant globals are not considered memory accesses for this
61 /// interface. Also, functions may freely modify stack space local to their
62 /// invocation without having to report it through these interfaces.
63 class MemoryEffects {
64 public:
65 /// The locations at which a function might access memory.
66 enum Location {
67 /// Access to memory via argument pointers.
68 ArgMem = 0,
69 /// Memory that is inaccessible via LLVM IR.
70 InaccessibleMem = 1,
71 /// Any other memory.
72 Other = 2,
73 };
74
75 private:
76 uint32_t Data = 0;
77
78 static constexpr uint32_t BitsPerLoc = 2;
79 static constexpr uint32_t LocMask = (1 << BitsPerLoc) - 1;
80
getLocationPos(Location Loc)81 static uint32_t getLocationPos(Location Loc) {
82 return (uint32_t)Loc * BitsPerLoc;
83 }
84
MemoryEffects(uint32_t Data)85 MemoryEffects(uint32_t Data) : Data(Data) {}
86
setModRef(Location Loc,ModRefInfo MR)87 void setModRef(Location Loc, ModRefInfo MR) {
88 Data &= ~(LocMask << getLocationPos(Loc));
89 Data |= static_cast<uint32_t>(MR) << getLocationPos(Loc);
90 }
91
92 friend raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB);
93
94 public:
95 /// Returns iterator over all supported location kinds.
locations()96 static auto locations() {
97 return enum_seq_inclusive(Location::ArgMem, Location::Other,
98 force_iteration_on_noniterable_enum);
99 }
100
101 /// Create MemoryEffects that can access only the given location with the
102 /// given ModRefInfo.
MemoryEffects(Location Loc,ModRefInfo MR)103 MemoryEffects(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); }
104
105 /// Create MemoryEffects that can access any location with the given
106 /// ModRefInfo.
MemoryEffects(ModRefInfo MR)107 explicit MemoryEffects(ModRefInfo MR) {
108 for (Location Loc : locations())
109 setModRef(Loc, MR);
110 }
111
112 /// Create MemoryEffects that can read and write any memory.
unknown()113 static MemoryEffects unknown() {
114 return MemoryEffects(ModRefInfo::ModRef);
115 }
116
117 /// Create MemoryEffects that cannot read or write any memory.
none()118 static MemoryEffects none() {
119 return MemoryEffects(ModRefInfo::NoModRef);
120 }
121
122 /// Create MemoryEffects that can read any memory.
readOnly()123 static MemoryEffects readOnly() {
124 return MemoryEffects(ModRefInfo::Ref);
125 }
126
127 /// Create MemoryEffects that can write any memory.
writeOnly()128 static MemoryEffects writeOnly() {
129 return MemoryEffects(ModRefInfo::Mod);
130 }
131
132 /// Create MemoryEffects that can only access argument memory.
133 static MemoryEffects argMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
134 return MemoryEffects(ArgMem, MR);
135 }
136
137 /// Create MemoryEffects that can only access inaccessible memory.
138 static MemoryEffects inaccessibleMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
139 return MemoryEffects(InaccessibleMem, MR);
140 }
141
142 /// Create MemoryEffects that can only access inaccessible or argument memory.
143 static MemoryEffects
144 inaccessibleOrArgMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
145 MemoryEffects FRMB = none();
146 FRMB.setModRef(ArgMem, MR);
147 FRMB.setModRef(InaccessibleMem, MR);
148 return FRMB;
149 }
150
151 /// Create MemoryEffects from an encoded integer value (used by memory
152 /// attribute).
createFromIntValue(uint32_t Data)153 static MemoryEffects createFromIntValue(uint32_t Data) {
154 return MemoryEffects(Data);
155 }
156
157 /// Convert MemoryEffects into an encoded integer value (used by memory
158 /// attribute).
toIntValue()159 uint32_t toIntValue() const {
160 return Data;
161 }
162
163 /// Get ModRefInfo for the given Location.
getModRef(Location Loc)164 ModRefInfo getModRef(Location Loc) const {
165 return ModRefInfo((Data >> getLocationPos(Loc)) & LocMask);
166 }
167
168 /// Get new MemoryEffects with modified ModRefInfo for Loc.
getWithModRef(Location Loc,ModRefInfo MR)169 MemoryEffects getWithModRef(Location Loc, ModRefInfo MR) const {
170 MemoryEffects ME = *this;
171 ME.setModRef(Loc, MR);
172 return ME;
173 }
174
175 /// Get new MemoryEffects with NoModRef on the given Loc.
getWithoutLoc(Location Loc)176 MemoryEffects getWithoutLoc(Location Loc) const {
177 MemoryEffects ME = *this;
178 ME.setModRef(Loc, ModRefInfo::NoModRef);
179 return ME;
180 }
181
182 /// Get ModRefInfo for any location.
getModRef()183 ModRefInfo getModRef() const {
184 ModRefInfo MR = ModRefInfo::NoModRef;
185 for (Location Loc : locations())
186 MR |= getModRef(Loc);
187 return MR;
188 }
189
190 /// Whether this function accesses no memory.
doesNotAccessMemory()191 bool doesNotAccessMemory() const { return Data == 0; }
192
193 /// Whether this function only (at most) reads memory.
onlyReadsMemory()194 bool onlyReadsMemory() const { return !isModSet(getModRef()); }
195
196 /// Whether this function only (at most) writes memory.
onlyWritesMemory()197 bool onlyWritesMemory() const { return !isRefSet(getModRef()); }
198
199 /// Whether this function only (at most) accesses argument memory.
onlyAccessesArgPointees()200 bool onlyAccessesArgPointees() const {
201 return getWithoutLoc(ArgMem).doesNotAccessMemory();
202 }
203
204 /// Whether this function may access argument memory.
doesAccessArgPointees()205 bool doesAccessArgPointees() const {
206 return isModOrRefSet(getModRef(ArgMem));
207 }
208
209 /// Whether this function only (at most) accesses inaccessible memory.
onlyAccessesInaccessibleMem()210 bool onlyAccessesInaccessibleMem() const {
211 return getWithoutLoc(InaccessibleMem).doesNotAccessMemory();
212 }
213
214 /// Whether this function only (at most) accesses argument and inaccessible
215 /// memory.
onlyAccessesInaccessibleOrArgMem()216 bool onlyAccessesInaccessibleOrArgMem() const {
217 return isNoModRef(getModRef(Other));
218 }
219
220 /// Intersect with other MemoryEffects.
221 MemoryEffects operator&(MemoryEffects Other) const {
222 return MemoryEffects(Data & Other.Data);
223 }
224
225 /// Intersect (in-place) with other MemoryEffects.
226 MemoryEffects &operator&=(MemoryEffects Other) {
227 Data &= Other.Data;
228 return *this;
229 }
230
231 /// Union with other MemoryEffects.
232 MemoryEffects operator|(MemoryEffects Other) const {
233 return MemoryEffects(Data | Other.Data);
234 }
235
236 /// Union (in-place) with other MemoryEffects.
237 MemoryEffects &operator|=(MemoryEffects Other) {
238 Data |= Other.Data;
239 return *this;
240 }
241
242 /// Check whether this is the same as other MemoryEffects.
243 bool operator==(MemoryEffects Other) const {
244 return Data == Other.Data;
245 }
246
247 /// Check whether this is different from other MemoryEffects.
248 bool operator!=(MemoryEffects Other) const {
249 return !operator==(Other);
250 }
251 };
252
253 /// Debug print MemoryEffects.
254 raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB);
255
256 // Legacy alias.
257 using FunctionModRefBehavior = MemoryEffects;
258
259 } // namespace llvm
260
261 #endif
262