Skip to content

Commit 8504265

Browse files
authored
Merge pull request #39761 from atrick/fix-accessopt
Fix AccessEnforcementOpts for OSSA
2 parents ea82df3 + 7d9caf3 commit 8504265

File tree

5 files changed

+389
-5
lines changed

5 files changed

+389
-5
lines changed

include/swift/SILOptimizer/Utils/OwnershipOptUtils.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/Basic/Defer.h"
2323
#include "swift/SIL/BasicBlockUtils.h"
2424
#include "swift/SIL/OwnershipUtils.h"
25+
#include "swift/SIL/PrunedLiveness.h"
2526
#include "swift/SIL/SILModule.h"
2627
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
2728

@@ -34,6 +35,31 @@ inline bool requiresOSSACleanup(SILValue v) {
3435
&& v.getOwnershipKind() != OwnershipKind::Unowned;
3536
}
3637

38+
/// Rewrite the lifetime of \p ownedValue to match \p lifetimeBoundary. This may
39+
/// insert copies at forwarding consumes, including phis.
40+
///
41+
/// Precondition: lifetimeBoundary is dominated by ownedValue.
42+
///
43+
/// Precondition: lifetimeBoundary is a superset of ownedValue's current
44+
/// lifetime (therefore, none of the safety checks done during
45+
/// CanonicalizeOSSALifetime are needed here).
46+
void extendOwnedLifetime(SILValue ownedValue,
47+
PrunedLivenessBoundary &lifetimeBoundary,
48+
InstructionDeleter &deleter);
49+
50+
/// Rewrite the local borrow scope introduced by \p beginBorrow to match \p
51+
/// guaranteedBoundary.
52+
///
53+
/// Precondition: guaranteedBoundary is dominated by beginBorrow which has no
54+
/// reborrows.
55+
///
56+
/// Precondition: guaranteedBoundary is a superset of beginBorrow's current
57+
/// scope (therefore, none of the safety checks done during
58+
/// CanonicalizeBorrowScope are needed here).
59+
void extendLocalBorrow(BeginBorrowInst *beginBorrow,
60+
PrunedLivenessBoundary &guaranteedBoundary,
61+
InstructionDeleter &deleter);
62+
3763
/// Given a new phi that may use a guaranteed value, create nested borrow scopes
3864
/// for its incoming operands and end_borrows that cover the phi's extended
3965
/// borrow scope, which transitively includes any phis that use this phi.
@@ -47,6 +73,73 @@ inline bool requiresOSSACleanup(SILValue v) {
4773
/// newly created phis do not yet have a borrow scope.
4874
bool createBorrowScopeForPhiOperands(SILPhiArgument *newPhi);
4975

76+
//===----------------------------------------------------------------------===//
77+
// GuaranteedOwnershipExtension
78+
//===----------------------------------------------------------------------===//
79+
80+
/// Extend existing guaranteed ownership to cover new guaranteeed uses that are
81+
/// dominated by the borrow introducer.
82+
class GuaranteedOwnershipExtension {
83+
// --- context
84+
InstructionDeleter &deleter;
85+
DeadEndBlocks &deBlocks;
86+
87+
// --- analysis state
88+
PrunedLiveness guaranteedLiveness;
89+
PrunedLiveness ownedLifetime;
90+
SmallVector<SILBasicBlock *, 4> ownedConsumeBlocks;
91+
BeginBorrowInst *beginBorrow = nullptr;
92+
93+
public:
94+
GuaranteedOwnershipExtension(InstructionDeleter &deleter,
95+
DeadEndBlocks &deBlocks)
96+
: deleter(deleter), deBlocks(deBlocks) {}
97+
98+
void clear() {
99+
guaranteedLiveness.clear();
100+
ownedLifetime.clear();
101+
ownedConsumeBlocks.clear();
102+
beginBorrow = nullptr;
103+
}
104+
105+
/// Invalid indicates that the current guaranteed scope is insufficient, and
106+
/// it does not meet the precondition for scope extension.
107+
///
108+
/// Valid indicates that the current guaranteed scope is sufficient with no
109+
/// transformation required.
110+
///
111+
/// ExtendBorrow indicates that the local borrow scope can be extended without
112+
/// affecting the owned lifetime or introducing copies.
113+
///
114+
/// ExtendLifetime indicates that the owned lifetime can be extended possibly
115+
/// requiring additional copies.
116+
enum Status { Invalid, Valid, ExtendBorrow, ExtendLifetime };
117+
118+
/// Can the OSSA ownership of the \p parentAddress cover all uses of the \p
119+
/// childAddress?
120+
///
121+
/// Precondition: \p parentAddress dominates \p childAddress
122+
Status checkAddressOwnership(SILValue parentAddress, SILValue childAddress);
123+
124+
/// Can the OSSA scope of \p borrow cover all \p newUses?
125+
///
126+
/// Precondition: \p borrow dominates \p newUses
127+
Status checkBorrowExtension(BorrowedValue borrow,
128+
ArrayRef<Operand *> newUses);
129+
130+
/// Can the OSSA scope of \p ownedValue cover all the guaranteed \p newUses?
131+
///
132+
/// Precondition: \p ownedValue dominates \p newUses
133+
Status checkLifetimeExtension(SILValue ownedValue,
134+
ArrayRef<Operand *> newUses);
135+
136+
void transform(Status status);
137+
};
138+
139+
//===----------------------------------------------------------------------===//
140+
// RAUW - Replace All Uses With...
141+
//===----------------------------------------------------------------------===//
142+
50143
/// A struct that contains context shared in between different operation +
51144
/// "ownership fixup" utilities. Please do not put actual methods on this, it is
52145
/// meant to be composed with.

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ static void findLastUserInBlock(SILBasicBlock *bb,
209209
continue;
210210

211211
boundary.lastUsers.push_back(inst);
212+
return;
212213
}
213214
llvm_unreachable("No user in LiveWithin block");
214215
}

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
};

0 commit comments

Comments
 (0)