1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===--- 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
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|