Skip to content

Commit dca28f0

Browse files
authored
Merge pull request #16835 from atrick/accessfold
Simplify AccessEnforcementOpts by leaving access markers in place.
2 parents 6e58abf + 6280528 commit dca28f0

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,19 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
///
13+
/// Pass order dependencies:
14+
///
15+
/// - Will benefit from running after AccessEnforcementSelection.
16+
///
17+
/// - Should run immediately before the AccessEnforcementWMO to share
18+
/// AccessedStorageAnalysis results.
19+
///
1320
/// This pass optimizes access enforcement as follows:
1421
///
15-
/// Access marker folding: Find begin/end access scopes that are uninterrupted
16-
/// by a potential conflicting access. Flag those as [nontracking] 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.
1726
///
1827
/// Folding must prove that no dynamic conflicts occur inside of an access
1928
/// scope. That is, a scope has no "nested inner conflicts". The access itself
@@ -39,8 +48,15 @@
3948
/// any path to an access' end of scope has a potentially conflicting access,
4049
/// then that access is marked as a nested conflict.
4150
///
42-
/// Pass order dependencies:
43-
/// - Will benefit from running after AccessEnforcementSelection.
51+
/// **Local access marker removal**
52+
///
53+
/// When none of the local accesses on local storage (box/stack) have nested
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.
4460
///
4561
/// TODO: Perform another run of AccessEnforcementSelection immediately before
4662
/// this pass. Currently, that pass only works well when run before
@@ -558,14 +574,25 @@ foldNonNestedAccesses(AccessConflictAnalysis::AccessMap &accessMap) {
558574
return changed;
559575
}
560576

561-
/// Eliminate accesses to uniquely identified local storage for which no
577+
/// Perform local access marker elimination.
578+
///
579+
/// Disable accesses to uniquely identified local storage for which no
562580
/// accesses can have nested conflicts. This is only valid if the function's
563-
/// local storage cannot be potentially modified by unidentified access.
581+
/// local storage cannot be potentially modified by unidentified access:
564582
///
565-
/// This simply invalidates the AccessMap result rather than erasing individual
566-
/// entries.
583+
/// - Arguments cannot alias with local storage, so accessing an argument has no
584+
/// effect on analysis of the current function. When a callee accesses an
585+
/// argument, AccessedStorageAnalysis will either map the accessed storage to
586+
/// a value in the caller's function, or mark it as unidentified.
587+
///
588+
/// - Stack or Box local storage could potentially be accessed via Unidentified
589+
/// access. (Some Unidentified accesses are for initialization or for
590+
/// temporary storage instead, but those should never have Dynamic
591+
/// enforcement). These accesses can only be eliminated when there is no
592+
/// Unidentified access within the function without the [no_nested_conflict]
593+
/// flag.
567594
static bool
568-
removeLocalNonNestedAccess(AccessConflictAnalysis::Result &&result,
595+
removeLocalNonNestedAccess(const AccessConflictAnalysis::Result &result,
569596
const FunctionAccessedStorage &functionAccess) {
570597
if (functionAccess.hasUnidentifiedAccess())
571598
return false;
@@ -574,24 +601,18 @@ removeLocalNonNestedAccess(AccessConflictAnalysis::Result &&result,
574601
SmallVector<BeginAccessInst *, 8> deadAccesses;
575602
for (auto &beginAccessAndInfo : result.accessMap) {
576603
BeginAccessInst *beginAccess = beginAccessAndInfo.first;
577-
AccessInfo &info = beginAccessAndInfo.second;
604+
const AccessInfo &info = beginAccessAndInfo.second;
578605
if (info.seenNestedConflict() || !info.isLocal())
579606
continue;
580607

581608
// This particular access to local storage is marked
582609
// [no_nested_conflict]. Now check FunctionAccessedStorage to determine if
583610
// that is true for all access to the same storage.
584-
if (functionAccess.hasNoNestedConflict(info))
585-
deadAccesses.push_back(beginAccess);
586-
}
587-
std::sort(deadAccesses.begin(), deadAccesses.end(),
588-
[&result](BeginAccessInst *a, BeginAccessInst *b) {
589-
return result.getAccessIndex(a) < result.getAccessIndex(b);
590-
});
591-
for (BeginAccessInst *beginAccess : deadAccesses) {
592-
DEBUG(llvm::dbgs() << "Removing dead access " << *beginAccess);
593-
changed = true;
594-
removeBeginAccess(beginAccess);
611+
if (functionAccess.hasNoNestedConflict(info)) {
612+
DEBUG(llvm::dbgs() << "Disabling dead access " << *beginAccess);
613+
beginAccess->setEnforcement(SILAccessEnforcement::Static);
614+
changed = true;
615+
}
595616
}
596617
return changed;
597618
}
@@ -618,15 +639,14 @@ struct AccessEnforcementOpts : public SILFunctionTransform {
618639

619640
// Use the updated AccessedStorageAnalysis to find any uniquely identified
620641
// local storage that has no nested conflict on any of its accesses within
621-
// this function. These can be removed entirely.
642+
// this function. All the accesses can be marked as statically enforced.
622643
//
623644
// Note that the storage address may be passed as an argument and there may
624645
// be nested conflicts within that call, but none of the accesses within
625646
// this function will overlap.
626647
const FunctionAccessedStorage &functionAccess = ASA->getEffects(F);
627-
if (removeLocalNonNestedAccess(std::move(result), functionAccess))
648+
if (removeLocalNonNestedAccess(result, functionAccess))
628649
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
629-
// `result` is now invalid.
630650
}
631651
};
632652
} // namespace

