Skip to content

Commit bf7cbb5

Browse files
committed
Add new utilities for store borrow extension and ending store borrow scope
1 parent 34cc511 commit bf7cbb5

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

include/swift/SIL/ScopedAddressUtils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/SIL/SILBasicBlock.h"
2020
#include "swift/SIL/SILInstruction.h"
2121
#include "swift/SIL/SILValue.h"
22+
#include "swift/SILOptimizer/Utils/InstModCallbacks.h"
2223

2324
namespace swift {
2425

@@ -90,6 +91,12 @@ struct ScopedAddressValue {
9091
/// unkown address use. Add this scope's live blocks into the PrunedLiveness
9192
/// result.
9293
bool computeLiveness(PrunedLiveness &liveness) const;
94+
95+
/// Create appropriate scope ending instruction at \p insertPt.
96+
void createScopeEnd(SILBasicBlock::iterator insertPt, SILLocation loc) const;
97+
98+
/// Create scope ending instructions at \p liveness boundary.
99+
void endScopeAtLivenessBoundary(PrunedLiveness *liveness) const;
93100
};
94101

95102
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
@@ -100,6 +107,12 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
100107
bool hasOtherStoreBorrowsInLifetime(StoreBorrowInst *sbi,
101108
PrunedLiveness *liveness,
102109
DeadEndBlocks *deadEndBlocks);
110+
111+
/// Extend the store_borrow \p sbi's scope such that it encloses \p newUsers.
112+
bool extendStoreBorrow(StoreBorrowInst *sbi,
113+
SmallVectorImpl<Operand *> &newUses,
114+
DeadEndBlocks *deadEndBlocks,
115+
InstModCallbacks callbacks = InstModCallbacks());
103116
} // namespace swift
104117

105118
#endif

lib/SIL/Utils/ScopedAddressUtils.cpp

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "swift/SIL/SILArgument.h"
1717
#include "swift/SIL/SILBuilder.h"
1818
#include "swift/SIL/SILInstruction.h"
19+
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
20+
#include "swift/SILOptimizer/Utils/OwnershipOptUtils.h"
1921

2022
using namespace swift;
2123

@@ -85,12 +87,18 @@ bool ScopedAddressValue::visitScopeEndingUses(
8587
}
8688

8789
bool ScopedAddressValue::computeLiveness(PrunedLiveness &liveness) const {
88-
auto addressKind = findTransitiveUsesForAddress(value);
90+
SmallVector<Operand *, 4> uses;
91+
// Collect all uses that need to be enclosed by the scope.
92+
auto addressKind = findTransitiveUsesForAddress(value, &uses);
8993
if (addressKind != AddressUseKind::NonEscaping) {
9094
return false;
9195
}
9296

9397
liveness.initializeDefBlock(value->getParentBlock());
98+
for (auto *use : uses) {
99+
// Update all collected uses as non-lifetime ending.
100+
liveness.updateForUse(use->getUser(), /* lifetimeEnding */ false);
101+
}
94102
visitScopeEndingUses([&](Operand *endOp) {
95103
liveness.updateForUse(endOp->getUser(), /* isLifetimeEnding */ true);
96104
return true;
@@ -156,6 +164,68 @@ bool swift::hasOtherStoreBorrowsInLifetime(StoreBorrowInst *storeBorrow,
156164
return false;
157165
}
158166

167+
bool swift::extendStoreBorrow(StoreBorrowInst *sbi,
168+
SmallVectorImpl<Operand *> &newUses,
169+
DeadEndBlocks *deadEndBlocks,
170+
InstModCallbacks callbacks) {
171+
ScopedAddressValue scopedAddress(sbi);
172+
173+
SmallVector<SILBasicBlock *, 4> discoveredBlocks;
174+
PrunedLiveness storeBorrowLiveness(&discoveredBlocks);
175+
bool success = scopedAddress.computeLiveness(storeBorrowLiveness);
176+
177+
// If all new uses are within store_borrow boundary, no need for extension.
178+
if (storeBorrowLiveness.areUsesWithinBoundary(newUses, deadEndBlocks)) {
179+
return true;
180+
}
181+
182+
if (!success) {
183+
return false;
184+
}
185+
186+
// store_borrow extension is possible only when there are no other
187+
// store_borrows to the same destination within the store_borrow's lifetime
188+
// built from newUsers.
189+
if (hasOtherStoreBorrowsInLifetime(sbi, &storeBorrowLiveness,
190+
deadEndBlocks)) {
191+
return false;
192+
}
193+
194+
InstModCallbacks tempCallbacks = callbacks;
195+
InstructionDeleter deleter(std::move(tempCallbacks));
196+
GuaranteedOwnershipExtension borrowExtension(deleter, *deadEndBlocks);
197+
auto status = borrowExtension.checkBorrowExtension(
198+
BorrowedValue(sbi->getSrc()), newUses);
199+
if (status == GuaranteedOwnershipExtension::Invalid) {
200+
return false;
201+
}
202+
203+
borrowExtension.transform(status);
204+
205+
SmallVector<Operand *, 4> endBorrowUses;
206+
// Collect old scope-ending instructions.
207+
scopedAddress.visitScopeEndingUses([&](Operand *op) {
208+
endBorrowUses.push_back(op);
209+
return true;
210+
});
211+
212+
for (auto *use : newUses) {
213+
// Update newUsers as non-lifetime ending.
214+
storeBorrowLiveness.updateForUse(use->getUser(),
215+
/* lifetimeEnding */ false);
216+
}
217+
218+
// Add new scope-ending instructions.
219+
scopedAddress.endScopeAtLivenessBoundary(&storeBorrowLiveness);
220+
221+
// Remove old scope-ending instructions.
222+
for (auto *endBorrowUse : endBorrowUses) {
223+
callbacks.deleteInst(endBorrowUse->getUser());
224+
}
225+
226+
return true;
227+
}
228+
159229
void ScopedAddressValue::print(llvm::raw_ostream &os) const {
160230
os << "ScopedAddressIntroducingValue:\n"
161231
"Kind: "

0 commit comments

Comments
 (0)