@@ -66,22 +66,28 @@ using namespace swift;
6666using llvm::DenseMap;
6767using llvm::SmallDenseSet;
6868
69+ using DisjointAccessLocationKey =
70+ llvm::PointerUnion<const VarDecl *, const SILGlobalVariable *>;
71+
6972// Get the VarDecl that represents the DisjointAccessLocation for the given
7073// storage and access base. Returns nullptr for any storage that can't be
7174// partitioned into a disjoint location.
7275//
7376// Global storage is expected to be disjoint because identifyFormalAccess may
7477// only return Unidentified storage for a global variable access if the global
7578// is defined in a different module.
76- const VarDecl *
79+ static DisjointAccessLocationKey
7780getDisjointAccessLocation (AccessStorageWithBase storageAndBase) {
7881 auto storage = storageAndBase.storage ;
7982 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+ }
8089 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 ();
8591 case AccessStorage::Box:
8692 case AccessStorage::Stack:
8793 case AccessStorage::Tail:
@@ -95,6 +101,21 @@ getDisjointAccessLocation(AccessStorageWithBase storageAndBase) {
95101 llvm_unreachable (" unhandled kind" );
96102}
97103
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+
98119namespace {
99120// Implements an optimization to remove access markers on disjoint memory
100121// locations that are never reentrantly accessed. For a given memory location,
@@ -134,7 +155,8 @@ class GlobalAccessRemoval {
134155 BeginAccessSet beginAccessSet;
135156 };
136157
137- DenseMap<const VarDecl *, DisjointAccessLocationInfo> disjointAccessMap;
158+ DenseMap<DisjointAccessLocationKey, DisjointAccessLocationInfo>
159+ disjointAccessMap;
138160
139161public:
140162 GlobalAccessRemoval (SILModule &module ) : module (module ) {}
@@ -143,9 +165,8 @@ class GlobalAccessRemoval {
143165
144166protected:
145167 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);
149170 void removeNonreentrantAccess ();
150171};
151172} // namespace
@@ -169,15 +190,15 @@ void GlobalAccessRemoval::perform() {
169190void GlobalAccessRemoval::visitInstruction (SILInstruction *I) {
170191 if (auto *BAI = dyn_cast<BeginAccessInst>(I)) {
171192 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 (),
174195 BAI->hasNoNestedConflict ());
175196 return ;
176197 }
177198 if (auto *BUAI = dyn_cast<BeginUnpairedAccessInst>(I)) {
178199 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 (),
181202 BUAI->hasNoNestedConflict ());
182203 return ;
183204 }
@@ -213,21 +234,21 @@ void GlobalAccessRemoval::visitInstruction(SILInstruction *I) {
213234// key_path instruction somewhere else in the same module (or it must be dead
214235// code, or only access public properties).
215236//
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
217238// access. This is only legal when the access is known to be a local access, not
218239// a class property or global.
219240void GlobalAccessRemoval::recordAccess (SILInstruction *beginAccess,
220- const VarDecl *decl ,
241+ DisjointAccessLocationKey key ,
221242 AccessStorage::Kind storageKind,
222243 bool hasNoNestedConflict) {
223- if (!decl || module . isVisibleExternally (decl ))
244+ if (key. isNull () || isVisibleExternally (key, & module ))
224245 return ;
225246
226247 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 " );
229250
230- auto accessLocIter = disjointAccessMap.find (decl );
251+ auto accessLocIter = disjointAccessMap.find (key );
231252 if (accessLocIter != disjointAccessMap.end ()) {
232253 // Add this begin_access to an existing DisjointAccessLocationInfo.
233254 DisjointAccessLocationInfo &info = accessLocIter->second ;
@@ -245,22 +266,21 @@ void GlobalAccessRemoval::recordAccess(SILInstruction *beginAccess,
245266 info.noNestedConflict = hasNoNestedConflict;
246267 if (auto *BA = dyn_cast<BeginAccessInst>(beginAccess))
247268 info.beginAccessSet .insert (BA);
248- disjointAccessMap.insert (std::make_pair (decl , info));
269+ disjointAccessMap.insert (std::make_pair (key , info));
249270}
250271
251272// For each unique storage within this function that is never reentrantly
252273// accessed, promote all access checks for that storage to static enforcement.
253274void GlobalAccessRemoval::removeNonreentrantAccess () {
254- for (auto &declAndInfo : disjointAccessMap) {
255- const DisjointAccessLocationInfo &info = declAndInfo .second ;
275+ for (auto &keyAndInfo : disjointAccessMap) {
276+ const DisjointAccessLocationInfo &info = keyAndInfo .second ;
256277 if (!info.noNestedConflict )
257278 continue ;
258279
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 ));
264284
265285 // Non-deterministic iteration, only used to set a flag.
266286 for (BeginAccessInst *beginAccess : info.beginAccessSet ) {
0 commit comments