@@ -66,22 +66,28 @@ using namespace swift;
66
66
using llvm::DenseMap;
67
67
using llvm::SmallDenseSet;
68
68
69
+ using DisjointAccessLocationKey =
70
+ llvm::PointerUnion<const VarDecl *, const SILGlobalVariable *>;
71
+
69
72
// Get the VarDecl that represents the DisjointAccessLocation for the given
70
73
// storage and access base. Returns nullptr for any storage that can't be
71
74
// partitioned into a disjoint location.
72
75
//
73
76
// Global storage is expected to be disjoint because identifyFormalAccess may
74
77
// only return Unidentified storage for a global variable access if the global
75
78
// is defined in a different module.
76
- const VarDecl *
79
+ static DisjointAccessLocationKey
77
80
getDisjointAccessLocation (AccessStorageWithBase storageAndBase) {
78
81
auto storage = storageAndBase.storage ;
79
82
switch (storage.getKind ()) {
83
+ case AccessStorage::Class: {
84
+ auto *varDecl = cast<VarDecl>(storageAndBase.getDecl ());
85
+ // For class properties, a VarDecl can always be derived from AccessBase.
86
+ assert (varDecl && " no VarDecl for class property" );
87
+ return varDecl;
88
+ }
80
89
case AccessStorage::Global:
81
- case AccessStorage::Class:
82
- // Class and Globals are always a VarDecl, but the global decl may have a
83
- // null value for global_addr -> phi.
84
- return cast_or_null<VarDecl>(storageAndBase.getDecl ());
90
+ return storageAndBase.getAccessBase ().getGlobal ();
85
91
case AccessStorage::Box:
86
92
case AccessStorage::Stack:
87
93
case AccessStorage::Tail:
@@ -95,6 +101,21 @@ getDisjointAccessLocation(AccessStorageWithBase storageAndBase) {
95
101
llvm_unreachable (" unhandled kind" );
96
102
}
97
103
104
+ static bool isVisibleExternally (DisjointAccessLocationKey key, SILModule *mod) {
105
+ if (auto *decl = key.dyn_cast <const VarDecl *>())
106
+ return mod->isVisibleExternally (decl);
107
+
108
+ auto *global = key.get <const SILGlobalVariable *>();
109
+ return isPossiblyUsedExternally (global->getLinkage (), mod->isWholeModule ());
110
+ }
111
+
112
+ static StringRef getName (DisjointAccessLocationKey key) {
113
+ if (auto *decl = key.dyn_cast <const VarDecl *>())
114
+ return decl->getNameStr ();
115
+
116
+ return key.get <const SILGlobalVariable *>()->getName ();
117
+ }
118
+
98
119
namespace {
99
120
// Implements an optimization to remove access markers on disjoint memory
100
121
// locations that are never reentrantly accessed. For a given memory location,
@@ -134,7 +155,8 @@ class GlobalAccessRemoval {
134
155
BeginAccessSet beginAccessSet;
135
156
};
136
157
137
- DenseMap<const VarDecl *, DisjointAccessLocationInfo> disjointAccessMap;
158
+ DenseMap<DisjointAccessLocationKey, DisjointAccessLocationInfo>
159
+ disjointAccessMap;
138
160
139
161
public:
140
162
GlobalAccessRemoval (SILModule &module ) : module (module ) {}
@@ -143,9 +165,8 @@ class GlobalAccessRemoval {
143
165
144
166
protected:
145
167
void visitInstruction (SILInstruction *I);
146
- void recordAccess (SILInstruction *beginAccess, const VarDecl *decl,
147
- AccessStorage::Kind storageKind,
148
- bool hasNoNestedConflict);
168
+ void recordAccess (SILInstruction *beginAccess, DisjointAccessLocationKey key,
169
+ AccessStorage::Kind storageKind, bool hasNoNestedConflict);
149
170
void removeNonreentrantAccess ();
150
171
};
151
172
} // namespace
@@ -169,15 +190,15 @@ void GlobalAccessRemoval::perform() {
169
190
void GlobalAccessRemoval::visitInstruction (SILInstruction *I) {
170
191
if (auto *BAI = dyn_cast<BeginAccessInst>(I)) {
171
192
auto storageAndBase = AccessStorageWithBase::compute (BAI->getSource ());
172
- const VarDecl *decl = getDisjointAccessLocation (storageAndBase);
173
- recordAccess (BAI, decl , storageAndBase.storage .getKind (),
193
+ auto key = getDisjointAccessLocation (storageAndBase);
194
+ recordAccess (BAI, key , storageAndBase.storage .getKind (),
174
195
BAI->hasNoNestedConflict ());
175
196
return ;
176
197
}
177
198
if (auto *BUAI = dyn_cast<BeginUnpairedAccessInst>(I)) {
178
199
auto storageAndBase = AccessStorageWithBase::compute (BUAI->getSource ());
179
- const VarDecl *decl = getDisjointAccessLocation (storageAndBase);
180
- recordAccess (BUAI, decl , storageAndBase.storage .getKind (),
200
+ auto key = getDisjointAccessLocation (storageAndBase);
201
+ recordAccess (BUAI, key , storageAndBase.storage .getKind (),
181
202
BUAI->hasNoNestedConflict ());
182
203
return ;
183
204
}
@@ -213,21 +234,21 @@ void GlobalAccessRemoval::visitInstruction(SILInstruction *I) {
213
234
// key_path instruction somewhere else in the same module (or it must be dead
214
235
// code, or only access public properties).
215
236
//
216
- // `decl ` may be nullptr if the declaration can't be determined from the
237
+ // `key ` may be nullptr if the variable's identity cannot be determined from the
217
238
// access. This is only legal when the access is known to be a local access, not
218
239
// a class property or global.
219
240
void GlobalAccessRemoval::recordAccess (SILInstruction *beginAccess,
220
- const VarDecl *decl ,
241
+ DisjointAccessLocationKey key ,
221
242
AccessStorage::Kind storageKind,
222
243
bool hasNoNestedConflict) {
223
- if (!decl || module . isVisibleExternally (decl ))
244
+ if (key. isNull () || isVisibleExternally (key, & module ))
224
245
return ;
225
246
226
247
LLVM_DEBUG (if (!hasNoNestedConflict) llvm::dbgs ()
227
- << " Nested conflict on " << decl-> getName () << " at"
228
- << *beginAccess << " \n " );
248
+ << " Nested conflict on " << getName (key ) << " at" << *beginAccess
249
+ << " \n " );
229
250
230
- auto accessLocIter = disjointAccessMap.find (decl );
251
+ auto accessLocIter = disjointAccessMap.find (key );
231
252
if (accessLocIter != disjointAccessMap.end ()) {
232
253
// Add this begin_access to an existing DisjointAccessLocationInfo.
233
254
DisjointAccessLocationInfo &info = accessLocIter->second ;
@@ -245,22 +266,21 @@ void GlobalAccessRemoval::recordAccess(SILInstruction *beginAccess,
245
266
info.noNestedConflict = hasNoNestedConflict;
246
267
if (auto *BA = dyn_cast<BeginAccessInst>(beginAccess))
247
268
info.beginAccessSet .insert (BA);
248
- disjointAccessMap.insert (std::make_pair (decl , info));
269
+ disjointAccessMap.insert (std::make_pair (key , info));
249
270
}
250
271
251
272
// For each unique storage within this function that is never reentrantly
252
273
// accessed, promote all access checks for that storage to static enforcement.
253
274
void GlobalAccessRemoval::removeNonreentrantAccess () {
254
- for (auto &declAndInfo : disjointAccessMap) {
255
- const DisjointAccessLocationInfo &info = declAndInfo .second ;
275
+ for (auto &keyAndInfo : disjointAccessMap) {
276
+ const DisjointAccessLocationInfo &info = keyAndInfo .second ;
256
277
if (!info.noNestedConflict )
257
278
continue ;
258
279
259
- const VarDecl *decl = declAndInfo.first ;
260
- LLVM_DEBUG (llvm::dbgs () << " Eliminating all formal access on "
261
- << decl->getName () << " \n " );
262
- assert (!module .isVisibleExternally (decl));
263
- (void )decl;
280
+ auto key = keyAndInfo.first ;
281
+ LLVM_DEBUG (llvm::dbgs ()
282
+ << " Eliminating all formal access on " << getName (key) << " \n " );
283
+ assert (!isVisibleExternally (key, &module ));
264
284
265
285
// Non-deterministic iteration, only used to set a flag.
266
286
for (BeginAccessInst *beginAccess : info.beginAccessSet ) {
0 commit comments