Skip to content

Commit 24ec0ed

Browse files
authored
Merge pull request #61505 from meg-gupta/guaranteedphis
Support @guaranteed forwarding phis
2 parents 5b88024 + 283f15e commit 24ec0ed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1395
-577
lines changed

include/swift/SIL/LinearLifetimeChecker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class LinearLifetimeChecker {
5353
class ErrorBuilder;
5454

5555
private:
56-
friend class ReborrowVerifier;
56+
friend class GuaranteedPhiVerifier;
5757
friend class SILOwnershipVerifier;
5858
friend class SILValueOwnershipChecker;
5959

include/swift/SIL/OwnershipUtils.h

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,49 @@ struct BorrowedValue;
7373
/// values?
7474
///
7575
/// This may be true even if the current instance of the instruction is not a
76-
/// ForwardingBorrow. If true, then the operation may be trivially rewritten
76+
/// GuaranteedForwarding. If true, then the operation may be trivially rewritten
7777
/// with Guaranteed ownership.
7878
bool canOpcodeForwardGuaranteedValues(SILValue value);
7979

8080
/// Is the opcode that consumes \p use capable of forwarding guaranteed values?
8181
///
82-
/// This may be true even if \p use is not a ForwardingBorrow. If true, then the
83-
/// operation may be trivially rewritten with Guaranteed ownership.
82+
/// This may be true even if \p use is not a GuaranteedForwarding. If true, then
83+
/// the operation may be trivially rewritten with Guaranteed ownership.
8484
bool canOpcodeForwardGuaranteedValues(Operand *use);
8585

8686
// This is the use-def equivalent of use->getOperandOwnership() ==
87-
// OperandOwnership::ForwardingBorrow.
88-
inline bool isForwardingBorrow(SILValue value) {
87+
// OperandOwnership::GuaranteedForwarding.
88+
inline bool isGuaranteedForwarding(SILValue value) {
8989
assert(value->getOwnershipKind() == OwnershipKind::Guaranteed);
9090
return canOpcodeForwardGuaranteedValues(value);
9191
}
9292

93+
/// Returns true if it is a forwarding phi
94+
inline bool isGuaranteedForwardingPhi(SILValue value) {
95+
if (value->getOwnershipKind() != OwnershipKind::Guaranteed) {
96+
return false;
97+
}
98+
if (isa<BeginBorrowInst>(value) || isa<LoadBorrowInst>(value)) {
99+
return false;
100+
}
101+
auto *phi = dyn_cast<SILPhiArgument>(value);
102+
if (!phi || !phi->isPhi()) {
103+
return true;
104+
}
105+
bool isGuaranteedForwardingPhi = true;
106+
phi->visitTransitiveIncomingPhiOperands(
107+
[&](auto *phi, auto *operand) -> bool {
108+
if (isa<BeginBorrowInst>(operand->get()) ||
109+
isa<LoadBorrowInst>(operand->get())) {
110+
isGuaranteedForwardingPhi = false;
111+
return false;
112+
}
113+
return true;
114+
});
115+
116+
return isGuaranteedForwardingPhi;
117+
}
118+
93119
/// Is the opcode that produces \p value capable of forwarding owned values?
94120
///
95121
/// This may be true even if the current instance of the instruction is not a
@@ -215,6 +241,11 @@ bool findExtendedTransitiveGuaranteedUses(
215241
bool findUsesOfSimpleValue(SILValue value,
216242
SmallVectorImpl<Operand *> *usePoints = nullptr);
217243

244+
/// Visit all GuaranteedForwardingPhis of \p value, not looking through
245+
/// reborrows.
246+
bool visitGuaranteedForwardingPhisForSSAValue(
247+
SILValue value, function_ref<bool(Operand *)> func);
248+
218249
/// An operand that forwards ownership to one or more results.
219250
class ForwardingOperand {
220251
Operand *use = nullptr;
@@ -447,13 +478,7 @@ struct BorrowingOperand {
447478
/// set of its operands uses.
448479
///
449480
/// E.x.: end_apply uses.
450-
///
451-
/// \p errorFunction a callback that if non-null is passed an operand that
452-
/// triggers a mal-formed SIL error. This is just needed for the ownership
453-
/// verifier to emit good output.
454-
void getImplicitUses(
455-
SmallVectorImpl<Operand *> &foundUses,
456-
std::function<void(Operand *)> *errorFunction = nullptr) const;
481+
void getImplicitUses(SmallVectorImpl<Operand *> &foundUses) const;
457482

458483
void print(llvm::raw_ostream &os) const;
459484
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
@@ -1249,14 +1274,19 @@ OwnedValueIntroducer getSingleOwnedValueIntroducer(SILValue value);
12491274

12501275
using BaseValueSet = SmallPtrSet<SILValue, 8>;
12511276

1252-
/// Starting from \p initialScopeOperand, find all reborrows and their
1253-
/// corresponding base values, and run the visitor function \p
1254-
/// visitReborrowBaseValuePair on them.
1255-
/// Note that a reborrow phi, can have different base values based on different
1256-
/// control flow paths.
1257-
void findTransitiveReborrowBaseValuePairs(
1258-
BorrowingOperand initialScopeOperand, SILValue origBaseValue,
1259-
function_ref<void(SILPhiArgument *, SILValue)> visitReborrowBaseValuePair);
1277+
/// Starting from \p borrowInst, find all reborrows along with their base
1278+
/// values, and run the visitor function \p visitReborrowPhiBaseValuePair on
1279+
/// them.
1280+
void visitExtendedReborrowPhiBaseValuePairs(
1281+
BeginBorrowInst *borrowInst, function_ref<void(SILPhiArgument *, SILValue)>
1282+
visitReborrowPhiBaseValuePair);
1283+
1284+
/// Starting from \p borrow, find all GuaranteedForwardingPhi uses along with
1285+
/// their base values, and run the visitor function \p
1286+
/// visitGuaranteedForwardingPhiBaseValuePair on them.
1287+
void visitExtendedGuaranteedForwardingPhiBaseValuePairs(
1288+
BorrowedValue borrow, function_ref<void(SILPhiArgument *, SILValue)>
1289+
visitGuaranteedForwardingPhiBaseValuePair);
12601290

12611291
/// Visit the phis in the same block as \p phi which are reborrows of a borrow
12621292
/// of one of the values reaching \p phi.

include/swift/SIL/SILValue.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,9 @@ struct OperandOwnership {
832832
/// Forwarded Borrow. Propagates the guaranteed value within the base's
833833
/// borrow scope.
834834
/// (tuple_extract, struct_extract, cast, switch)
835-
ForwardingBorrow,
835+
GuaranteedForwarding,
836+
/// A GuaranteedForwarding value passed as a phi operand.
837+
GuaranteedForwardingPhi,
836838
/// End Borrow. End the borrow scope opened directly by the operand.
837839
/// The operand must be a begin_borrow, begin_apply, or function argument.
838840
/// (end_borrow, end_apply)
@@ -886,10 +888,11 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
886888
///
887889
/// Forwarding instructions that produce Owned or Guaranteed values always
888890
/// forward an operand of the same ownership kind. Each case has a distinct
889-
/// OperandOwnership (ForwardingConsume and ForwardingBorrow), which enforces a
890-
/// specific constraint on the operand's ownership. Forwarding instructions that
891-
/// produce an Unowned value, however, may forward an operand of any
892-
/// ownership. Therefore, ForwardingUnowned is mapped to OwnershipKind::Any.
891+
/// OperandOwnership (ForwardingConsume and GuaranteedForwarding), which
892+
/// enforces a specific constraint on the operand's ownership. Forwarding
893+
/// instructions that produce an Unowned value, however, may forward an operand
894+
/// of any ownership. Therefore, ForwardingUnowned is mapped to
895+
/// OwnershipKind::Any.
893896
///
894897
/// This design yields the following advantages:
895898
///
@@ -923,7 +926,8 @@ inline OwnershipConstraint OperandOwnership::getOwnershipConstraint() {
923926
case OperandOwnership::ForwardingConsume:
924927
return {OwnershipKind::Owned, UseLifetimeConstraint::LifetimeEnding};
925928
case OperandOwnership::InteriorPointer:
926-
case OperandOwnership::ForwardingBorrow:
929+
case OperandOwnership::GuaranteedForwarding:
930+
case OperandOwnership::GuaranteedForwardingPhi:
927931
return {OwnershipKind::Guaranteed,
928932
UseLifetimeConstraint::NonLifetimeEnding};
929933
case OperandOwnership::EndBorrow:
@@ -951,7 +955,8 @@ inline bool canAcceptUnownedValue(OperandOwnership operandOwnership) {
951955
case OperandOwnership::DestroyingConsume:
952956
case OperandOwnership::ForwardingConsume:
953957
case OperandOwnership::InteriorPointer:
954-
case OperandOwnership::ForwardingBorrow:
958+
case OperandOwnership::GuaranteedForwarding:
959+
case OperandOwnership::GuaranteedForwardingPhi:
955960
case OperandOwnership::EndBorrow:
956961
case OperandOwnership::Reborrow:
957962
return false;
@@ -990,7 +995,7 @@ ValueOwnershipKind::getForwardingOperandOwnership(bool allowUnowned) const {
990995
case OwnershipKind::None:
991996
return OperandOwnership::TrivialUse;
992997
case OwnershipKind::Guaranteed:
993-
return OperandOwnership::ForwardingBorrow;
998+
return OperandOwnership::GuaranteedForwarding;
994999
case OwnershipKind::Owned:
9951000
return OperandOwnership::ForwardingConsume;
9961001
}

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ bool swift::checkOperandOwnershipInvariants(const Operand *operand,
2727
// Must be a valid BorrowingOperand.
2828
return bool(BorrowingOperand(const_cast<Operand *>(operand)));
2929
}
30+
if (opOwnership == OperandOwnership::GuaranteedForwarding) {
31+
return canOpcodeForwardGuaranteedValues(const_cast<Operand *>(operand));
32+
}
3033
return true;
3134
}
3235

@@ -297,14 +300,14 @@ OPERAND_OWNERSHIP(InteriorPointer, HopToExecutor)
297300
OPERAND_OWNERSHIP(InteriorPointer, ExtractExecutor)
298301

299302
// Instructions that propagate a value within a borrow scope.
300-
OPERAND_OWNERSHIP(ForwardingBorrow, TupleExtract)
301-
OPERAND_OWNERSHIP(ForwardingBorrow, StructExtract)
302-
OPERAND_OWNERSHIP(ForwardingBorrow, DifferentiableFunctionExtract)
303-
OPERAND_OWNERSHIP(ForwardingBorrow, LinearFunctionExtract)
303+
OPERAND_OWNERSHIP(GuaranteedForwarding, TupleExtract)
304+
OPERAND_OWNERSHIP(GuaranteedForwarding, StructExtract)
305+
OPERAND_OWNERSHIP(GuaranteedForwarding, DifferentiableFunctionExtract)
306+
OPERAND_OWNERSHIP(GuaranteedForwarding, LinearFunctionExtract)
304307
// FIXME: OpenExistential[Box]Value should be able to take owned values too by
305308
// using getForwardingOperandOwnership.
306-
OPERAND_OWNERSHIP(ForwardingBorrow, OpenExistentialValue)
307-
OPERAND_OWNERSHIP(ForwardingBorrow, OpenExistentialBoxValue)
309+
OPERAND_OWNERSHIP(GuaranteedForwarding, OpenExistentialValue)
310+
OPERAND_OWNERSHIP(GuaranteedForwarding, OpenExistentialBoxValue)
308311

309312
OPERAND_OWNERSHIP(EndBorrow, EndBorrow)
310313

@@ -335,7 +338,7 @@ OPERAND_OWNERSHIP(EndBorrow, AbortApply)
335338
#undef OPERAND_OWNERSHIP
336339

337340
// Forwarding operations are conditionally either ForwardingConsumes or
338-
// ForwardingBorrows, depending on the instruction's constant ownership
341+
// GuaranteedForwarding, depending on the instruction's constant ownership
339342
// attribute.
340343
#define FORWARDING_OWNERSHIP(INST) \
341344
OperandOwnership OperandOwnershipClassifier::visit##INST##Inst( \
@@ -376,7 +379,7 @@ FORWARDING_ANY_OWNERSHIP(CheckedCastBranch)
376379
// the meet of its operands' ownership. A destructured member has the same
377380
// ownership as its aggregate unless its type gives it None ownership.
378381
//
379-
// TODO: Aggregate operations should be Reborrows, not ForwardingBorrows,
382+
// TODO: Aggregate operations should be Reborrows, not GuaranteedForwarding,
380383
// because the borrowed value is different on either side of the operation and
381384
// the lifetimes of borrowed members could differ.
382385
#define AGGREGATE_OWNERSHIP(INST) \
@@ -422,15 +425,15 @@ OperandOwnershipClassifier::visitSelectEnumInst(SelectEnumInst *i) {
422425
OperandOwnership
423426
OperandOwnershipClassifier::visitSelectValueInst(SelectValueInst *i) {
424427
if (getValue() == i->getDefaultResult())
425-
return OperandOwnership::ForwardingBorrow;
428+
return OperandOwnership::GuaranteedForwarding;
426429

427430
for (unsigned idx = 0, endIdx = i->getNumCases(); idx < endIdx; ++idx) {
428431
SILValue casevalue;
429432
SILValue result;
430433
std::tie(casevalue, result) = i->getCase(idx);
431434

432435
if (getValue() == casevalue) {
433-
return OperandOwnership::ForwardingBorrow;
436+
return OperandOwnership::GuaranteedForwarding;
434437
}
435438
}
436439
return OperandOwnership::TrivialUse;
@@ -440,10 +443,10 @@ OperandOwnership OperandOwnershipClassifier::visitBranchInst(BranchInst *bi) {
440443
ValueOwnershipKind destBlockArgOwnershipKind =
441444
bi->getDestBB()->getArgument(getOperandIndex())->getOwnershipKind();
442445

443-
// FIXME: remove this special case once all aggregate operations behave just
444-
// like phis.
445446
if (destBlockArgOwnershipKind == OwnershipKind::Guaranteed) {
446-
return OperandOwnership::Reborrow;
447+
return isGuaranteedForwardingPhi(getValue())
448+
? OperandOwnership::GuaranteedForwardingPhi
449+
: OperandOwnership::Reborrow;
447450
}
448451
return destBlockArgOwnershipKind.getForwardingOperandOwnership(
449452
/*allowUnowned*/true);

lib/SIL/IR/SILArgument.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,8 @@ bool SILPhiArgument::visitTransitiveIncomingPhiOperands(
240240
argument->getIncomingPhiOperands(operands);
241241

242242
for (auto *operand : operands) {
243-
SILPhiArgument *forwarded;
244-
if ((forwarded = dyn_cast<SILPhiArgument>(operand->get())) &&
245-
forwarded->isPhi()) {
243+
SILPhiArgument *forwarded = dyn_cast<SILPhiArgument>(operand->get());
244+
if (forwarded && forwarded->isPhi()) {
246245
worklist.insert(forwarded);
247246
}
248247
if (!visitor(argument, operand))

lib/SIL/IR/SILValue.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,8 +430,10 @@ StringRef OperandOwnership::asString() const {
430430
return "forwarding-consume";
431431
case OperandOwnership::InteriorPointer:
432432
return "interior-pointer";
433-
case OperandOwnership::ForwardingBorrow:
434-
return "forwarding-borrow";
433+
case OperandOwnership::GuaranteedForwarding:
434+
return "guaranteed-forwarding";
435+
case OperandOwnership::GuaranteedForwardingPhi:
436+
return "guaranteed-forwarding-phi";
435437
case OperandOwnership::EndBorrow:
436438
return "end-borrow";
437439
case OperandOwnership::Reborrow:

0 commit comments

Comments
 (0)