@@ -129,10 +129,23 @@ class AccessEnforcementOptsInfo : public AccessedStorage {
129
129
Bits.AccessEnforcementOptsInfo .seenNestedConflict = 1 ;
130
130
}
131
131
132
+ // / Did a PostOrder walk previously find another access to the same
133
+ // / storage. If so, then this access could be merged with a subsequent access
134
+ // / after checking for conflicts.
135
+ bool seenIdenticalStorage () const {
136
+ return Bits.AccessEnforcementOptsInfo .seenIdenticalStorage ;
137
+ }
138
+
139
+ void setSeenIdenticalStorage () {
140
+ Bits.AccessEnforcementOptsInfo .seenIdenticalStorage = 1 ;
141
+ }
142
+
132
143
void dump () const {
133
144
AccessedStorage::dump ();
134
145
llvm::dbgs () << " access index: " << getAccessIndex () << " <"
135
- << (seenNestedConflict () ? " " : " no " ) << " conflict>\n " ;
146
+ << (seenNestedConflict () ? " " : " no " ) << " conflict> <"
147
+ << (seenIdenticalStorage () ? " " : " not " ) << " seen identical>"
148
+ << " \n " ;
136
149
}
137
150
};
138
151
using AccessInfo = AccessEnforcementOptsInfo;
@@ -267,21 +280,26 @@ class AccessConflictAndMergeAnalysis {
267
280
268
281
private:
269
282
LoopRegionFunctionInfo *LRFI;
283
+ PostOrderFunctionInfo *PO;
270
284
AccessedStorageAnalysis *ASA;
271
285
286
+ // Unique storage locations seen in this function.
287
+ AccessedStorageSet storageSet;
288
+
272
289
Result result;
273
290
274
291
public:
275
292
AccessConflictAndMergeAnalysis (LoopRegionFunctionInfo *LRFI,
293
+ PostOrderFunctionInfo *PO,
276
294
AccessedStorageAnalysis *ASA)
277
- : LRFI(LRFI), ASA(ASA) {}
295
+ : LRFI(LRFI), PO(PO ), ASA(ASA) {}
278
296
279
- void analyze ();
297
+ bool analyze ();
280
298
281
299
const Result &getResult () { return result; }
282
300
283
301
protected:
284
- void identifyBeginAccesses ();
302
+ bool identifyBeginAccesses ();
285
303
286
304
void
287
305
propagateAccessSetsBottomUp (LoopRegionToAccessedStorage ®ionToStorageMap,
@@ -456,6 +474,11 @@ void AccessConflictAndMergeAnalysis::insertOutOfScopeAccess(
456
474
RegionState &state, BeginAccessInst *beginAccess,
457
475
AccessInfo &currStorageInfo) {
458
476
477
+ if (!currStorageInfo.seenIdenticalStorage ()) {
478
+ LLVM_DEBUG (llvm::dbgs () << " Ignoring unmergeable access: " << *beginAccess);
479
+ return ;
480
+ }
481
+
459
482
auto identicalStorageIter = llvm::find_if (
460
483
state.outOfScopeConflictFreeAccesses , [&](BeginAccessInst *bai) {
461
484
auto storageInfo = result.getAccessInfo (bai);
@@ -470,8 +493,13 @@ void AccessConflictAndMergeAnalysis::insertOutOfScopeAccess(
470
493
}
471
494
472
495
// Top-level driver for AccessConflictAndMergeAnalysis
473
- void AccessConflictAndMergeAnalysis::analyze () {
474
- identifyBeginAccesses ();
496
+ //
497
+ // Returns true if the analysis succeeded.
498
+ bool AccessConflictAndMergeAnalysis::analyze () {
499
+ if (!identifyBeginAccesses ()) {
500
+ LLVM_DEBUG (llvm::dbgs () << " Skipping AccessConflictAndMergeAnalysis...\n " );
501
+ return false ;
502
+ }
475
503
LoopRegionToAccessedStorage accessSetsOfRegions;
476
504
// Populate a worklist of regions such that the top of the worklist is the
477
505
// innermost loop and the bottom of the worklist is the entry block.
@@ -501,6 +529,7 @@ void AccessConflictAndMergeAnalysis::analyze() {
501
529
}
502
530
}
503
531
}
532
+ return true ;
504
533
}
505
534
506
535
// Find all begin access operations in this function. Map each access to
@@ -509,29 +538,52 @@ void AccessConflictAndMergeAnalysis::analyze() {
509
538
//
510
539
// Also, add the storage location to the function's RegionStorage
511
540
//
541
+ // Returns true if it is worthwhile to continue the analysis.
542
+ //
512
543
// TODO: begin_unpaired_access is not tracked. Even though begin_unpaired_access
513
544
// isn't explicitly paired, it may be possible after devirtualization and
514
545
// inlining to find all uses of the scratch buffer. However, this doesn't
515
546
// currently happen in practice (rdar://40033735).
516
- void AccessConflictAndMergeAnalysis::identifyBeginAccesses () {
517
- for (auto &BB : *LRFI->getFunction ()) {
518
- for (auto &I : BB) {
547
+ bool AccessConflictAndMergeAnalysis::identifyBeginAccesses () {
548
+ bool seenPossibleNestedConflict = false ;
549
+ bool seenIdenticalStorage = false ;
550
+ // Scan blocks in PostOrder (bottom-up) to mark any accesses with identical
551
+ // storage to another reachable access. The earlier access must be marked
552
+ // because this analysis does forward data flow to find conflicts.
553
+ for (auto *BB : PO->getPostOrder ()) {
554
+ for (auto &I : llvm::reverse (*BB)) {
519
555
auto *beginAccess = dyn_cast<BeginAccessInst>(&I);
520
556
if (!beginAccess)
521
557
continue ;
522
558
523
559
if (beginAccess->getEnforcement () != SILAccessEnforcement::Dynamic)
524
560
continue ;
525
561
562
+ if (!beginAccess->hasNoNestedConflict ())
563
+ seenPossibleNestedConflict = true ;
564
+
526
565
// The accessed base is expected to be valid for begin_access, but for
527
566
// now, since this optimization runs at the end of the pipeline, we
528
567
// gracefully ignore unrecognized source address patterns, which show up
529
568
// here as an invalid `storage` value.
530
- const AccessedStorage & storage =
569
+ AccessedStorage storage =
531
570
findAccessedStorageNonNested (beginAccess->getSource ());
532
571
533
- auto iterAndSuccess = result.accessMap .try_emplace (
534
- beginAccess, static_cast <const AccessInfo &>(storage));
572
+ auto iterAndInserted = storageSet.insert (storage);
573
+
574
+ // After inserting it in storageSet, this storage object can be downcast
575
+ // to AccessInfo to use the pass-specific bits.
576
+ auto &accessInfo = static_cast <AccessInfo &>(storage);
577
+
578
+ // If the same location was seen later in the CFG, mark this access as one
579
+ // to check for merging.
580
+ if (!iterAndInserted.second ) {
581
+ seenIdenticalStorage = true ;
582
+ accessInfo.setSeenIdenticalStorage ();
583
+ }
584
+
585
+ auto iterAndSuccess =
586
+ result.accessMap .try_emplace (beginAccess, accessInfo);
535
587
(void )iterAndSuccess;
536
588
assert (iterAndSuccess.second );
537
589
@@ -541,6 +593,7 @@ void AccessConflictAndMergeAnalysis::identifyBeginAccesses() {
541
593
assert (!info.seenNestedConflict ());
542
594
}
543
595
}
596
+ return seenPossibleNestedConflict || seenIdenticalStorage;
544
597
}
545
598
546
599
// Returns a mapping from each loop sub-region to all its access storage
@@ -619,11 +672,14 @@ void AccessConflictAndMergeAnalysis::visitBeginAccess(
619
672
recordInScopeConflicts (state, beginAccessInfo, beginAccess->getAccessKind ());
620
673
// Remove in-scope conflicts to avoid checking them again.
621
674
removeConflicts (state.inScopeConflictFreeAccesses , beginAccessInfo);
622
- // Always record the current access as in-scope. It can potentially be folded
623
- // to [no_nested_conflict] independent of any enclosing access conflicts.
624
- bool inserted = state.inScopeConflictFreeAccesses .insert (beginAccess);
625
- (void )inserted;
626
- assert (inserted && " the begin_access should not have been seen yet." );
675
+
676
+ if (!beginAccess->hasNoNestedConflict ()) {
677
+ // Record the current access as in-scope. It can potentially be folded to
678
+ // [no_nested_conflict] independent of any enclosing access conflicts.
679
+ bool inserted = state.inScopeConflictFreeAccesses .insert (beginAccess);
680
+ (void )inserted;
681
+ assert (inserted && " the begin_access should not have been seen yet." );
682
+ }
627
683
628
684
// Find an out-of-scope access that is mergeable with this access. This is
629
685
// done at the BeginAccess because it doesn't matter whether the merged access
@@ -637,7 +693,7 @@ void AccessConflictAndMergeAnalysis::visitBeginAccess(
637
693
if (BeginAccessInst *mergeableAccess =
638
694
findMergeableOutOfScopeAccess (state, beginAccess)) {
639
695
LLVM_DEBUG (llvm::dbgs () << " Found mergable pair: " << *mergeableAccess
640
- << " , " << *beginAccess << " \n " );
696
+ << " with " << *beginAccess << " \n " );
641
697
result.mergePairs .emplace_back (mergeableAccess, beginAccess);
642
698
}
643
699
// For the purpose of data-flow, removing the out-of-scope access does not
@@ -950,8 +1006,10 @@ static bool mergeAccesses(
950
1006
SILFunction *F, PostDominanceInfo *postDomTree,
951
1007
const AccessConflictAndMergeAnalysis::MergeablePairs &mergePairs) {
952
1008
953
- if (mergePairs.empty ())
1009
+ if (mergePairs.empty ()) {
1010
+ LLVM_DEBUG (llvm::dbgs () << " Skipping SCC Analysis...\n " );
954
1011
return false ;
1012
+ }
955
1013
956
1014
bool changed = false ;
957
1015
@@ -999,7 +1057,7 @@ static bool mergeAccesses(
999
1057
continue ;
1000
1058
1001
1059
LLVM_DEBUG (llvm::dbgs ()
1002
- << " Merging: " << *childIns << " into " << *parentIns << " \n " );
1060
+ << " Merging " << *childIns << " into " << *parentIns << " \n " );
1003
1061
1004
1062
// Change the no nested conflict of parent if the child has a nested
1005
1063
// conflict.
@@ -1044,9 +1102,12 @@ struct AccessEnforcementOpts : public SILFunctionTransform {
1044
1102
<< F->getName () << " \n " );
1045
1103
1046
1104
LoopRegionFunctionInfo *LRFI = getAnalysis<LoopRegionAnalysis>()->get (F);
1105
+ PostOrderFunctionInfo *PO = getAnalysis<PostOrderAnalysis>()->get (F);
1047
1106
AccessedStorageAnalysis *ASA = getAnalysis<AccessedStorageAnalysis>();
1048
- AccessConflictAndMergeAnalysis a (LRFI, ASA);
1049
- a.analyze ();
1107
+ AccessConflictAndMergeAnalysis a (LRFI, PO, ASA);
1108
+ if (!a.analyze ())
1109
+ return ;
1110
+
1050
1111
auto result = a.getResult ();
1051
1112
1052
1113
// Perform access folding by setting the [no_nested_conflict] flag on
0 commit comments