Skip to content

Commit 7d9caf3

Browse files
committed
Fix AccessEnforcementOpts for OSSA.
Add extendOwnership to fixup OSSA before merging access scopes. Uses the new GuaranteedOwnershipExtension utility.
1 parent 4183abc commit 7d9caf3

File tree

2 files changed

+78
-5
lines changed

2 files changed

+78
-5
lines changed

lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,12 @@
8383
#include "swift/SIL/MemAccessUtils.h"
8484
#include "swift/SIL/SILFunction.h"
8585
#include "swift/SILOptimizer/Analysis/AccessStorageAnalysis.h"
86+
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
8687
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
8788
#include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h"
8889
#include "swift/SILOptimizer/PassManager/Transforms.h"
8990
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
91+
#include "swift/SILOptimizer/Utils/OwnershipOptUtils.h"
9092
#include "llvm/ADT/MapVector.h"
9193
#include "llvm/ADT/SCCIterator.h"
9294

@@ -1003,10 +1005,30 @@ canMerge(PostDominanceInfo *postDomTree,
10031005
return canMergeEnd(parentIns, childIns);
10041006
}
10051007

1008+
static bool extendOwnership(BeginAccessInst *parentInst,
1009+
BeginAccessInst *childInst,
1010+
InstructionDeleter &deleter,
1011+
DeadEndBlocks &deBlocks) {
1012+
GuaranteedOwnershipExtension extension(deleter, deBlocks);
1013+
auto status = extension.checkAddressOwnership(parentInst, childInst);
1014+
switch (status) {
1015+
case GuaranteedOwnershipExtension::Invalid:
1016+
return false;
1017+
case GuaranteedOwnershipExtension::Valid:
1018+
return true;
1019+
case GuaranteedOwnershipExtension::ExtendLifetime:
1020+
case GuaranteedOwnershipExtension::ExtendBorrow:
1021+
break;
1022+
}
1023+
extension.transform(status);
1024+
return true;
1025+
}
1026+
10061027
/// Perform access merging.
1007-
static bool mergeAccesses(
1008-
SILFunction *F, PostDominanceInfo *postDomTree,
1009-
const AccessConflictAndMergeAnalysis::MergeablePairs &mergePairs) {
1028+
static bool
1029+
mergeAccesses(SILFunction *F, PostDominanceInfo *postDomTree,
1030+
const AccessConflictAndMergeAnalysis::MergeablePairs &mergePairs,
1031+
InstModCallbacks &callbacks, DeadEndBlocks &deBlocks) {
10101032

10111033
if (mergePairs.empty()) {
10121034
LLVM_DEBUG(llvm::dbgs() << "Skipping SCC Analysis...\n");
@@ -1042,6 +1064,7 @@ static bool mergeAccesses(
10421064
// begin_access instruction. We store (begin_access %2 -> begin_access %1)
10431065
// to re-map a merged begin_access to it's replaced instruction.
10441066
llvm::DenseMap<BeginAccessInst *, BeginAccessInst *> oldToNewMap;
1067+
InstructionDeleter deleter(callbacks);
10451068

10461069
while (!workPairs.empty()) {
10471070
auto curr = workPairs.pop_back_val();
@@ -1058,6 +1081,9 @@ static bool mergeAccesses(
10581081
if (!canMerge(postDomTree, blockToSCCMap, parentIns, childIns))
10591082
continue;
10601083

1084+
if (!extendOwnership(parentIns, childIns, deleter, deBlocks))
1085+
return false;
1086+
10611087
LLVM_DEBUG(llvm::dbgs()
10621088
<< "Merging " << *childIns << " into " << *parentIns << "\n");
10631089

@@ -1084,8 +1110,9 @@ static bool mergeAccesses(
10841110
auto curr = oldToNewMap.begin();
10851111
auto *oldIns = curr->getFirst();
10861112
oldToNewMap.erase(oldIns);
1087-
oldIns->eraseFromParent();
1113+
deleter.forceDelete(oldIns);
10881114
}
1115+
deleter.cleanupDeadInstructions();
10891116
return changed;
10901117
}
10911118

@@ -1101,6 +1128,8 @@ struct AccessEnforcementOpts : public SILFunctionTransform {
11011128

11021129
LoopRegionFunctionInfo *LRFI = getAnalysis<LoopRegionAnalysis>()->get(F);
11031130
PostOrderFunctionInfo *PO = getAnalysis<PostOrderAnalysis>()->get(F);
1131+
DeadEndBlocksAnalysis *deBlocksAnalysis =
1132+
PM->getAnalysis<DeadEndBlocksAnalysis>();
11041133
AccessStorageAnalysis *ASA = getAnalysis<AccessStorageAnalysis>();
11051134
AccessConflictAndMergeAnalysis a(LRFI, PO, ASA);
11061135
if (!a.analyze())
@@ -1132,7 +1161,9 @@ struct AccessEnforcementOpts : public SILFunctionTransform {
11321161
PostDominanceAnalysis *postDomAnalysis =
11331162
getAnalysis<PostDominanceAnalysis>();
11341163
PostDominanceInfo *postDomTree = postDomAnalysis->get(F);
1135-
if (mergeAccesses(F, postDomTree, result.mergePairs))
1164+
DeadEndBlocks *deBlocks = deBlocksAnalysis->get(F);
1165+
InstModCallbacks callbacks;
1166+
if (mergeAccesses(F, postDomTree, result.mergePairs, callbacks, *deBlocks))
11361167
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
11371168
}
11381169
};

test/SILOptimizer/access_enforcement_opts_ossa.sil

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ class Klass {
1818

1919
}
2020

21+
class NonTrivial {
22+
@_hasStorage var object: Klass { get set }
23+
}
24+
2125
var globalX: X
2226

2327
var globalOtherX: X
@@ -26,6 +30,8 @@ sil_global hidden @globalX : $X
2630

2731
sil_global hidden @globalOtherX : $X
2832

33+
sil [ossa] @hasIndirectArg : $@convention(thin) (@inout Klass) -> ()
34+
2935
sil hidden [ossa] @Xinit : $@convention(method) (@thin X.Type) -> X {
3036
bb0(%0 : $@thin X.Type):
3137
%1 = alloc_stack $X, var, name "self"
@@ -1821,6 +1827,10 @@ class Bar {
18211827
func foo()
18221828
}
18231829

1830+
// Nothing happens here. I guess we check that the analysis does not crash.
1831+
//
1832+
// CHECK-LABEL: sil [ossa] @$testEndLifetime : $@convention(method) (@owned Bar, @in Bar) -> () {
1833+
// CHECK-LABEL: } // end sil function '$testEndLifetime'
18241834
sil [ossa] @$testEndLifetime : $@convention(method) (@owned Bar, @in Bar) -> () {
18251835
bb0(%0 : @owned $Bar, %1 : $*Bar):
18261836
%b = begin_access [modify] [dynamic] %1 : $*Bar
@@ -1832,3 +1842,35 @@ bb0(%0 : @owned $Bar, %1 : $*Bar):
18321842
%r = tuple ()
18331843
return %r : $()
18341844
}
1845+
1846+
// CHECK-LABEL: sil [ossa] @testBorrowedAccess : $@convention(thin) (@owned NonTrivial) -> () {
1847+
// CHECK: bb0(%0 : @owned $NonTrivial):
1848+
// CHECK: [[BORROW:%.*]] = begin_borrow %0 : $NonTrivial
1849+
// CHECK: [[ADR:%.*]] = ref_element_addr [[BORROW]] : $NonTrivial, #NonTrivial.object
1850+
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADR]] : $*Klass
1851+
// CHECK-NOT: access
1852+
// CHECK-NOT: borrow
1853+
// CHECK: apply %{{.*}}([[ACCESS]]) : $@convention(thin) (@inout Klass) -> ()
1854+
// CHECK: apply %{{.*}}([[ACCESS]]) : $@convention(thin) (@inout Klass) -> ()
1855+
// CHECK: end_access [[ACCESS]] : $*Klass
1856+
// CHECK: end_borrow [[BORROW]] : $NonTrivial
1857+
// CHECK: destroy_value %0 : $NonTrivial
1858+
// CHECK-LABEL: } // end sil function 'testBorrowedAccess'
1859+
sil [ossa] @testBorrowedAccess : $@convention(thin) (@owned NonTrivial) -> () {
1860+
bb0(%0 : @owned $NonTrivial):
1861+
%f = function_ref @hasIndirectArg : $@convention(thin) (@inout Klass) -> ()
1862+
%b1 = begin_borrow %0 : $NonTrivial
1863+
%e1 = ref_element_addr %b1 : $NonTrivial, #NonTrivial.object
1864+
%a1 = begin_access [modify] [dynamic] %e1 : $*Klass
1865+
%c1 = apply %f(%a1) : $@convention(thin) (@inout Klass) -> ()
1866+
end_access %a1 : $*Klass
1867+
end_borrow %b1 : $NonTrivial
1868+
%b2 = begin_borrow %0 : $NonTrivial
1869+
%e2 = ref_element_addr %b2 : $NonTrivial, #NonTrivial.object
1870+
%a2 = begin_access [modify] [dynamic] %e2 : $*Klass
1871+
%c2 = apply %f(%a2) : $@convention(thin) (@inout Klass) -> ()
1872+
end_access %a2 : $*Klass
1873+
end_borrow %b2 : $NonTrivial
1874+
destroy_value %0 : $NonTrivial
1875+
return undef : $()
1876+
}

0 commit comments

Comments
 (0)