Skip to content

Commit c773a0a

Browse files
authored
Merge pull request #16771 from atrick/accessfold
Add access marker removal to AccessEnforcementOpts.
2 parents dfff7ea + c5475c9 commit c773a0a

File tree

9 files changed

+788
-352
lines changed

9 files changed

+788
-352
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 72 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,17 @@ class ObjectProjection {
5353
}
5454
};
5555

56-
/// Represents the identity of a storage location being accessed.
56+
/// Represents the identity of a storage object being accessed.
5757
///
5858
/// AccessedStorage may be one of several kinds of "identified" storage
59-
/// locations, or may be valid, but Unidentified storage. An identified location
59+
/// objects, or may be valid, but Unidentified storage. An identified object
6060
/// is known to identify the base of the accessed storage, whether that is a
6161
/// SILValue that produces the base address, or a variable
6262
/// declaration. "Uniquely identified" storage refers to identified storage that
6363
/// cannot be aliased. For example, local allocations are uniquely identified,
6464
/// while global variables and class properties are not. Unidentified storage is
6565
/// associated with a SILValue that produces the accessed address but has not
66-
/// been determined to be the base of a storage location. It may, for example,
66+
/// been determined to be the base of a storage object. It may, for example,
6767
/// be a SILPHIArgument.
6868
///
6969
/// An invalid AccessedStorage object is marked Unidentified and contains an
@@ -72,19 +72,19 @@ class ObjectProjection {
7272
/// SILVerification could allow the optimizer to aggressively assert that
7373
/// AccessedStorage is always valid.
7474
///
75-
/// Note that the SILValue that represents a storage location is not
75+
/// Note that the SILValue that represents a storage object is not
7676
/// necessarilly an address type. It may instead be a SILBoxType.
7777
///
78-
/// AccessedStorage hashing and comparison is used to determine when two
79-
/// 'begin_access' instructions access the same or disjoint underlying
80-
/// locations.
78+
/// AccessedStorage hashing and comparison (via DenseMapInfo) is used to
79+
/// determine when two 'begin_access' instructions access the same or disjoint
80+
/// underlying objects.
8181
///
82-
/// Equality guarantees that two AccessStorage values refer to the same
83-
/// memory if both values are valid.
82+
/// `DenseMapInfo::isEqual()` guarantees that two AccessStorage values refer to
83+
/// the same memory if both values are valid.
8484
///
85-
/// Inequality does not guarantee that two identified AccessStorage values
86-
/// distinct. Inequality does guarantee that two *uniquely* identified
87-
/// AccessStorage values are distinct.
85+
/// `!DenseMapInfo::isEqual()` does not guarantee that two identified
86+
/// AccessStorage values are distinct. Inequality does, however, guarantee that
87+
/// two *uniquely* identified AccessStorage values are distinct.
8888
class AccessedStorage {
8989
public:
9090
/// Enumerate over all valid begin_access bases. Clients can use a covered
@@ -111,26 +111,42 @@ class AccessedStorage {
111111
// with the fields used within this class as a common prefix.
112112
//
113113
// This allows passes to embed analysis flags, and reserves enough space to
114-
// embed a unique access index.
114+
// embed a unique index.
115+
//
116+
// AccessedStorageAnalysis defines an StorageAccessInfo object that maps each
117+
// storage object within a function to its unique storage index and summary
118+
// information of that storage object.
119+
//
120+
// AccessEnforcementOpts defines an AccessEnforcementOptsInfo object that maps
121+
// each begin_access to its storage object, unique access index, and summary
122+
// info for that access.
115123
union {
116124
uint64_t OpaqueBits;
117-
SWIFT_INLINE_BITFIELD_BASE(AccessedStorage, bitmax(NumKindBits, 8), Kind
118-
: bitmax(NumKindBits, 8));
125+
SWIFT_INLINE_BITFIELD_BASE(AccessedStorage, bitmax(NumKindBits, 8),
126+
Kind : bitmax(NumKindBits, 8));
119127

120-
// Define bits for use in the AccessEnforcementOpts pass. Reserve the high
121-
// bit for a seenNestedConflict flag, which is the result of pass-specific
122-
// analysis. The remaning bits are sufficient to index all
128+
// Define bits for use in AccessedStorageAnalysis. Each identified storage
129+
// object is mapped to one instance of this subclass.
130+
SWIFT_INLINE_BITFIELD_FULL(StorageAccessInfo, AccessedStorage,
131+
64 - NumAccessedStorageBits,
132+
accessKind : NumSILAccessKindBits,
133+
noNestedConflict : 1,
134+
storageIndex : 64 - (NumAccessedStorageBits
135+
+ NumSILAccessKindBits
136+
+ 1));
137+
138+
// Define bits for use in the AccessEnforcementOpts pass. Each begin_access
139+
// in the function is mapped to one instance of this subclass. Reserve a
140+
// bit for a seenNestedConflict flag, which is the per-begin-access result
141+
// of pass-specific analysis. The remaning bits are sufficient to index all
123142
// begin_[unpaired_]access instructions.
124143
//
125-
// `AccessEnforcementOpts` does not need to be a defined class. This macro
126-
// simply defines the pass-specific name "AccessEnforcementOptsBitfield".
127-
//
128-
// `AccessedStorage` identifies the AccessedStoredBitfield defined above,
144+
// `AccessedStorage` refers to the AccessedStorageBitfield defined above,
129145
// setting aside enough bits for common data.
130146
SWIFT_INLINE_BITFIELD_FULL(AccessEnforcementOptsInfo, AccessedStorage,
131147
64 - NumAccessedStorageBits,
132-
beginAccessIndex : 63 - NumAccessedStorageBits,
133-
seenNestedConflict : 1);
148+
seenNestedConflict : 1,
149+
beginAccessIndex : 63 - NumAccessedStorageBits);
134150
} Bits;
135151

136152
private:
@@ -156,7 +172,7 @@ class AccessedStorage {
156172
initKind(Class);
157173
}
158174

159-
// Return true if this is a valid storage location.
175+
// Return true if this is a valid storage object.
160176
operator bool() const { return getKind() != Unidentified || value; }
161177

162178
Kind getKind() const { return static_cast<Kind>(Bits.AccessedStorage.Kind); }
@@ -205,6 +221,20 @@ class AccessedStorage {
205221
}
206222
}
207223

224+
bool isLocal() const {
225+
switch (getKind()) {
226+
case Box:
227+
case Stack:
228+
return true;
229+
case Global:
230+
case Class:
231+
case Argument:
232+
case Nested:
233+
case Unidentified:
234+
return false;
235+
}
236+
}
237+
208238
bool isUniquelyIdentified() const {
209239
switch (getKind()) {
210240
case Box:
@@ -231,6 +261,13 @@ class AccessedStorage {
231261

232262
void print(raw_ostream &os) const;
233263
void dump() const;
264+
265+
private:
266+
// Disable direct comparison because we allow subclassing with bitfields.
267+
// Currently, we use DenseMapInfo to unique storage, which defines key
268+
// equalilty only in terms of the base AccessedStorage class bits.
269+
bool operator==(const AccessedStorage &) const = delete;
270+
bool operator!=(const AccessedStorage &) const = delete;
234271
};
235272
} // end namespace swift
236273

@@ -300,9 +337,9 @@ namespace swift {
300337
/// memory, return an AccessedStorage object that identifies the formal access.
301338
///
302339
/// The returned AccessedStorage represents the best attempt to find the base of
303-
/// the storage location being accessed at `sourceAddr`. This may be a fully
340+
/// the storage object being accessed at `sourceAddr`. This may be a fully
304341
/// identified storage base of known kind, or a valid but Unidentified storage
305-
/// location, such as a SILPHIArgument.
342+
/// object, such as a SILPHIArgument.
306343
///
307344
/// This may return an invalid storage object if the address producer is not
308345
/// recognized by a whitelist of recognizable access patterns. The result must
@@ -347,6 +384,14 @@ bool isPossibleFormalAccessBase(const AccessedStorage &storage, SILFunction *F);
347384
void visitAccessedAddress(SILInstruction *I,
348385
llvm::function_ref<void(Operand *)> visitor);
349386

387+
/// Perform a RAUW operation on begin_access with it's own source operand.
388+
/// Then erase the begin_access and all associated end_access instructions.
389+
/// Return an iterator to the following instruction.
390+
///
391+
/// The caller should use this iterator rather than assuming that the
392+
/// instruction following this begin_access was not also erased.
393+
SILBasicBlock::iterator removeBeginAccess(BeginAccessInst *beginAccess);
394+
350395
} // end namespace swift
351396

352397
#endif

include/swift/SIL/SILInstruction.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3184,8 +3184,10 @@ enum class SILAccessKind : uint8_t {
31843184
Deinit,
31853185

31863186
// This enum is encoded.
3187-
Last = Deinit
3187+
Last = Deinit,
31883188
};
3189+
enum { NumSILAccessKindBits = 2 };
3190+
31893191
StringRef getSILAccessKindName(SILAccessKind kind);
31903192

31913193
/// Different kinds of exclusivity enforcement for accesses.

0 commit comments

Comments
 (0)