35
35
#include " swift/SIL/SILArgument.h"
36
36
#include " swift/SIL/SILInstruction.h"
37
37
#include " swift/SIL/Projection.h"
38
+ #include " swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h"
38
39
#include " swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
39
40
#include " swift/SILOptimizer/PassManager/Passes.h"
40
41
#include " swift/SILOptimizer/PassManager/Transforms.h"
@@ -167,10 +168,10 @@ class AccessedStorage {
167
168
class RecordedAccess {
168
169
private:
169
170
BeginAccessInst *Inst;
170
- ProjectionPath SubPath;
171
+ const IndexTrieNode * SubPath;
171
172
172
173
public:
173
- RecordedAccess (BeginAccessInst *BAI, const ProjectionPath & SubPath)
174
+ RecordedAccess (BeginAccessInst *BAI, const IndexTrieNode * SubPath)
174
175
: Inst(BAI), SubPath(SubPath) {}
175
176
176
177
BeginAccessInst *getInstruction () const { return Inst; }
@@ -179,15 +180,15 @@ class RecordedAccess {
179
180
180
181
SILLocation getAccessLoc () const { return Inst->getLoc (); }
181
182
182
- const ProjectionPath & getSubPath () const { return SubPath; }
183
+ const IndexTrieNode * getSubPath () const { return SubPath; }
183
184
};
184
185
185
186
// / Records the in-progress accesses to a given sub path.
186
187
class SubAccessInfo {
187
188
public:
188
- SubAccessInfo (const ProjectionPath & P) : Path(P) {}
189
+ SubAccessInfo (const IndexTrieNode * P) : Path(P) {}
189
190
190
- ProjectionPath Path;
191
+ const IndexTrieNode * Path;
191
192
192
193
// / The number of in-progress 'read' accesses (that is 'begin_access [read]'
193
194
// / instructions that have not yet had the corresponding 'end_access').
@@ -202,7 +203,7 @@ class SubAccessInfo {
202
203
203
204
public:
204
205
// / Increment the count for given access.
205
- void beginAccess (BeginAccessInst *BAI, const ProjectionPath & SubPath) {
206
+ void beginAccess (BeginAccessInst *BAI, const IndexTrieNode * SubPath) {
206
207
if (!FirstAccess) {
207
208
assert (Reads == 0 && NonReads == 0 );
208
209
FirstAccess = RecordedAccess (BAI, SubPath);
@@ -250,14 +251,17 @@ class SubAccessInfo {
250
251
}
251
252
252
253
bool conflictsWithAccess (SILAccessKind Kind,
253
- const ProjectionPath & SubPath) const {
254
+ const IndexTrieNode * SubPath) const {
254
255
if (!canConflictWithAccessOfKind (Kind))
255
256
return false ;
256
257
257
- SubSeqRelation_t Relation = Path.computeSubSeqRelation (SubPath);
258
- // If the one path is a subsequence of the other (or they are the same)
259
- // then access the same storage.
260
- return (Relation != SubSeqRelation_t::Unknown);
258
+ return pathsConflict (Path, SubPath);
259
+ }
260
+
261
+ // / Returns true when the two subpaths access overlapping memory.
262
+ bool pathsConflict (const IndexTrieNode *Path1,
263
+ const IndexTrieNode *Path2) const {
264
+ return Path1->isPrefixOf (Path2) || Path2->isPrefixOf (Path1);
261
265
}
262
266
};
263
267
@@ -271,7 +275,7 @@ class AccessInfo {
271
275
SubAccessVector SubAccesses;
272
276
273
277
// / Returns the SubAccess info for accessing at the given SubPath.
274
- SubAccessInfo &findOrCreateSubAccessInfo (const ProjectionPath & SubPath) {
278
+ SubAccessInfo &findOrCreateSubAccessInfo (const IndexTrieNode * SubPath) {
275
279
for (auto &Info : SubAccesses) {
276
280
if (Info.Path == SubPath)
277
281
return Info;
@@ -283,7 +287,7 @@ class AccessInfo {
283
287
284
288
SubAccessVector::const_iterator
285
289
findFirstSubPathWithConflict (SILAccessKind OtherKind,
286
- const ProjectionPath & OtherSubPath) const {
290
+ const IndexTrieNode * OtherSubPath) const {
287
291
// Note this iteration requires deterministic ordering for repeatable
288
292
// diagnostics.
289
293
for (auto I = SubAccesses.begin (), E = SubAccesses.end (); I != E; ++I) {
@@ -299,7 +303,7 @@ class AccessInfo {
299
303
// Returns the previous access when beginning an access of the given Kind will
300
304
// result in a conflict with a previous access.
301
305
Optional<RecordedAccess>
302
- conflictsWithAccess (SILAccessKind Kind, const ProjectionPath & SubPath) const {
306
+ conflictsWithAccess (SILAccessKind Kind, const IndexTrieNode * SubPath) const {
303
307
auto I = findFirstSubPathWithConflict (Kind, SubPath);
304
308
if (I == SubAccesses.end ())
305
309
return None;
@@ -326,13 +330,13 @@ class AccessInfo {
326
330
}
327
331
328
332
// / Increment the count for given access.
329
- void beginAccess (BeginAccessInst *BAI, const ProjectionPath & SubPath) {
333
+ void beginAccess (BeginAccessInst *BAI, const IndexTrieNode * SubPath) {
330
334
SubAccessInfo &SubAccess = findOrCreateSubAccessInfo (SubPath);
331
335
SubAccess.beginAccess (BAI, SubPath);
332
336
}
333
337
334
338
// / Decrement the count for given access.
335
- void endAccess (EndAccessInst *EAI, const ProjectionPath & SubPath) {
339
+ void endAccess (EndAccessInst *EAI, const IndexTrieNode * SubPath) {
336
340
SubAccessInfo &SubAccess = findOrCreateSubAccessInfo (SubPath);
337
341
SubAccess.endAccess (EAI);
338
342
}
@@ -580,36 +584,46 @@ tryFixItWithCallToCollectionSwapAt(const BeginAccessInst *Access1,
580
584
// / that stored-property relaxation supports: struct stored properties
581
585
// / and tuple elements.
582
586
static std::string getPathDescription (DeclName BaseName, SILType BaseType,
583
- ProjectionPath SubPath, SILModule &M) {
587
+ const IndexTrieNode *SubPath,
588
+ SILModule &M) {
589
+ // Walk the trie to the root to collection the sequence (in reverse order).
590
+ llvm::SmallVector<unsigned , 4 > ReversedIndices;
591
+ const IndexTrieNode *I = SubPath;
592
+ while (!I->isRoot ()) {
593
+ ReversedIndices.push_back (I->getIndex ());
594
+ I = I->getParent ();
595
+ }
596
+
584
597
std::string sbuf;
585
598
llvm::raw_string_ostream os (sbuf);
586
599
587
600
os << " '" << BaseName;
588
601
589
602
SILType ContainingType = BaseType;
590
- for (auto &P : SubPath ) {
603
+ for (unsigned Index : reversed (ReversedIndices) ) {
591
604
os << " ." ;
592
- switch (P.getKind ()) {
593
- case ProjectionKind::Struct:
594
- os << P.getVarDecl (ContainingType)->getBaseName ();
595
- break ;
596
- case ProjectionKind::Tuple: {
597
- // Use the tuple element's name if present, otherwise use its index.
598
- Type SwiftTy = ContainingType.getSwiftRValueType ();
599
- TupleType *TupleTy = SwiftTy->getAs <TupleType>();
600
- assert (TupleTy && " Tuple projection on non-tuple type!?" );
601
605
602
- Identifier ElementName = TupleTy->getElement (P.getIndex ()).getName ();
606
+ if (ContainingType.getAs <StructType>()) {
607
+ NominalTypeDecl *D = ContainingType.getNominalOrBoundGenericNominal ();
608
+ auto Iter = D->getStoredProperties ().begin ();
609
+ std::advance (Iter, Index);
610
+ VarDecl *VD = *Iter;
611
+ os << VD->getBaseName ();
612
+ ContainingType = ContainingType.getFieldType (VD, M);
613
+ continue ;
614
+ }
615
+
616
+ if (auto TupleTy = ContainingType.getAs <TupleType>()) {
617
+ Identifier ElementName = TupleTy->getElement (Index).getName ();
603
618
if (ElementName.empty ())
604
- os << P. getIndex () ;
619
+ os << Index ;
605
620
else
606
621
os << ElementName;
607
- break ;
608
- }
609
- default :
610
- llvm_unreachable (" Unexpected projection kind in SubPath!" );
622
+ ContainingType = ContainingType.getTupleElementType (Index);
623
+ continue ;
611
624
}
612
- ContainingType = P.getType (ContainingType, M);
625
+
626
+ llvm_unreachable (" Unexpected type in projection SubPath!" );
613
627
}
614
628
615
629
os << " '" ;
@@ -784,8 +798,14 @@ static bool isCallToStandardLibrarySwap(ApplyInst *AI, ASTContext &Ctx) {
784
798
return FD == Ctx.getSwap (nullptr );
785
799
}
786
800
787
- static SILInstruction *getSingleAddressProjectionUser (SILInstruction *I) {
801
+ // / If the instruction is a field or tuple projection and it has a single
802
+ // / user return a pair of the single user and the projection index.
803
+ // / Otherwise, return a pair with the component nullptr and the second
804
+ // / unspecified.
805
+ static std::pair<SILInstruction *, unsigned >
806
+ getSingleAddressProjectionUser (SILInstruction *I) {
788
807
SILInstruction *SingleUser = nullptr ;
808
+ unsigned ProjectionIndex = 0 ;
789
809
790
810
for (Operand *Use : I->getUses ()) {
791
811
SILInstruction *User = Use->getUser ();
@@ -794,28 +814,43 @@ static SILInstruction *getSingleAddressProjectionUser(SILInstruction *I) {
794
814
795
815
// We have more than a single user so bail.
796
816
if (SingleUser)
797
- return nullptr ;
817
+ return std::make_pair ( nullptr , 0 ) ;
798
818
799
819
switch (User->getKind ()) {
800
820
case ValueKind::StructElementAddrInst:
821
+ ProjectionIndex = cast<StructElementAddrInst>(User)->getFieldNo ();
822
+ SingleUser = User;
823
+ break ;
801
824
case ValueKind::TupleElementAddrInst:
825
+ ProjectionIndex = cast<TupleElementAddrInst>(User)->getFieldNo ();
802
826
SingleUser = User;
803
827
break ;
804
828
default :
805
- return nullptr ;
829
+ return std::make_pair ( nullptr , 0 ) ;
806
830
}
807
831
}
808
832
809
- return SingleUser;
833
+ return std::make_pair ( SingleUser, ProjectionIndex) ;
810
834
}
811
835
812
- static ProjectionPath findSubPathAccessed (BeginAccessInst *BAI) {
813
- ProjectionPath SubPath (BAI->getType (), BAI->getType ());
836
+ // / Returns an IndexTrieNode that represents the single subpath accessed from
837
+ // / BAI or the root if no such node exists.
838
+ static const IndexTrieNode *findSubPathAccessed (BeginAccessInst *BAI,
839
+ IndexTrieNode *Root) {
840
+ IndexTrieNode *SubPath = Root;
814
841
842
+ // For each single-user projection of BAI, construct or get a node
843
+ // from the trie representing the index of the field or tuple element
844
+ // accessed by that projection.
815
845
SILInstruction *Iter = BAI;
846
+ while (true ) {
847
+ std::pair<SILInstruction *, unsigned > ProjectionUser =
848
+ getSingleAddressProjectionUser (Iter);
849
+ if (!ProjectionUser.first )
850
+ break ;
816
851
817
- while ((Iter = getSingleAddressProjectionUser (Iter))) {
818
- SubPath. push_back ( Projection ( Iter)) ;
852
+ SubPath = SubPath-> getChild (ProjectionUser. second );
853
+ Iter = ProjectionUser. first ;
819
854
}
820
855
821
856
return SubPath;
@@ -826,14 +861,15 @@ static ProjectionPath findSubPathAccessed(BeginAccessInst *BAI) {
826
861
// / with. Otherwise, returns None.
827
862
Optional<RecordedAccess> shouldReportAccess (const AccessInfo &Info,
828
863
swift::SILAccessKind Kind,
829
- const ProjectionPath & SubPath) {
864
+ const IndexTrieNode * SubPath) {
830
865
if (Info.alreadyHadConflict ())
831
866
return None;
832
867
833
868
return Info.conflictsWithAccess (Kind, SubPath);
834
869
}
835
870
836
- static void checkStaticExclusivity (SILFunction &Fn, PostOrderFunctionInfo *PO) {
871
+ static void checkStaticExclusivity (SILFunction &Fn, PostOrderFunctionInfo *PO,
872
+ AccessSummaryAnalysis *ASA) {
837
873
// The implementation relies on the following SIL invariants:
838
874
// - All incoming edges to a block must have the same in-progress
839
875
// accesses. This enables the analysis to not perform a data flow merge
@@ -899,7 +935,8 @@ static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO) {
899
935
SILAccessKind Kind = BAI->getAccessKind ();
900
936
const AccessedStorage &Storage = findAccessedStorage (BAI->getSource ());
901
937
AccessInfo &Info = Accesses[Storage];
902
- ProjectionPath SubPath = findSubPathAccessed (BAI);
938
+ const IndexTrieNode *SubPath =
939
+ findSubPathAccessed (BAI, ASA->getSubPathTrieRoot ());
903
940
if (auto Conflict = shouldReportAccess (Info, Kind, SubPath)) {
904
941
ConflictingAccesses.emplace_back (Storage, *Conflict,
905
942
RecordedAccess (BAI, SubPath));
@@ -914,7 +951,8 @@ static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO) {
914
951
AccessInfo &Info = It->getSecond ();
915
952
916
953
BeginAccessInst *BAI = EAI->getBeginAccess ();
917
- const ProjectionPath &SubPath = findSubPathAccessed (BAI);
954
+ const IndexTrieNode *SubPath =
955
+ findSubPathAccessed (BAI, ASA->getSubPathTrieRoot ());
918
956
Info.endAccess (EAI, SubPath);
919
957
920
958
// If the storage location has no more in-progress accesses, remove
@@ -958,7 +996,8 @@ class DiagnoseStaticExclusivity : public SILFunctionTransform {
958
996
return ;
959
997
960
998
PostOrderFunctionInfo *PO = getAnalysis<PostOrderAnalysis>()->get (Fn);
961
- checkStaticExclusivity (*Fn, PO);
999
+ auto *ASA = getAnalysis<AccessSummaryAnalysis>();
1000
+ checkStaticExclusivity (*Fn, PO, ASA);
962
1001
}
963
1002
};
964
1003
0 commit comments