Skip to content

Commit f29bb44

Browse files
committed
OwnershipUseVisitor::visitInnerBorrowUses: support dependent values
Add liveness support for dependent values: borrowed-from & mark_dependence so they aren't reported as unknown uses. Centralize the logic in BorrowingOperand::getScopeIntroducingUserResult and BorrowingOperand::getDependentUserResult().
1 parent b854ab1 commit f29bb44

File tree

3 files changed

+102
-43
lines changed

3 files changed

+102
-43
lines changed

include/swift/SIL/OwnershipUseVisitor.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,17 +261,36 @@ bool OwnershipUseVisitor<Impl>::visitOuterBorrowScopeEnd(Operand *borrowEnd) {
261261
/// (begin_borrow, load_borrow, or begin_apply).
262262
template <typename Impl>
263263
bool OwnershipUseVisitor<Impl>::visitInnerBorrow(Operand *borrowingOperand) {
264-
if (!asImpl().handleInnerBorrow(borrowingOperand))
265-
return false;
264+
auto bo = BorrowingOperand(borrowingOperand);
265+
assert(bo && "unexpected Borrow operand ownership");
266+
if (bo.getScopeIntroducingUserResult()) {
267+
if (!asImpl().handleInnerBorrow(borrowingOperand))
268+
return false;
266269

267-
return BorrowingOperand(borrowingOperand)
268-
.visitScopeEndingUses(
270+
return bo.visitScopeEndingUses(
269271
[&](Operand *borrowEnd) {
270272
return visitInnerBorrowScopeEnd(borrowEnd);
271273
},
272274
[&](Operand *unknownUse) {
273275
return asImpl().handlePointerEscape(unknownUse);
274276
});
277+
}
278+
if (auto dependentValue = bo.getDependentUserResult()) {
279+
switch (dependentValue->getOwnershipKind()) {
280+
case OwnershipKind::Guaranteed:
281+
if (!handleUsePoint(borrowingOperand,
282+
UseLifetimeConstraint::NonLifetimeEnding)) {
283+
return false;
284+
}
285+
return visitGuaranteedUses(dependentValue);
286+
case OwnershipKind::Any:
287+
case OwnershipKind::None:
288+
case OwnershipKind::Owned: // non-escapable
289+
case OwnershipKind::Unowned:
290+
break;
291+
}
292+
}
293+
return asImpl().handlePointerEscape(borrowingOperand);
275294
}
276295

277296
/// Note: borrowEnd->get() may be a borrow introducer for an inner scope, or a

include/swift/SIL/OwnershipUtils.h

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ struct BorrowingOperand {
362362
/// Returns false and early exits if the \p visitScopeEnd or \p
363363
/// visitUnknownUse returns false.
364364
///
365+
/// This only calls 'visitScopeEnd` when getScopeIntroducingUserResult() is
366+
/// valid. Otherwise, it immediate calls visitUnknownUse on the current
367+
/// operand.
368+
///
365369
/// For an instantaneous borrow, such as apply, this visits no uses. For
366370
/// begin_apply it visits the end_apply uses. For borrow introducers, it
367371
/// visits the end of the introduced borrow scope.
@@ -430,25 +434,7 @@ struct BorrowingOperand {
430434
/// If true, getBorrowIntroducingUserResult() can be called to acquire the
431435
/// SILValue that introduces a new borrow scope.
432436
bool hasBorrowIntroducingUser() const {
433-
// TODO: Can we derive this by running a borrow introducer check ourselves?
434-
switch (kind) {
435-
case BorrowingOperandKind::Invalid:
436-
llvm_unreachable("Using invalid case?!");
437-
case BorrowingOperandKind::BeginBorrow:
438-
case BorrowingOperandKind::BorrowedFrom:
439-
case BorrowingOperandKind::Branch:
440-
return true;
441-
case BorrowingOperandKind::StoreBorrow:
442-
case BorrowingOperandKind::BeginApply:
443-
case BorrowingOperandKind::Apply:
444-
case BorrowingOperandKind::TryApply:
445-
case BorrowingOperandKind::Yield:
446-
case BorrowingOperandKind::PartialApplyStack:
447-
case BorrowingOperandKind::MarkDependenceNonEscaping:
448-
case BorrowingOperandKind::BeginAsyncLet:
449-
return false;
450-
}
451-
llvm_unreachable("Covered switch isn't covered?!");
437+
return getBorrowIntroducingUserResult() != SILValue();
452438
}
453439

454440
/// If this operand's user has a single result that introduces the borrow
@@ -457,8 +443,21 @@ struct BorrowingOperand {
457443
/// guaranteed forwarding phis, are not scoped.
458444
SILValue getBorrowIntroducingUserResult() const;
459445

460-
/// Return the borrowing operand's value.
461-
SILValue getScopeIntroducingUserResult();
446+
/// Return the borrowing operand's value if it is a scoped operation,
447+
/// such as partial_apply, mark_dependence, store_borrow, begin_async_let.
448+
///
449+
/// This is meant to be equivalent to BeginBorrowValue in
450+
/// SwiftCompilerSources.
451+
SILValue getScopeIntroducingUserResult() const;
452+
453+
// Return the dependent value of borrowed-from or mark_dependence.
454+
//
455+
// This only returns a valid result when getScopeIntroducingUserResult()
456+
// returns an invalid result. Ideally, we would convert BorrowingOperand into
457+
// an enum to partition the kinds of borrows.
458+
//
459+
// This may be a guaranteed, trivial, or owned non-escapable value.
460+
SILValue getDependentUserResult() const;
462461

463462
void print(llvm::raw_ostream &os) const;
464463
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ bool BorrowingOperand::visitExtendedScopeEndingUses(
786786
return visitScopeEndingUses(visitor, visitUnknownUse);
787787
}
788788

789+
// This should be equivalent to SwiftCompilerSources, BorrowedValue.
789790
SILValue BorrowingOperand::getBorrowIntroducingUserResult() const {
790791
switch (kind) {
791792
case BorrowingOperandKind::Invalid:
@@ -800,8 +801,16 @@ SILValue BorrowingOperand::getBorrowIntroducingUserResult() const {
800801
return SILValue();
801802

802803
case BorrowingOperandKind::BeginBorrow:
803-
case BorrowingOperandKind::BorrowedFrom: {
804804
return cast<SingleValueInstruction>(op->getUser());
805+
806+
case BorrowingOperandKind::BorrowedFrom: {
807+
// A reborrow introduces a new borrow scope, a guaranteed forwarding phi
808+
// does not.
809+
auto *bfi = cast<BorrowedFromInst>(op->getUser());
810+
if (bfi->isReborrow()) {
811+
return bfi->getBorrowedValue();
812+
}
813+
return SILValue();
805814
}
806815
case BorrowingOperandKind::Branch: {
807816
auto *bi = cast<BranchInst>(op->getUser());
@@ -811,29 +820,57 @@ SILValue BorrowingOperand::getBorrowIntroducingUserResult() const {
811820
llvm_unreachable("covered switch");
812821
}
813822

814-
SILValue BorrowingOperand::getScopeIntroducingUserResult() {
823+
SILValue BorrowingOperand::getScopeIntroducingUserResult() const {
815824
switch (kind) {
816-
case BorrowingOperandKind::Invalid:
817-
case BorrowingOperandKind::Yield:
818-
case BorrowingOperandKind::Apply:
819-
case BorrowingOperandKind::TryApply:
820-
return SILValue();
821-
822825
case BorrowingOperandKind::BeginAsyncLet:
823826
case BorrowingOperandKind::PartialApplyStack:
824-
case BorrowingOperandKind::MarkDependenceNonEscaping:
825-
case BorrowingOperandKind::BeginBorrow:
826-
case BorrowingOperandKind::BorrowedFrom:
827827
case BorrowingOperandKind::StoreBorrow:
828828
return cast<SingleValueInstruction>(op->getUser());
829829

830+
case BorrowingOperandKind::MarkDependenceNonEscaping:
831+
if (auto *mdi = cast<MarkDependenceInst>(op->getUser())) {
832+
if (mdi->hasScopedLifetime())
833+
return mdi;
834+
}
835+
return SILValue();
836+
830837
case BorrowingOperandKind::BeginApply:
831838
return cast<BeginApplyInst>(op->getUser())->getTokenResult();
832839

833-
case BorrowingOperandKind::Branch: {
834-
PhiOperand phiOp(op);
835-
return phiOp.getValue();
840+
default:
841+
return getBorrowIntroducingUserResult();
836842
}
843+
llvm_unreachable("covered switch");
844+
}
845+
846+
SILValue BorrowingOperand::getDependentUserResult() const {
847+
switch (kind) {
848+
case BorrowingOperandKind::BorrowedFrom: {
849+
auto *bfi = cast<BorrowedFromInst>(op->getUser());
850+
if (!bfi->isReborrow())
851+
return bfi;
852+
853+
return SILValue();
854+
}
855+
case BorrowingOperandKind::MarkDependenceNonEscaping: {
856+
auto *mdi = cast<MarkDependenceInst>(op->getUser());
857+
assert(mdi->isNonEscaping() && "escaping dependencies don't borrow");
858+
if (!mdi->hasScopedLifetime())
859+
return mdi;
860+
861+
return SILValue();
862+
}
863+
case BorrowingOperandKind::Invalid:
864+
case BorrowingOperandKind::BeginBorrow:
865+
case BorrowingOperandKind::StoreBorrow:
866+
case BorrowingOperandKind::BeginApply:
867+
case BorrowingOperandKind::Branch:
868+
case BorrowingOperandKind::Apply:
869+
case BorrowingOperandKind::TryApply:
870+
case BorrowingOperandKind::Yield:
871+
case BorrowingOperandKind::PartialApplyStack:
872+
case BorrowingOperandKind::BeginAsyncLet:
873+
return SILValue();
837874
}
838875
llvm_unreachable("covered switch");
839876
}
@@ -1044,6 +1081,9 @@ bool BorrowedValue::visitInteriorPointerOperandHelper(
10441081
}
10451082

10461083
auto result = borrowingOperand.getBorrowIntroducingUserResult();
1084+
if (!result) {
1085+
result = borrowingOperand.getDependentUserResult();
1086+
}
10471087
for (auto *use : result->getUses()) {
10481088
if (auto intPtrOperand = InteriorPointerOperand(use)) {
10491089
func(intPtrOperand);
@@ -1070,11 +1110,12 @@ bool BorrowedValue::visitInteriorPointerOperandHelper(
10701110
continue;
10711111
}
10721112

1073-
// Look through object.
1113+
// Look through object. SingleValueInstruction is overly restrictive but
1114+
// rules out any interesting corner cases.
10741115
if (auto *svi = dyn_cast<SingleValueInstruction>(user)) {
1075-
if (Projection::isObjectProjection(svi)) {
1076-
for (SILValue result : user->getResults()) {
1077-
llvm::copy(result->getUses(), std::back_inserter(worklist));
1116+
if (ForwardingInstruction::isa(user)) {
1117+
for (auto *use : svi->getUses()) {
1118+
worklist.push_back(use);
10781119
}
10791120
continue;
10801121
}

0 commit comments

Comments
 (0)