Skip to content

Commit c2ae7e0

Browse files
committed
Add visitForwardedGuaranteedOperands utility.
Factors a mess of code in MemAccessUtils to handle forwarding instruction types into a simpler utility. This utility is also needed for ownership APIs, which need to be extended to handle these cases.
1 parent 090f049 commit c2ae7e0

File tree

5 files changed

+105
-62
lines changed

5 files changed

+105
-62
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ SILValue findOwnershipReferenceRoot(SILValue ref);
206206

207207
/// Look through all ownership forwarding instructions to find the values which
208208
/// were originally borrowed.
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.
209213
void findGuaranteedReferenceRoots(SILValue referenceValue,
210214
bool lookThroughNestedBorrows,
211215
SmallVectorImpl<SILValue> &roots);

include/swift/SIL/OwnershipUtils.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,18 @@ void visitExtendedGuaranteedForwardingPhiBaseValuePairs(
12991299
BorrowedValue borrow, function_ref<void(SILPhiArgument *, SILValue)>
13001300
visitGuaranteedForwardingPhiBaseValuePair);
13011301

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

include/swift/SIL/SILInstruction.h

Lines changed: 4 additions & 0 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
}

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 28 additions & 62 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"
@@ -863,75 +865,39 @@ SILValue swift::findOwnershipReferenceRoot(SILValue ref) {
863865
void swift::findGuaranteedReferenceRoots(SILValue value,
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

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,6 +1721,63 @@ void swift::visitExtendedGuaranteedForwardingPhiBaseValuePairs(
17211721
}
17221722
}
17231723

1724+
/// If \p instruction forwards guaranteed values to its results, visit each
1725+
/// forwarded operand. The visitor must check whether the forwarded value is
1726+
/// guaranteed.
1727+
///
1728+
/// Return true \p visitOperand was called at least once.
1729+
///
1730+
/// \p visitOperand should always recheck for Guaranteed owernship if it
1731+
/// matters, in case a cast forwards a trivial type to a nontrivial type.
1732+
///
1733+
/// This intentionally does not handle phis, which require recursive traversal
1734+
/// to determine `isGuaranteedForwardingPhi`.
1735+
bool swift::visitForwardedGuaranteedOperands(
1736+
SILValue value, function_ref<void(Operand *)> visitOperand) {
1737+
1738+
assert(!SILArgument::asPhi(value) && "phis are handled separately");
1739+
1740+
if (auto *termResult = SILArgument::isTerminatorResult(value)) {
1741+
if (auto *oper = termResult->forwardedTerminatorResultOperand()) {
1742+
visitOperand(oper);
1743+
return true;
1744+
}
1745+
return false;
1746+
}
1747+
auto *inst = value->getDefiningInstruction();
1748+
if (!inst)
1749+
return false;
1750+
1751+
// Bypass conversions that produce a guarantee value out of thin air.
1752+
if (inst->getNumRealOperands() == 0) {
1753+
return false;
1754+
}
1755+
if (isa<FirstArgOwnershipForwardingSingleValueInst>(inst)
1756+
|| isa<OwnershipForwardingConversionInst>(inst)
1757+
|| isa<OwnershipForwardingSelectEnumInstBase>(inst)
1758+
|| isa<OwnershipForwardingMultipleValueInstruction>(inst)
1759+
|| isa<MoveOnlyWrapperToCopyableValueInst>(inst)
1760+
|| isa<CopyableToMoveOnlyWrapperValueInst>(inst)) {
1761+
assert(inst->getNumRealOperands() == 1
1762+
&& "forwarding instructions must have a single real operand");
1763+
assert(!isa<SingleValueInstruction>(inst)
1764+
|| !BorrowedValue(cast<SingleValueInstruction>(inst))
1765+
&& "forwarded operand cannot begin a borrow scope");
1766+
visitOperand(&inst->getOperandRef(0));
1767+
return true;
1768+
}
1769+
if (isa<AllArgOwnershipForwardingSingleValueInst>(inst)) {
1770+
assert(inst->getNumOperands() > 0 && "checked above");
1771+
assert(inst->getNumOperands() == inst->getNumRealOperands() &&
1772+
"mixin expects all readl operands");
1773+
for (auto &operand : inst->getAllOperands()) {
1774+
visitOperand(&operand);
1775+
}
1776+
return true;
1777+
}
1778+
return false;
1779+
}
1780+
17241781
/// Visit the phis in the same block as \p phi which are reborrows of a borrow
17251782
/// of one of the values reaching \p phi.
17261783
///

0 commit comments

Comments
 (0)