Skip to content
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
8 changes: 8 additions & 0 deletions include/swift/SIL/OwnershipUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,14 @@ void visitTransitiveEndBorrows(
BorrowedValue beginBorrow,
function_ref<void(EndBorrowInst *)> visitEndBorrow);

/// Whether the specified lexical begin_borrow instruction is nested.
///
/// A begin_borrow [lexical] is nested if the borrowed value's lifetime is
/// guaranteed by another lexical scope. That happens if:
/// - the value is a guaranteed argument to the function
/// - the value is itself a begin_borrow [lexical]
bool isNestedLexicalBeginBorrow(BeginBorrowInst *bbi);

} // namespace swift

#endif
18 changes: 18 additions & 0 deletions lib/SIL/Utils/OwnershipUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1487,3 +1487,21 @@ void swift::visitTransitiveEndBorrows(
}
}
}

/// Whether the specified lexical begin_borrow instruction is nested.
///
/// A begin_borrow [lexical] is nested if the borrowed value's lifetime is
/// guaranteed by another lexical scope. That happens if:
/// - the value is a guaranteed argument to the function
/// - the value is itself a begin_borrow [lexical]
bool swift::isNestedLexicalBeginBorrow(BeginBorrowInst *bbi) {
assert(bbi->isLexical());
auto value = bbi->getOperand();
if (auto *outerBBI = dyn_cast<BeginBorrowInst>(value)) {
return outerBBI->isLexical();
}
if (auto *arg = dyn_cast<SILFunctionArgument>(value)) {
return arg->getOwnershipKind() == OwnershipKind::Guaranteed;
}
return false;
}
27 changes: 4 additions & 23 deletions lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,15 @@
using namespace swift;
using namespace swift::semanticarc;

/// Whether the provided lexical begin_borrow instruction is redundant.
///
/// A begin_borrow [lexical] is redundant if the borrowed value's lifetime is
/// otherwise guaranteed. That happens if:
/// - the value is a guaranteed argument to the function
/// - the value is itself a begin_borrow [lexical]
static bool isRedundantLexicalBeginBorrow(BeginBorrowInst *bbi) {
assert(bbi->isLexical());
auto value = bbi->getOperand();
if (auto *outerBBI = dyn_cast<BeginBorrowInst>(value)) {
return outerBBI->isLexical();
}
if (auto *arg = dyn_cast<SILFunctionArgument>(value)) {
return arg->getOwnershipKind() == OwnershipKind::Guaranteed;
}
return false;
}

bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) {
// Quickly check if we are supposed to perform this transformation.
if (!ctx.shouldPerform(ARCTransformKind::RedundantBorrowScopeElimPeephole))
return false;

// Lexical borrow scopes must remain in order to ensure that value lifetimes
// are not observably shortened.
if (bbi->isLexical()) {
if (!isRedundantLexicalBeginBorrow(bbi))
return false;
// Non-redundant, lexical borrow scopes must remain in order to ensure that
// value lifetimes are not observably shortened.
if (bbi->isLexical() && !isNestedLexicalBeginBorrow(bbi)) {
return false;
}

auto kind = bbi->getOperand().getOwnershipKind();
Expand Down
2 changes: 1 addition & 1 deletion lib/SILOptimizer/Transforms/CopyPropagation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ void CopyPropagation::run() {
// blocks and pushing begin_borrows as we see them and then popping them
// off the end will result in shrinking inner borrow scopes first.
while (auto *bbi = beginBorrowsToShrink.pop()) {
shrinkBorrowScope(bbi, deleter);
changed |= shrinkBorrowScope(bbi, deleter);
}

// canonicalizer performs all modifications through deleter's callbacks, so we
Expand Down
10 changes: 7 additions & 3 deletions lib/SILOptimizer/Utils/CanonicalizeInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,13 @@ static SILBasicBlock::iterator
eliminateSimpleBorrows(BeginBorrowInst *bbi, CanonicalizeInstruction &pass) {
auto next = std::next(bbi->getIterator());

// Never eliminate lexical borrow scopes. They must be kept to ensure that
// value lifetimes aren't observably shortened.
if (bbi->isLexical())
// Lexical borrow scopes can only be eliminated under certain circumstances:
// (1) They can never be eliminated if the module is in the raw stage, because
// they may be needed for diagnostic.
// (2) They can never be eliminated if there is no enclosing lexical scope
// which guarantees the lifetime of the value.
if (bbi->isLexical() && (bbi->getModule().getStage() == SILStage::Raw ||
!isNestedLexicalBeginBorrow(bbi)))
return next;

// We know that our borrow is completely within the lifetime of its base value
Expand Down