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