Skip to content

SILOptimizer: Break circular dependency with SIL library by moving extendStoreBorrow() #61776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions include/swift/SIL/ScopedAddressUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,6 @@ bool hasOtherStoreBorrowsInLifetime(StoreBorrowInst *sbi,
SSAPrunedLiveness *liveness,
DeadEndBlocks *deadEndBlocks);

/// Extend the store_borrow \p sbi's scope such that it encloses \p newUsers.
bool extendStoreBorrow(StoreBorrowInst *sbi,
SmallVectorImpl<Operand *> &newUses,
DeadEndBlocks *deadEndBlocks,
InstModCallbacks callbacks = InstModCallbacks());
} // namespace swift

#endif
6 changes: 6 additions & 0 deletions include/swift/SILOptimizer/Utils/OwnershipOptUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,12 @@ struct LoadOperation {
}
};

/// Extend the store_borrow \p sbi's scope such that it encloses \p newUsers.
bool extendStoreBorrow(StoreBorrowInst *sbi,
SmallVectorImpl<Operand *> &newUses,
DeadEndBlocks *deadEndBlocks,
InstModCallbacks callbacks = InstModCallbacks());

} // namespace swift

#endif
67 changes: 0 additions & 67 deletions lib/SIL/Utils/ScopedAddressUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,73 +182,6 @@ bool swift::hasOtherStoreBorrowsInLifetime(StoreBorrowInst *storeBorrow,
return false;
}

bool swift::extendStoreBorrow(StoreBorrowInst *sbi,
SmallVectorImpl<Operand *> &newUses,
DeadEndBlocks *deadEndBlocks,
InstModCallbacks callbacks) {
ScopedAddressValue scopedAddress(sbi);

SmallVector<SILBasicBlock *, 4> discoveredBlocks;
SSAPrunedLiveness storeBorrowLiveness(&discoveredBlocks);

// FIXME: if OSSA lifetimes are complete, then we don't need transitive
// liveness here.
AddressUseKind useKind =
scopedAddress.computeTransitiveLiveness(storeBorrowLiveness);

// If all new uses are within store_borrow boundary, no need for extension.
if (storeBorrowLiveness.areUsesWithinBoundary(newUses, deadEndBlocks)) {
return true;
}

if (useKind != AddressUseKind::NonEscaping) {
return false;
}

// store_borrow extension is possible only when there are no other
// store_borrows to the same destination within the store_borrow's lifetime
// built from newUsers.
if (hasOtherStoreBorrowsInLifetime(sbi, &storeBorrowLiveness,
deadEndBlocks)) {
return false;
}

InstModCallbacks tempCallbacks = callbacks;
InstructionDeleter deleter(std::move(tempCallbacks));
GuaranteedOwnershipExtension borrowExtension(deleter, *deadEndBlocks,
sbi->getFunction());
auto status = borrowExtension.checkBorrowExtension(
BorrowedValue(sbi->getSrc()), newUses);
if (status == GuaranteedOwnershipExtension::Invalid) {
return false;
}

borrowExtension.transform(status);

SmallVector<Operand *, 4> endBorrowUses;
// Collect old scope-ending instructions.
scopedAddress.visitScopeEndingUses([&](Operand *op) {
endBorrowUses.push_back(op);
return true;
});

for (auto *use : newUses) {
// Update newUsers as non-lifetime ending.
storeBorrowLiveness.updateForUse(use->getUser(),
/* lifetimeEnding */ false);
}

// Add new scope-ending instructions.
scopedAddress.endScopeAtLivenessBoundary(&storeBorrowLiveness);

// Remove old scope-ending instructions.
for (auto *endBorrowUse : endBorrowUses) {
callbacks.deleteInst(endBorrowUse->getUser());
}

return true;
}

void ScopedAddressValue::print(llvm::raw_ostream &os) const {
os << "ScopedAddressIntroducingValue:\n"
"Kind: "
Expand Down
68 changes: 68 additions & 0 deletions lib/SILOptimizer/Utils/OwnershipOptUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "swift/SIL/MemAccessUtils.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/Projection.h"
#include "swift/SIL/ScopedAddressUtils.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILInstruction.h"
Expand Down Expand Up @@ -1848,3 +1849,70 @@ bool swift::createBorrowScopeForPhiOperands(SILPhiArgument *newPhi) {
}
return GuaranteedPhiBorrowFixup().createExtendedNestedBorrowScope(newPhi);
}

bool swift::extendStoreBorrow(StoreBorrowInst *sbi,
SmallVectorImpl<Operand *> &newUses,
DeadEndBlocks *deadEndBlocks,
InstModCallbacks callbacks) {
ScopedAddressValue scopedAddress(sbi);

SmallVector<SILBasicBlock *, 4> discoveredBlocks;
SSAPrunedLiveness storeBorrowLiveness(&discoveredBlocks);

// FIXME: if OSSA lifetimes are complete, then we don't need transitive
// liveness here.
AddressUseKind useKind =
scopedAddress.computeTransitiveLiveness(storeBorrowLiveness);

// If all new uses are within store_borrow boundary, no need for extension.
if (storeBorrowLiveness.areUsesWithinBoundary(newUses, deadEndBlocks)) {
return true;
}

if (useKind != AddressUseKind::NonEscaping) {
return false;
}

// store_borrow extension is possible only when there are no other
// store_borrows to the same destination within the store_borrow's lifetime
// built from newUsers.
if (hasOtherStoreBorrowsInLifetime(sbi, &storeBorrowLiveness,
deadEndBlocks)) {
return false;
}

InstModCallbacks tempCallbacks = callbacks;
InstructionDeleter deleter(std::move(tempCallbacks));
GuaranteedOwnershipExtension borrowExtension(deleter, *deadEndBlocks,
sbi->getFunction());
auto status = borrowExtension.checkBorrowExtension(
BorrowedValue(sbi->getSrc()), newUses);
if (status == GuaranteedOwnershipExtension::Invalid) {
return false;
}

borrowExtension.transform(status);

SmallVector<Operand *, 4> endBorrowUses;
// Collect old scope-ending instructions.
scopedAddress.visitScopeEndingUses([&](Operand *op) {
endBorrowUses.push_back(op);
return true;
});

for (auto *use : newUses) {
// Update newUsers as non-lifetime ending.
storeBorrowLiveness.updateForUse(use->getUser(),
/* lifetimeEnding */ false);
}

// Add new scope-ending instructions.
scopedAddress.endScopeAtLivenessBoundary(&storeBorrowLiveness);

// Remove old scope-ending instructions.
for (auto *endBorrowUse : endBorrowUses) {
callbacks.deleteInst(endBorrowUse->getUser());
}

return true;
}
1 change: 1 addition & 0 deletions lib/SILOptimizer/Utils/PartialApplyCombiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "swift/SIL/SILValue.h"
#include "swift/SIL/ScopedAddressUtils.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/OwnershipOptUtils.h"
#include "swift/SILOptimizer/Utils/ValueLifetime.h"

using namespace swift;
Expand Down