15
15
#ifndef SWIFT_SIL_MEMACCESSUTILS_H
16
16
#define SWIFT_SIL_MEMACCESSUTILS_H
17
17
18
- #include " swift/SIL/Projection.h"
19
18
#include " swift/SIL/InstructionUtils.h"
19
+ #include " swift/SIL/SILArgument.h"
20
+ #include " swift/SIL/SILBasicBlock.h"
20
21
#include " swift/SIL/SILInstruction.h"
21
22
#include " llvm/ADT/DenseMap.h"
22
23
@@ -28,31 +29,6 @@ inline bool accessKindMayConflict(SILAccessKind a, SILAccessKind b) {
28
29
return !(a == SILAccessKind::Read && b == SILAccessKind::Read);
29
30
}
30
31
31
- // / Represents the identity of a stored class property as a combination
32
- // / of a base and projection.
33
- class ObjectProjection {
34
- SILValue object;
35
- Projection proj;
36
-
37
- public:
38
- ObjectProjection (SILValue object, const Projection &projection)
39
- : object(object), proj(projection) {
40
- assert (object->getType ().isObject ());
41
- }
42
-
43
- SILValue getObject () const { return object; }
44
-
45
- const Projection &getProjection () const { return proj; }
46
-
47
- bool operator ==(const ObjectProjection &other) const {
48
- return object == other.object && proj == other.proj ;
49
- }
50
-
51
- bool operator !=(const ObjectProjection &other) const {
52
- return object != other.object || proj != other.proj ;
53
- }
54
- };
55
-
56
32
// / Represents the identity of a storage object being accessed.
57
33
// /
58
34
// / AccessedStorage may be one of several kinds of "identified" storage
@@ -107,7 +83,23 @@ class AccessedStorage {
107
83
// / of access base. Otherwise, return Unidentified.
108
84
static AccessedStorage::Kind classify (SILValue base);
109
85
86
+ // / Directly create an AccessedStorage for class property access.
87
+ static AccessedStorage forClass (SILValue object, unsigned propertyIndex) {
88
+ AccessedStorage storage;
89
+ storage.initKind (Class, propertyIndex);
90
+ storage.value = object;
91
+ return storage;
92
+ }
93
+
110
94
protected:
95
+ // Checking the storage kind is far more common than other fields. Make sure
96
+ // it can be byte load with no shift.
97
+ static const int ReservedKindBits = 8 ;
98
+ static_assert (ReservedKindBits >= NumKindBits, " Too many storage kinds." );
99
+
100
+ static const unsigned InvalidElementIndex =
101
+ (1 << (32 - ReservedKindBits)) - 1 ;
102
+
111
103
// Form a bitfield that is effectively a union over any pass-specific data
112
104
// with the fields used within this class as a common prefix.
113
105
//
@@ -122,9 +114,13 @@ class AccessedStorage {
122
114
// each begin_access to its storage object, unique access index, and summary
123
115
// info for that access.
124
116
union {
125
- uint64_t OpaqueBits;
126
- SWIFT_INLINE_BITFIELD_BASE (AccessedStorage, bitmax (NumKindBits, 8 ),
127
- Kind : bitmax (NumKindBits, 8 ));
117
+ uint64_t opaqueBits;
118
+ // elementIndex can overflow while gracefully degrading analysis. For now,
119
+ // reserve an absurd number of bits at a nice alignment boundary, but this
120
+ // can be reduced.
121
+ SWIFT_INLINE_BITFIELD_BASE (AccessedStorage, 32 , kind
122
+ : ReservedKindBits,
123
+ elementIndex : 32 - ReservedKindBits);
128
124
129
125
// Define bits for use in AccessedStorageAnalysis. Each identified storage
130
126
// object is mapped to one instance of this subclass.
@@ -157,59 +153,67 @@ class AccessedStorage {
157
153
158
154
private:
159
155
union {
156
+ // For non-class storage, 'value' is the access base. For class storage
157
+ // 'value' is the object base, where the access base is the class' stored
158
+ // property.
160
159
SILValue value;
161
- unsigned paramIndex;
162
160
SILGlobalVariable *global;
163
- ObjectProjection objProj;
164
161
};
165
162
166
- void initKind (Kind k) {
167
- Bits.OpaqueBits = 0 ;
168
- Bits.AccessedStorage .Kind = k;
163
+ void initKind (Kind k, unsigned elementIndex = InvalidElementIndex) {
164
+ Bits.opaqueBits = 0 ;
165
+ Bits.AccessedStorage .kind = k;
166
+ Bits.AccessedStorage .elementIndex = elementIndex;
167
+ }
168
+
169
+ unsigned getElementIndex () const { return Bits.AccessedStorage .elementIndex ; }
170
+ void setElementIndex (unsigned elementIndex) {
171
+ Bits.AccessedStorage .elementIndex = elementIndex;
169
172
}
170
173
171
174
public:
172
175
AccessedStorage () : value() { initKind (Unidentified); }
173
176
174
177
AccessedStorage (SILValue base, Kind kind);
175
178
176
- AccessedStorage (SILValue object, Projection projection)
177
- : objProj(object, projection) {
178
- initKind (Class);
179
- }
180
-
181
179
// Return true if this is a valid storage object.
182
180
operator bool () const { return getKind () != Unidentified || value; }
183
181
184
- Kind getKind () const { return static_cast <Kind>(Bits.AccessedStorage .Kind ); }
182
+ Kind getKind () const { return static_cast <Kind>(Bits.AccessedStorage .kind ); }
185
183
186
184
// Clear any bits reserved for subclass data. Useful for up-casting back to
187
185
// the base class.
188
- void resetSubclassData () { initKind (getKind ()); }
186
+ void resetSubclassData () {
187
+ initKind (getKind (), Bits.AccessedStorage .elementIndex );
188
+ }
189
189
190
190
SILValue getValue () const {
191
- assert (getKind () != Argument && getKind () != Global && getKind () != Class);
191
+ assert (getKind () != Global && getKind () != Class);
192
192
return value;
193
193
}
194
194
195
195
unsigned getParamIndex () const {
196
196
assert (getKind () == Argument);
197
- return paramIndex ;
197
+ return getElementIndex () ;
198
198
}
199
199
200
- SILArgument *getArgument (SILFunction *F ) const {
200
+ SILArgument *getArgument () const {
201
201
assert (getKind () == Argument);
202
- return F-> getArgument (paramIndex );
202
+ return cast<SILArgument>(value );
203
203
}
204
204
205
205
SILGlobalVariable *getGlobal () const {
206
206
assert (getKind () == Global);
207
207
return global;
208
208
}
209
209
210
- const ObjectProjection & getObjectProjection () const {
210
+ SILValue getObject () const {
211
211
assert (getKind () == Class);
212
- return objProj;
212
+ return value;
213
+ }
214
+ unsigned getPropertyIndex () const {
215
+ assert (getKind () == Class);
216
+ return getElementIndex ();
213
217
}
214
218
215
219
// / Return true if the given storage objects have identical storage locations.
@@ -223,16 +227,16 @@ class AccessedStorage {
223
227
switch (getKind ()) {
224
228
case Box:
225
229
case Stack:
230
+ case Argument:
226
231
case Yield:
227
232
case Nested:
228
233
case Unidentified:
229
234
return value == other.value ;
230
- case Argument:
231
- return paramIndex == other.paramIndex ;
232
235
case Global:
233
236
return global == other.global ;
234
237
case Class:
235
- return objProj == other.objProj ;
238
+ return value == other.value
239
+ && getElementIndex () == other.getElementIndex ();
236
240
}
237
241
}
238
242
@@ -286,19 +290,19 @@ class AccessedStorage {
286
290
// Classes are not uniquely identified by their base. However, if the
287
291
// underling objects have identical types and distinct property indices then
288
292
// they are distinct storage locations.
289
- auto &proj = getObjectProjection ();
290
- auto &otherProj = other.getObjectProjection ();
291
- if (proj.getObject ()->getType () == otherProj.getObject ()->getType ()
292
- && proj.getProjection () != otherProj.getProjection ()) {
293
+ if (getObject ()->getType () == other.getObject ()->getType ()
294
+ && getPropertyIndex () != other.getPropertyIndex ()) {
293
295
return true ;
294
296
}
295
297
return false ;
296
298
}
297
299
298
300
// / Returns the ValueDecl for the underlying storage, if it can be
299
- // / determined. Otherwise returns null. For diagnostics and checking via the
300
- // / ValueDecl if we are processing a `let` variable.
301
- const ValueDecl *getDecl (SILFunction *F) const ;
301
+ // / determined. Otherwise returns null.
302
+ // /
303
+ // / WARNING: This is not a constant-time operation. It is for diagnostics and
304
+ // / checking via the ValueDecl if we are processing a `let` variable.
305
+ const ValueDecl *getDecl () const ;
302
306
303
307
void print (raw_ostream &os) const ;
304
308
void dump () const ;
@@ -343,8 +347,8 @@ template <> struct DenseMapInfo<swift::AccessedStorage> {
343
347
case swift::AccessedStorage::Global:
344
348
return DenseMapInfo<void *>::getHashValue (storage.getGlobal ());
345
349
case swift::AccessedStorage::Class: {
346
- const swift::ObjectProjection &P = storage.getObjectProjection ();
347
- return llvm::hash_combine (P. getObject (), P. getProjection ());
350
+ return llvm::hash_combine ( storage.getObject (),
351
+ storage. getPropertyIndex ());
348
352
}
349
353
}
350
354
llvm_unreachable (" Unhandled AccessedStorageKind" );
0 commit comments