19
19
// /
20
20
// / This pass optimizes access enforcement as follows:
21
21
// /
22
- // / **Access marker folding**: Find begin/end access scopes that are
23
- // / uninterrupted by a potential conflicting access. Flag those as [nontracking]
24
- // / access.
22
+ // / **Access marker folding**
23
+ // /
24
+ // / Find begin/end access scopes that are uninterrupted by a potential
25
+ // / conflicting access. Flag those as [nontracking] access.
25
26
// /
26
27
// / Folding must prove that no dynamic conflicts occur inside of an access
27
28
// / scope. That is, a scope has no "nested inner conflicts". The access itself
50
51
// / **Local access marker removal**
51
52
// /
52
53
// / When none of the local accesses on local storage (box/stack) have nested
53
- // / conflicts, then all the locall accesses may be removed. This is somwhat rare
54
- // / because static diagnostics already promote the obvious cases to static
55
- // / checks. However, there are two reasons that dynamic local markers may be
56
- // / removed: (1) inlining may cause closure access to become local access (2)
57
- // / local storage may truly escape, but none of the the local access scopes
58
- // / cross a call site.
54
+ // / conflicts, then all the local accesses may be disabled by setting their
55
+ // / enforcement to ` static`. This is somwhat rare because static diagnostics
56
+ // / already promote the obvious cases to static checks. However, there are two
57
+ // / reasons that dynamic local markers may be disabled: (1) inlining may cause
58
+ // / closure access to become local access (2) local storage may truly escape,
59
+ // / but none of the the local access scopes cross a call site.
59
60
// /
60
61
// / TODO: Perform another run of AccessEnforcementSelection immediately before
61
62
// / this pass. Currently, that pass only works well when run before
@@ -575,7 +576,7 @@ foldNonNestedAccesses(AccessConflictAnalysis::AccessMap &accessMap) {
575
576
576
577
// / Perform local access marker elimination.
577
578
// /
578
- // / Eliminate accesses to uniquely identified local storage for which no
579
+ // / Disable accesses to uniquely identified local storage for which no
579
580
// / accesses can have nested conflicts. This is only valid if the function's
580
581
// / local storage cannot be potentially modified by unidentified access:
581
582
// /
@@ -590,11 +591,8 @@ foldNonNestedAccesses(AccessConflictAnalysis::AccessMap &accessMap) {
590
591
// / enforcement). These accesses can only be eliminated when there is no
591
592
// / Unidentified access within the function without the [no_nested_conflict]
592
593
// / flag.
593
- // /
594
- // / This simply invalidates the AccessMap result rather than erasing individual
595
- // / entries.
596
594
static bool
597
- removeLocalNonNestedAccess (AccessConflictAnalysis::Result & &result,
595
+ removeLocalNonNestedAccess (const AccessConflictAnalysis::Result &result,
598
596
const FunctionAccessedStorage &functionAccess) {
599
597
if (functionAccess.hasUnidentifiedAccess ())
600
598
return false ;
@@ -603,24 +601,18 @@ removeLocalNonNestedAccess(AccessConflictAnalysis::Result &&result,
603
601
SmallVector<BeginAccessInst *, 8 > deadAccesses;
604
602
for (auto &beginAccessAndInfo : result.accessMap ) {
605
603
BeginAccessInst *beginAccess = beginAccessAndInfo.first ;
606
- AccessInfo &info = beginAccessAndInfo.second ;
604
+ const AccessInfo &info = beginAccessAndInfo.second ;
607
605
if (info.seenNestedConflict () || !info.isLocal ())
608
606
continue ;
609
607
610
608
// This particular access to local storage is marked
611
609
// [no_nested_conflict]. Now check FunctionAccessedStorage to determine if
612
610
// that is true for all access to the same storage.
613
- if (functionAccess.hasNoNestedConflict (info))
614
- deadAccesses.push_back (beginAccess);
615
- }
616
- std::sort (deadAccesses.begin (), deadAccesses.end (),
617
- [&result](BeginAccessInst *a, BeginAccessInst *b) {
618
- return result.getAccessIndex (a) < result.getAccessIndex (b);
619
- });
620
- for (BeginAccessInst *beginAccess : deadAccesses) {
621
- DEBUG (llvm::dbgs () << " Removing dead access " << *beginAccess);
622
- changed = true ;
623
- removeBeginAccess (beginAccess);
611
+ if (functionAccess.hasNoNestedConflict (info)) {
612
+ DEBUG (llvm::dbgs () << " Disabling dead access " << *beginAccess);
613
+ beginAccess->setEnforcement (SILAccessEnforcement::Static);
614
+ changed = true ;
615
+ }
624
616
}
625
617
return changed;
626
618
}
@@ -647,15 +639,14 @@ struct AccessEnforcementOpts : public SILFunctionTransform {
647
639
648
640
// Use the updated AccessedStorageAnalysis to find any uniquely identified
649
641
// local storage that has no nested conflict on any of its accesses within
650
- // this function. These can be removed entirely .
642
+ // this function. All the accesses can be marked as statically enforced .
651
643
//
652
644
// Note that the storage address may be passed as an argument and there may
653
645
// be nested conflicts within that call, but none of the accesses within
654
646
// this function will overlap.
655
647
const FunctionAccessedStorage &functionAccess = ASA->getEffects (F);
656
- if (removeLocalNonNestedAccess (std::move ( result) , functionAccess))
648
+ if (removeLocalNonNestedAccess (result, functionAccess))
657
649
invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
658
- // `result` is now invalid.
659
650
}
660
651
};
661
652
} // namespace
0 commit comments