Skip to content

Commit 6280528

Browse files
committed
Simplify AccessEnforcementOpts by leaving access markers in place.
The extra cost of deterministically deleting instructions is unnecessary. In the long term, we'll want to verify that access markers exist after all SIL passes. So just change their enforcement level rather than removing them.
1 parent 0aa2eae commit 6280528

File tree

2 files changed

+28
-32
lines changed

2 files changed

+28
-32
lines changed

lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
///
2020
/// This pass optimizes access enforcement as follows:
2121
///
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.
2526
///
2627
/// Folding must prove that no dynamic conflicts occur inside of an access
2728
/// scope. That is, a scope has no "nested inner conflicts". The access itself
@@ -50,12 +51,12 @@
5051
/// **Local access marker removal**
5152
///
5253
/// 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.
5960
///
6061
/// TODO: Perform another run of AccessEnforcementSelection immediately before
6162
/// this pass. Currently, that pass only works well when run before
@@ -575,7 +576,7 @@ foldNonNestedAccesses(AccessConflictAnalysis::AccessMap &accessMap) {
575576

576577
/// Perform local access marker elimination.
577578
///
578-
/// Eliminate accesses to uniquely identified local storage for which no
579+
/// Disable accesses to uniquely identified local storage for which no
579580
/// accesses can have nested conflicts. This is only valid if the function's
580581
/// local storage cannot be potentially modified by unidentified access:
581582
///
@@ -590,11 +591,8 @@ foldNonNestedAccesses(AccessConflictAnalysis::AccessMap &accessMap) {
590591
/// enforcement). These accesses can only be eliminated when there is no
591592
/// Unidentified access within the function without the [no_nested_conflict]
592593
/// flag.
593-
///
594-
/// This simply invalidates the AccessMap result rather than erasing individual
595-
/// entries.
596594
static bool
597-
removeLocalNonNestedAccess(AccessConflictAnalysis::Result &&result,
595+
removeLocalNonNestedAccess(const AccessConflictAnalysis::Result &result,
598596
const FunctionAccessedStorage &functionAccess) {
599597
if (functionAccess.hasUnidentifiedAccess())
600598
return false;
@@ -603,24 +601,18 @@ removeLocalNonNestedAccess(AccessConflictAnalysis::Result &&result,
603601
SmallVector<BeginAccessInst *, 8> deadAccesses;
604602
for (auto &beginAccessAndInfo : result.accessMap) {
605603
BeginAccessInst *beginAccess = beginAccessAndInfo.first;
606-
AccessInfo &info = beginAccessAndInfo.second;
604+
const AccessInfo &info = beginAccessAndInfo.second;
607605
if (info.seenNestedConflict() || !info.isLocal())
608606
continue;
609607

610608
// This particular access to local storage is marked
611609
// [no_nested_conflict]. Now check FunctionAccessedStorage to determine if
612610
// 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+
}
624616
}
625617
return changed;
626618
}
@@ -647,15 +639,14 @@ struct AccessEnforcementOpts : public SILFunctionTransform {
647639

648640
// Use the updated AccessedStorageAnalysis to find any uniquely identified
649641
// 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.
651643
//
652644
// Note that the storage address may be passed as an argument and there may
653645
// be nested conflicts within that call, but none of the accesses within
654646
// this function will overlap.
655647
const FunctionAccessedStorage &functionAccess = ASA->getEffects(F);
656-
if (removeLocalNonNestedAccess(std::move(result), functionAccess))
648+
if (removeLocalNonNestedAccess(result, functionAccess))
657649
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
658-
// `result` is now invalid.
659650
}
660651
};
661652
} // 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)