@@ -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,
@@ -423,10 +441,12 @@ BeginAccessInst *AccessConflictAndMergeAnalysis::findMergeableOutOfScopeAccess(
423
441
// Given a mergeableAccess, 'A', another out-of-scope access, 'B', and the
424
442
// current access, 'C' which has identical storage as 'A', the only situation
425
443
// in which it is illegal to merge 'A' with 'C' is when 'B' has non-distinct
426
- // storage from 'A'/'C' and 'B' begins after 'A' and ends before 'C'. This
427
- // would introduce a false conflict. Since it is impossible to determine here
428
- // whether 'A' and 'B' overlap, we assume they do not and avoid merging. The
429
- // case in which they actually do overlap is an unimportant to optimize.
444
+ // storage from 'A'/'C', 'B' begins after 'A', and 'B' ends before
445
+ // 'C'. Merging 'A' with 'C' would then introduce a false conflict. Since it
446
+ // is impossible to determine here whether 'A' and 'B' overlap, we assume they
447
+ // do not and simply avoid merging whenever 'B' and 'C' overlap. It is not
448
+ // important to optimize the case in which 'A' and 'B' overlap because
449
+ // potential conflicts like that are unlikely.
430
450
if (llvm::any_of (state.outOfScopeConflictFreeAccesses ,
431
451
[&](BeginAccessInst *bai) {
432
452
auto storageInfo = result.getAccessInfo (bai);
@@ -454,6 +474,11 @@ void AccessConflictAndMergeAnalysis::insertOutOfScopeAccess(
454
474
RegionState &state, BeginAccessInst *beginAccess,
455
475
AccessInfo &currStorageInfo) {
456
476
477
+ if (!currStorageInfo.seenIdenticalStorage ()) {
478
+ LLVM_DEBUG (llvm::dbgs () << " Ignoring unmergeable access: " << *beginAccess);
479
+ return ;
480
+ }
481
+
457
482
auto identicalStorageIter = llvm::find_if (
458
483
state.outOfScopeConflictFreeAccesses , [&](BeginAccessInst *bai) {
459
484
auto storageInfo = result.getAccessInfo (bai);
@@ -468,8 +493,13 @@ void AccessConflictAndMergeAnalysis::insertOutOfScopeAccess(
468
493
}
469
494
470
495
// Top-level driver for AccessConflictAndMergeAnalysis
471
- void AccessConflictAndMergeAnalysis::analyze () {
472
- 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
+ }
473
503
LoopRegionToAccessedStorage accessSetsOfRegions;
474
504
// Populate a worklist of regions such that the top of the worklist is the
475
505
// innermost loop and the bottom of the worklist is the entry block.
@@ -499,6 +529,7 @@ void AccessConflictAndMergeAnalysis::analyze() {
499
529
}
500
530
}
501
531
}
532
+ return true ;
502
533
}
503
534
504
535
// Find all begin access operations in this function. Map each access to
@@ -507,29 +538,52 @@ void AccessConflictAndMergeAnalysis::analyze() {
507
538
//
508
539
// Also, add the storage location to the function's RegionStorage
509
540
//
541
+ // Returns true if it is worthwhile to continue the analysis.
542
+ //
510
543
// TODO: begin_unpaired_access is not tracked. Even though begin_unpaired_access
511
544
// isn't explicitly paired, it may be possible after devirtualization and
512
545
// inlining to find all uses of the scratch buffer. However, this doesn't
513
546
// currently happen in practice (rdar://40033735).
514
- void AccessConflictAndMergeAnalysis::identifyBeginAccesses () {
515
- for (auto &BB : *LRFI->getFunction ()) {
516
- 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)) {
517
555
auto *beginAccess = dyn_cast<BeginAccessInst>(&I);
518
556
if (!beginAccess)
519
557
continue ;
520
558
521
559
if (beginAccess->getEnforcement () != SILAccessEnforcement::Dynamic)
522
560
continue ;
523
561
562
+ if (!beginAccess->hasNoNestedConflict ())
563
+ seenPossibleNestedConflict = true ;
564
+
524
565
// The accessed base is expected to be valid for begin_access, but for
525
566
// now, since this optimization runs at the end of the pipeline, we
526
567
// gracefully ignore unrecognized source address patterns, which show up
527
568
// here as an invalid `storage` value.
528
- const AccessedStorage & storage =
569
+ AccessedStorage storage =
529
570
findAccessedStorageNonNested (beginAccess->getSource ());
530
571
531
- auto iterAndSuccess = result.accessMap .try_emplace (
532
- 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);
533
587
(void )iterAndSuccess;
534
588
assert (iterAndSuccess.second );
535
589
@@ -539,6 +593,7 @@ void AccessConflictAndMergeAnalysis::identifyBeginAccesses() {
539
593
assert (!info.seenNestedConflict ());
540
594
}
541
595
}
596
+ return seenPossibleNestedConflict || seenIdenticalStorage;
542
597
}
543
598
544
599
// Returns a mapping from each loop sub-region to all its access storage
@@ -617,11 +672,14 @@ void AccessConflictAndMergeAnalysis::visitBeginAccess(
617
672
recordInScopeConflicts (state, beginAccessInfo, beginAccess->getAccessKind ());
618
673
// Remove in-scope conflicts to avoid checking them again.
619
674
removeConflicts (state.inScopeConflictFreeAccesses , beginAccessInfo);
620
- // Always record the current access as in-scope. It can potentially be folded
621
- // to [no_nested_conflict] independent of any enclosing access conflicts.
622
- bool inserted = state.inScopeConflictFreeAccesses .insert (beginAccess);
623
- (void )inserted;
624
- 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
+ }
625
683
626
684
// Find an out-of-scope access that is mergeable with this access. This is
627
685
// done at the BeginAccess because it doesn't matter whether the merged access
@@ -635,7 +693,7 @@ void AccessConflictAndMergeAnalysis::visitBeginAccess(
635
693
if (BeginAccessInst *mergeableAccess =
636
694
findMergeableOutOfScopeAccess (state, beginAccess)) {
637
695
LLVM_DEBUG (llvm::dbgs () << " Found mergable pair: " << *mergeableAccess
638
- << " , " << *beginAccess << " \n " );
696
+ << " with " << *beginAccess << " \n " );
639
697
result.mergePairs .emplace_back (mergeableAccess, beginAccess);
640
698
}
641
699
// For the purpose of data-flow, removing the out-of-scope access does not
@@ -947,6 +1005,12 @@ canMerge(PostDominanceInfo *postDomTree,
947
1005
static bool mergeAccesses (
948
1006
SILFunction *F, PostDominanceInfo *postDomTree,
949
1007
const AccessConflictAndMergeAnalysis::MergeablePairs &mergePairs) {
1008
+
1009
+ if (mergePairs.empty ()) {
1010
+ LLVM_DEBUG (llvm::dbgs () << " Skipping SCC Analysis...\n " );
1011
+ return false ;
1012
+ }
1013
+
950
1014
bool changed = false ;
951
1015
952
1016
// Compute a map from each block to its SCC -
@@ -993,7 +1057,7 @@ static bool mergeAccesses(
993
1057
continue ;
994
1058
995
1059
LLVM_DEBUG (llvm::dbgs ()
996
- << " Merging: " << *childIns << " into " << *parentIns << " \n " );
1060
+ << " Merging " << *childIns << " into " << *parentIns << " \n " );
997
1061
998
1062
// Change the no nested conflict of parent if the child has a nested
999
1063
// conflict.
@@ -1038,9 +1102,12 @@ struct AccessEnforcementOpts : public SILFunctionTransform {
1038
1102
<< F->getName () << " \n " );
1039
1103
1040
1104
LoopRegionFunctionInfo *LRFI = getAnalysis<LoopRegionAnalysis>()->get (F);
1105
+ PostOrderFunctionInfo *PO = getAnalysis<PostOrderAnalysis>()->get (F);
1041
1106
AccessedStorageAnalysis *ASA = getAnalysis<AccessedStorageAnalysis>();
1042
- AccessConflictAndMergeAnalysis a (LRFI, ASA);
1043
- a.analyze ();
1107
+ AccessConflictAndMergeAnalysis a (LRFI, PO, ASA);
1108
+ if (!a.analyze ())
1109
+ return ;
1110
+
1044
1111
auto result = a.getResult ();
1045
1112
1046
1113
// Perform access folding by setting the [no_nested_conflict] flag on
0 commit comments