Skip to content

Commit f407389

Browse files
authored
Merge pull request #62634 from atrick/enclosing-def
Add findEnclosingDefs and findBorrowIntroducers utilities
2 parents 8cd86a2 + b85aea1 commit f407389

File tree

11 files changed

+1001
-76
lines changed

11 files changed

+1001
-76
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,12 @@ SILValue findOwnershipReferenceRoot(SILValue ref);
206206

207207
/// Look through all ownership forwarding instructions to find the values which
208208
/// were originally borrowed.
209-
void findGuaranteedReferenceRoots(SILValue value, bool lookThroughNestedBorrows,
209+
///
210+
/// Note: This treats guaranteed forwarding phis like roots even though they do
211+
/// not introduce the borrow scope. This ensures that all roots dominate \p
212+
/// reference Value. But the client will need to handle forwarding phis.
213+
void findGuaranteedReferenceRoots(SILValue referenceValue,
214+
bool lookThroughNestedBorrows,
210215
SmallVectorImpl<SILValue> &roots);
211216

212217
/// Find the aggregate containing the first owned root of the

include/swift/SIL/OwnershipUtils.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "swift/SIL/SILBasicBlock.h"
5151
#include "swift/SIL/SILInstruction.h"
5252
#include "swift/SIL/SILValue.h"
53+
#include "swift/SIL/StackList.h"
5354
#include "llvm/ADT/SmallPtrSet.h"
5455
#include "llvm/ADT/SmallVector.h"
5556

@@ -1299,6 +1300,18 @@ void visitExtendedGuaranteedForwardingPhiBaseValuePairs(
12991300
BorrowedValue borrow, function_ref<void(SILPhiArgument *, SILValue)>
13001301
visitGuaranteedForwardingPhiBaseValuePair);
13011302

1303+
/// If \p value is a guaranteed non-phi value forwarded from it's instruction's
1304+
/// operands, visit each forwarded operand.
1305+
///
1306+
/// Returns true if \p visitOperand was called (for convenience).
1307+
///
1308+
/// Precondition: \p value is not a phi. The client must handle phis first by
1309+
/// checking if they are reborrows (using BorrowedValue). Reborrows have no
1310+
/// forwarded operands. Guaranteed forwarding need to be handled by recursing
1311+
/// through the phi operands.
1312+
bool visitForwardedGuaranteedOperands(
1313+
SILValue value, function_ref<void(Operand *)> visitOperand);
1314+
13021315
/// Visit the phis in the same block as \p phi which are reborrows of a borrow
13031316
/// of one of the values reaching \p phi.
13041317
///
@@ -1307,6 +1320,24 @@ void visitExtendedGuaranteedForwardingPhiBaseValuePairs(
13071320
bool visitAdjacentReborrowsOfPhi(SILPhiArgument *phi,
13081321
function_ref<bool(SILPhiArgument *)> visitor);
13091322

1323+
/// Visit each definition of a scope that immediately encloses a guaranteed
1324+
/// value. The guaranteed value effectively keeps these scopes alive.
1325+
///
1326+
/// This means something different depepending on whether \p value is itself a
1327+
/// borrow introducer vs. a forwarded guaranteed value. If \p value is an
1328+
/// introducer, then this discovers the enclosing borrow scope and visits all
1329+
/// introducers of that scope. If \p value is a forwarded value, then this
1330+
/// visits the introducers of the current borrow scope.
1331+
bool visitEnclosingDefs(SILValue value, function_ref<bool(SILValue)> visitor);
1332+
1333+
/// Visit the values that introduce the borrow scopes that includes \p
1334+
/// value. If value is owned, or introduces a borrow scope, then this only
1335+
/// visits \p value.
1336+
///
1337+
/// Returns false if the visitor returned false and exited early.
1338+
bool visitBorrowIntroducers(SILValue value,
1339+
function_ref<bool(SILValue)> visitor);
1340+
13101341
/// Given a begin of a borrow scope, visit all end_borrow users of the borrow or
13111342
/// its reborrows.
13121343
void visitTransitiveEndBorrows(

include/swift/SIL/SILArgument.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ class SILArgument : public ValueBase {
205205
/// Precondition: this->isTerminatorResult()
206206
///
207207
/// TODO: Move this and other APIs into a TerminatorResult abstraction.
208-
const Operand *forwardedTerminatorResultOperand() const;
208+
Operand *forwardedTerminatorResultOperand() const;
209209

210210
/// Return the SILArgumentKind of this argument.
211211
SILArgumentKind getKind() const {

include/swift/SIL/SILInstruction.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,10 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
599599
return getTypeDependentOperands().size();
600600
}
601601

602+
unsigned getNumRealOperands() const {
603+
return getAllOperands().size() - getNumTypeDependentOperands();
604+
}
605+
602606
bool isTypeDependentOperand(unsigned i) const {
603607
return i >= getNumOperands() - getNumTypeDependentOperands();
604608
}
@@ -8496,9 +8500,14 @@ class TermInst : public NonValueInstruction {
84968500
/// example, a switch forwards ownership of the enum type into ownership of
84978501
/// the payload.
84988502
///
8499-
/// Postcondition: each successor has zero or one block arguments which
8500-
/// represents the forwaded result.
8503+
/// Postcondition: if the result is non-null, then each successor has zero or
8504+
/// one block arguments which represents the forwaded result.
85018505
const Operand *forwardedOperand() const;
8506+
8507+
Operand *forwardedOperand() {
8508+
return const_cast<Operand *>(
8509+
static_cast<const TermInst *>(this)->forwardedOperand());
8510+
}
85028511
};
85038512

85048513
// Forwards the first operand to a result in each successor block.

lib/SIL/IR/SILArgument.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ TermInst *SILPhiArgument::getTerminatorForResult() const {
341341
return nullptr;
342342
}
343343

344-
const Operand *SILArgument::forwardedTerminatorResultOperand() const {
344+
Operand *SILArgument::forwardedTerminatorResultOperand() const {
345345
assert(isTerminatorResult() && "API is invalid for phis");
346346
return getSingleTerminator()->forwardedOperand();
347347
}

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 29 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "swift/Basic/GraphNodeWorklist.h"
1717
#include "swift/SIL/Consumption.h"
1818
#include "swift/SIL/DynamicCasts.h"
19+
#include "swift/SIL/NodeDatastructures.h"
20+
#include "swift/SIL/OwnershipUtils.h"
1921
#include "swift/SIL/SILBridging.h"
2022
#include "swift/SIL/SILBridgingUtils.h"
2123
#include "swift/SIL/SILInstruction.h"
@@ -860,78 +862,42 @@ SILValue swift::findOwnershipReferenceRoot(SILValue ref) {
860862
return ref;
861863
}
862864

863-
void swift::findGuaranteedReferenceRoots(SILValue value,
865+
void swift::findGuaranteedReferenceRoots(SILValue referenceValue,
864866
bool lookThroughNestedBorrows,
865867
SmallVectorImpl<SILValue> &roots) {
866-
GraphNodeWorklist<SILValue, 4> worklist;
867-
auto addAllOperandsToWorklist = [&worklist](SILInstruction *inst) -> bool {
868-
if (inst->getNumOperands() > 0) {
869-
for (auto operand : inst->getOperandValues()) {
870-
worklist.insert(operand);
871-
}
872-
return true;
873-
}
874-
return false;
875-
};
876-
worklist.initialize(value);
868+
ValueWorklist worklist(referenceValue->getFunction());
869+
worklist.pushIfNotVisited(referenceValue);
877870
while (auto value = worklist.pop()) {
878-
if (auto *result = SILArgument::isTerminatorResult(value)) {
879-
if (auto *forwardedOper = result->forwardedTerminatorResultOperand()) {
880-
worklist.insert(forwardedOper->get());
881-
continue;
882-
}
883-
} else if (auto *inst = value->getDefiningInstruction()) {
884-
if (auto *bbi = dyn_cast<BeginBorrowInst>(inst)) {
871+
// Instructions may forwarded None ownership to guaranteed.
872+
if (value->getOwnershipKind() != OwnershipKind::Guaranteed)
873+
continue;
874+
875+
if (SILArgument::asPhi(value)) {
876+
roots.push_back(value);
877+
continue;
878+
}
879+
880+
if (visitForwardedGuaranteedOperands(value, [&](Operand *operand) {
881+
worklist.pushIfNotVisited(operand->get());
882+
})) {
883+
// This instruction is not a root if any operands were forwarded,
884+
// regardless of whether they were already visited.
885+
continue;
886+
}
887+
// Found a potential root.
888+
if (lookThroughNestedBorrows) {
889+
if (auto *bbi = dyn_cast<BeginBorrowInst>(value)) {
885890
auto borrowee = bbi->getOperand();
886-
if (lookThroughNestedBorrows &&
887-
borrowee->getOwnershipKind() == OwnershipKind::Guaranteed) {
891+
if (borrowee->getOwnershipKind() == OwnershipKind::Guaranteed) {
888892
// A nested borrow, the root guaranteed earlier in the use-def chain.
889-
worklist.insert(borrowee);
890-
}
891-
// The borrowee isn't guaranteed or we aren't looking through nested
892-
// borrows. Fall through to add the begin_borrow to roots.
893-
} else if (auto *result =
894-
dyn_cast<FirstArgOwnershipForwardingSingleValueInst>(inst)) {
895-
if (result->getNumOperands() > 0) {
896-
worklist.insert(result->getOperand(0));
897-
continue;
898-
}
899-
} else if (auto *result =
900-
dyn_cast<AllArgOwnershipForwardingSingleValueInst>(inst)) {
901-
if (addAllOperandsToWorklist(result)) {
902-
continue;
903-
}
904-
} else if (auto *result = dyn_cast<OwnershipForwardingTermInst>(inst)) {
905-
assert(false && "value defined by a terminator?!");
906-
} else if (auto *result =
907-
dyn_cast<OwnershipForwardingConversionInst>(inst)) {
908-
worklist.insert(result->getConverted());
909-
continue;
910-
} else if (auto *result =
911-
dyn_cast<OwnershipForwardingSelectEnumInstBase>(inst)) {
912-
if (addAllOperandsToWorklist(result)) {
913-
continue;
914-
}
915-
} else if (auto *result =
916-
dyn_cast<OwnershipForwardingMultipleValueInstruction>(
917-
inst)) {
918-
if (addAllOperandsToWorklist(result)) {
919-
continue;
920-
}
921-
} else if (auto *mvi =
922-
dyn_cast<MoveOnlyWrapperToCopyableValueInst>(inst)) {
923-
if (addAllOperandsToWorklist(mvi)) {
924-
continue;
925-
}
926-
} else if (auto *c = dyn_cast<CopyableToMoveOnlyWrapperValueInst>(inst)) {
927-
if (addAllOperandsToWorklist(c)) {
893+
worklist.pushIfNotVisited(borrowee);
928894
continue;
929895
}
896+
// The borrowee isn't guaranteed or we aren't looking through nested
897+
// borrows. Fall through to add the begin_borrow to roots.
930898
}
931899
}
932-
933-
if (value->getOwnershipKind() == OwnershipKind::Guaranteed)
934-
roots.push_back(value);
900+
roots.push_back(value);
935901
}
936902
}
937903

0 commit comments

Comments
 (0)