test/SILOptimizer/access_enforcement_opts.sil

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ bb0:
197197
// Demote both read accesses to non_nested, then remove the local outer access.
198198
//
199199
// CHECK-LABEL: sil @testCaptureReadRead : $@convention(thin) () -> () {
200-
// CHECK-NOT: begin_access
200+
// CHECK: begin_access [read] [static] [no_nested_conflict] %0 : $*X
201201
// CHECK-LABEL: } // end sil function 'testCaptureReadRead'
202202
sil @testCaptureReadRead : $@convention(thin) () -> () {
203203
bb0:
@@ -246,7 +246,9 @@ bb0(%0 : $*X):
246246
// Demote both read accesses to non_nested, and remove the local outer access.
247247
//
248248
// CHECK-LABEL: sil @testCaptureBoxReadRead : $@convention(thin) () -> () {
249-
// CHECK-NOT: begin_access
249+
// CHECK: [[BOX:%.*]] = alloc_box ${ var X }, var, name "x"
250+
// CHECK: [[BOXADR:%.*]] = project_box [[BOX]] : ${ var X }, 0
251+
// CHECK: begin_access [read] [static] [no_nested_conflict] [[BOXADR]] : $*X
250252
// CHECK-LABEL: } // end sil function 'testCaptureBoxReadRead'
251253
sil @testCaptureBoxReadRead : $@convention(thin) () -> () {
252254
bb0:
@@ -361,7 +363,10 @@ bb0(%0 : $*Int64):
361363
// Demote read/read access to [no_nested_conflict].
362364
//
363365
// CHECK-LABEL: sil @testInoutReadEscapeRead : $@convention(thin) () -> () {
364-
// CHECK-NOT: begin_access
366+
// CHECK: [[BOX:%.*]] = alloc_box ${ var Int64 }, var, name "x"
367+
// CHECK: [[BOXADR:%.*]] = project_box [[BOX]] : ${ var Int64 }, 0
368+
// CHECK: begin_access [read] [static] [no_nested_conflict] [[BOXADR]] : $*Int64
369+
// CHECK: begin_access [read] [static] [no_nested_conflict] [[BOXADR]] : $*Int64
365370
// CHECK-LABEL: } // end sil function 'testInoutReadEscapeRead'
366371
sil @testInoutReadEscapeRead : $@convention(thin) () -> () {
367372
bb0:

0 commit comments

Comments
 (0)