Skip to content

Commit f95748c

Browse files
Merge pull request #40461 from nate-chandler/lexical_lifetimes/remove-simple-lexical-borrow-if-redundant
[CanonicalizeInst] Remove redundant lexical bbis.
2 parents 403ccd4 + ac50bb7 commit f95748c

File tree

5 files changed

+38
-27
lines changed

5 files changed

+38
-27
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,14 @@ void visitTransitiveEndBorrows(
12061206
BorrowedValue beginBorrow,
12071207
function_ref<void(EndBorrowInst *)> visitEndBorrow);
12081208

1209+
/// Whether the specified lexical begin_borrow instruction is nested.
1210+
///
1211+
/// A begin_borrow [lexical] is nested if the borrowed value's lifetime is
1212+
/// guaranteed by another lexical scope. That happens if:
1213+
/// - the value is a guaranteed argument to the function
1214+
/// - the value is itself a begin_borrow [lexical]
1215+
bool isNestedLexicalBeginBorrow(BeginBorrowInst *bbi);
1216+
12091217
} // namespace swift
12101218

12111219
#endif

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,3 +1487,21 @@ void swift::visitTransitiveEndBorrows(
14871487
}
14881488
}
14891489
}
1490+
1491+
/// Whether the specified lexical begin_borrow instruction is nested.
1492+
///
1493+
/// A begin_borrow [lexical] is nested if the borrowed value's lifetime is
1494+
/// guaranteed by another lexical scope. That happens if:
1495+
/// - the value is a guaranteed argument to the function
1496+
/// - the value is itself a begin_borrow [lexical]
1497+
bool swift::isNestedLexicalBeginBorrow(BeginBorrowInst *bbi) {
1498+
assert(bbi->isLexical());
1499+
auto value = bbi->getOperand();
1500+
if (auto *outerBBI = dyn_cast<BeginBorrowInst>(value)) {
1501+
return outerBBI->isLexical();
1502+
}
1503+
if (auto *arg = dyn_cast<SILFunctionArgument>(value)) {
1504+
return arg->getOwnershipKind() == OwnershipKind::Guaranteed;
1505+
}
1506+
return false;
1507+
}

lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,15 @@
2424
using namespace swift;
2525
using namespace swift::semanticarc;
2626

27-
/// Whether the provided lexical begin_borrow instruction is redundant.
28-
///
29-
/// A begin_borrow [lexical] is redundant if the borrowed value's lifetime is
30-
/// otherwise guaranteed. That happens if:
31-
/// - the value is a guaranteed argument to the function
32-
/// - the value is itself a begin_borrow [lexical]
33-
static bool isRedundantLexicalBeginBorrow(BeginBorrowInst *bbi) {
34-
assert(bbi->isLexical());
35-
auto value = bbi->getOperand();
36-
if (auto *outerBBI = dyn_cast<BeginBorrowInst>(value)) {
37-
return outerBBI->isLexical();
38-
}
39-
if (auto *arg = dyn_cast<SILFunctionArgument>(value)) {
40-
return arg->getOwnershipKind() == OwnershipKind::Guaranteed;
41-
}
42-
return false;
43-
}
44-
4527
bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) {
4628
// Quickly check if we are supposed to perform this transformation.
4729
if (!ctx.shouldPerform(ARCTransformKind::RedundantBorrowScopeElimPeephole))
4830
return false;
4931

50-
// Lexical borrow scopes must remain in order to ensure that value lifetimes
51-
// are not observably shortened.
52-
if (bbi->isLexical()) {
53-
if (!isRedundantLexicalBeginBorrow(bbi))
54-
return false;
32+
// Non-redundant, lexical borrow scopes must remain in order to ensure that
33+
// value lifetimes are not observably shortened.
34+
if (bbi->isLexical() && !isNestedLexicalBeginBorrow(bbi)) {
35+
return false;
5536
}
5637

5738
auto kind = bbi->getOperand().getOwnershipKind();

lib/SILOptimizer/Transforms/CopyPropagation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ void CopyPropagation::run() {
438438
// blocks and pushing begin_borrows as we see them and then popping them
439439
// off the end will result in shrinking inner borrow scopes first.
440440
while (auto *bbi = beginBorrowsToShrink.pop()) {
441-
shrinkBorrowScope(bbi, deleter);
441+
changed |= shrinkBorrowScope(bbi, deleter);
442442
}
443443

444444
// canonicalizer performs all modifications through deleter's callbacks, so we

lib/SILOptimizer/Utils/CanonicalizeInstruction.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -445,9 +445,13 @@ static SILBasicBlock::iterator
445445
eliminateSimpleBorrows(BeginBorrowInst *bbi, CanonicalizeInstruction &pass) {
446446
auto next = std::next(bbi->getIterator());
447447

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

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

0 commit comments

Comments
 (0)