Skip to content

Commit 8996fb8

Browse files
committed
Add functionality to the OSSA BorrowedValue utility.
This abstraction is heavily used to ask about the current borrow scope enclosing some uses. Give it the functionality it needs. Add BorrowedValue::computeLiveness(PrunedLiveness). Get the borrow scope's live range. A trivial 4-line implementation. Cleanup BorrowedValue::areUsesWithinScope(). Quick check to see if a set of uses known to be dominated by the borrow are within the borrow scope. Add BorrowedValue::hasReborrow(). Is this local borrow scope reborrowed? If not, then it's local scope-ending operations are the end of its required lifetime. Simplify BorrowedValue::gatherReborrows() to use OperandOwnership::Reborrow.
1 parent 70a14ff commit 8996fb8

File tree

3 files changed

+45
-36
lines changed

3 files changed

+45
-36
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515

1616
#include "swift/Basic/Debug.h"
1717
#include "swift/Basic/LLVM.h"
18+
#include "swift/SIL/MemAccessUtils.h"
1819
#include "swift/SIL/SILArgument.h"
19-
#include "swift/SIL/SILInstruction.h"
2020
#include "swift/SIL/SILBasicBlock.h"
21+
#include "swift/SIL/SILInstruction.h"
2122
#include "swift/SIL/SILValue.h"
2223
#include "llvm/ADT/SmallPtrSet.h"
2324
#include "llvm/ADT/SmallVector.h"
@@ -29,6 +30,7 @@ class SILInstruction;
2930
class SILModule;
3031
class SILValue;
3132
class DeadEndBlocks;
33+
class PrunedLiveness;
3234

3335
/// Returns true if v is an address or trivial.
3436
bool isValueAddressOrTrivial(SILValue v);
@@ -535,14 +537,19 @@ struct BorrowedValue {
535537

536538
bool isLocalScope() const { return kind.isLocalScope(); }
537539

538-
/// Returns true if the passed in set of uses is completely within
539-
/// the lifetime of this borrow introducer.
540+
/// Add this scopes live blocks into the PrunedLiveness result.
541+
void computeLiveness(PrunedLiveness &liveness) const;
542+
543+
/// Returns true if \p uses are completely within this borrow introducer's
544+
/// local scope.
545+
///
546+
/// Precondition: \p uses are dominated by the local borrow introducer.
540547
///
541-
/// NOTE: Scratch space is used internally to this method to store the end
542-
/// borrow scopes if needed.
543-
bool areUsesWithinScope(ArrayRef<Operand *> uses,
544-
SmallVectorImpl<Operand *> &scratchSpace,
545-
DeadEndBlocks &deadEndBlocks) const;
548+
/// This ignores reborrows. The assumption is that, since \p uses are
549+
/// dominated by this local scope, checking the extended borrow scope should
550+
/// not be necessary to determine they are within the scope.
551+
bool areUsesWithinLocalScope(ArrayRef<Operand *> uses,
552+
DeadEndBlocks &deadEndBlocks) const;
546553

547554
/// Given a local borrow scope introducer, visit all non-forwarding consuming
548555
/// users. This means that this looks through guaranteed block arguments. \p
@@ -583,6 +590,14 @@ struct BorrowedValue {
583590
func, InteriorPointerOperandVisitorKind::YesNestedYesReborrows);
584591
}
585592

593+
bool hasReborrow() const {
594+
for (auto *op : value->getUses()) {
595+
if (op->getOperandOwnership() == OperandOwnership::Reborrow)
596+
return true;
597+
}
598+
return false;
599+
}
600+
586601
/// Visit all immediate uses of this borrowed value and if any of them are
587602
/// reborrows, place them in BorrowingOperand form into \p
588603
/// foundReborrows. Returns true if we appended any such reborrows to
@@ -591,12 +606,10 @@ struct BorrowedValue {
591606
&foundReborrows) const {
592607
bool foundAnyReborrows = false;
593608
for (auto *op : value->getUses()) {
594-
if (auto borrowingOperand = BorrowingOperand(op)) {
595-
if (borrowingOperand.isReborrow()) {
596-
foundReborrows.push_back(
597-
{value->getParentBlock(), op->getOperandNumber()});
598-
foundAnyReborrows = true;
599-
}
609+
if (op->getOperandOwnership() == OperandOwnership::Reborrow) {
610+
foundReborrows.push_back(
611+
{value->getParentBlock(), op->getOperandNumber()});
612+
foundAnyReborrows = true;
600613
}
601614
}
602615
return foundAnyReborrows;

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -550,14 +550,17 @@ llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &os,
550550
return os;
551551
}
552552

553-
bool BorrowedValue::areUsesWithinScope(
554-
ArrayRef<Operand *> uses, SmallVectorImpl<Operand *> &scratchSpace,
555-
DeadEndBlocks &deadEndBlocks) const {
556-
// Make sure that we clear our scratch space/utilities before we exit.
557-
SWIFT_DEFER {
558-
scratchSpace.clear();
559-
};
553+
/// Add this scopes live blocks into the PrunedLiveness result.
554+
void BorrowedValue::computeLiveness(PrunedLiveness &liveness) const {
555+
liveness.initializeDefBlock(value->getParentBlock());
556+
visitLocalScopeEndingUses([&](Operand *endOp) {
557+
liveness.updateForUse(endOp->getUser(), true);
558+
return true;
559+
});
560+
}
560561

562+
bool BorrowedValue::areUsesWithinLocalScope(
563+
ArrayRef<Operand *> uses, DeadEndBlocks &deadEndBlocks) const {
561564
// First make sure that we actually have a local scope. If we have a non-local
562565
// scope, then we have something (like a SILFunctionArgument) where a larger
563566
// semantic construct (in the case of SILFunctionArgument, the function
@@ -566,15 +569,10 @@ bool BorrowedValue::areUsesWithinScope(
566569
if (!isLocalScope())
567570
return true;
568571

569-
// Otherwise, gather up our local scope ending instructions, looking through
570-
// guaranteed phi nodes.
571-
visitExtendedLocalScopeEndingUses([&scratchSpace](Operand *op) {
572-
scratchSpace.emplace_back(op);
573-
return true;
574-
});
575-
576-
LinearLifetimeChecker checker(deadEndBlocks);
577-
return checker.validateLifetime(value, scratchSpace, uses);
572+
// Compute the local scope's liveness.
573+
PrunedLiveness liveness;
574+
computeLiveness(liveness);
575+
return liveness.areUsesWithinBoundary(uses, deadEndBlocks);
578576
}
579577

580578
// The visitor \p func is only called on final scope-ending uses, not reborrows.

lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,8 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(
186186
return false;
187187
SmallVector<Operand *, 8> scratchSpace;
188188
if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) {
189-
return !borrowScope.areUsesWithinScope(lr.getAllConsumingUses(),
190-
scratchSpace,
191-
getDeadEndBlocks());
189+
return !borrowScope.areUsesWithinLocalScope(lr.getAllConsumingUses(),
190+
getDeadEndBlocks());
192191
})) {
193192
return false;
194193
}
@@ -216,9 +215,8 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(
216215
}
217216

218217
if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) {
219-
return !borrowScope.areUsesWithinScope(
220-
phiArgLR.getAllConsumingUses(), scratchSpace,
221-
getDeadEndBlocks());
218+
return !borrowScope.areUsesWithinLocalScope(
219+
phiArgLR.getAllConsumingUses(), getDeadEndBlocks());
222220
})) {
223221
return false;
224222
}

0 commit comments

Comments
 (0)