Skip to content

Commit 6d0a325

Browse files
authored
Merge pull request #62454 from meg-gupta/guaranteedforwardingphiverify
Update guaranteed forwarding phi apis and verification
2 parents 57eeb18 + 35d45de commit 6d0a325

20 files changed

+213
-219
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -69,50 +69,58 @@ struct BorrowedValue;
6969
// TODO: encapsulate in a ForwardingInstruction abstraction
7070
//===----------------------------------------------------------------------===//
7171

72-
/// Is the opcode that produces \p value capable of forwarding guaranteed
72+
/// Is the opcode that produces \p value capable of forwarding inner guaranteed
7373
/// values?
7474
///
7575
/// This may be true even if the current instance of the instruction is not a
7676
/// GuaranteedForwarding. If true, then the operation may be trivially rewritten
7777
/// with Guaranteed ownership.
78-
bool canOpcodeForwardGuaranteedValues(SILValue value);
78+
bool canOpcodeForwardInnerGuaranteedValues(SILValue value);
7979

80-
/// Is the opcode that consumes \p use capable of forwarding guaranteed values?
80+
/// Is the opcode that consumes \p use capable of forwarding inner guaranteed
81+
/// values?
8182
///
8283
/// This may be true even if \p use is not a GuaranteedForwarding. If true, then
8384
/// the operation may be trivially rewritten with Guaranteed ownership.
84-
bool canOpcodeForwardGuaranteedValues(Operand *use);
85+
bool canOpcodeForwardInnerGuaranteedValues(Operand *use);
8586

8687
// This is the use-def equivalent of use->getOperandOwnership() ==
8788
// OperandOwnership::GuaranteedForwarding.
8889
inline bool isGuaranteedForwarding(SILValue value) {
89-
assert(value->getOwnershipKind() == OwnershipKind::Guaranteed);
90-
return canOpcodeForwardGuaranteedValues(value);
91-
}
92-
93-
/// Returns true if it is a forwarding phi
94-
inline bool isGuaranteedForwardingPhi(SILValue value) {
9590
if (value->getOwnershipKind() != OwnershipKind::Guaranteed) {
9691
return false;
9792
}
98-
if (isa<BeginBorrowInst>(value) || isa<LoadBorrowInst>(value)) {
99-
return false;
93+
// NOTE: canOpcodeForwardInnerGuaranteedValues returns true for transformation
94+
// terminator results.
95+
if (canOpcodeForwardInnerGuaranteedValues(value) ||
96+
isa<SILFunctionArgument>(value)) {
97+
return true;
10098
}
99+
// If not a phi, return false
101100
auto *phi = dyn_cast<SILPhiArgument>(value);
102101
if (!phi || !phi->isPhi()) {
103-
return true;
102+
return false;
104103
}
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-
104+
// For a phi, if we find GuaranteedForwarding phi operand on any incoming
105+
// path, we return true. Additional verification is added to ensure
106+
// GuaranteedForwarding phi operands are found on zero or all paths in the
107+
// OwnershipVerifier.
108+
bool isGuaranteedForwardingPhi = false;
109+
phi->visitTransitiveIncomingPhiOperands([&](auto *, auto *op) -> bool {
110+
auto opValue = op->get();
111+
assert(opValue->getOwnershipKind().isCompatibleWith(
112+
OwnershipKind::Guaranteed));
113+
if (canOpcodeForwardInnerGuaranteedValues(opValue) ||
114+
isa<SILFunctionArgument>(opValue)) {
115+
isGuaranteedForwardingPhi = true;
116+
return false;
117+
}
118+
auto *phi = dyn_cast<SILPhiArgument>(opValue);
119+
if (!phi || !phi->isPhi()) {
120+
return false;
121+
}
122+
return true;
123+
});
116124
return isGuaranteedForwardingPhi;
117125
}
118126

@@ -527,7 +535,7 @@ class BorrowedValueKind {
527535
})) {
528536
return Kind::Invalid;
529537
}
530-
if (isGuaranteedForwardingPhi(value)) {
538+
if (isGuaranteedForwarding(value)) {
531539
return Kind::Invalid;
532540
}
533541
return Kind::Phi;

include/swift/SIL/SILValue.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -825,8 +825,6 @@ struct OperandOwnership {
825825
/// borrow scope.
826826
/// (tuple_extract, struct_extract, cast, switch)
827827
GuaranteedForwarding,
828-
/// A GuaranteedForwarding value passed as a phi operand.
829-
GuaranteedForwardingPhi,
830828
/// End Borrow. End the borrow scope opened directly by the operand.
831829
/// The operand must be a begin_borrow, begin_apply, or function argument.
832830
/// (end_borrow, end_apply)
@@ -919,7 +917,6 @@ inline OwnershipConstraint OperandOwnership::getOwnershipConstraint() {
919917
return {OwnershipKind::Owned, UseLifetimeConstraint::LifetimeEnding};
920918
case OperandOwnership::InteriorPointer:
921919
case OperandOwnership::GuaranteedForwarding:
922-
case OperandOwnership::GuaranteedForwardingPhi:
923920
return {OwnershipKind::Guaranteed,
924921
UseLifetimeConstraint::NonLifetimeEnding};
925922
case OperandOwnership::EndBorrow:
@@ -948,7 +945,6 @@ inline bool canAcceptUnownedValue(OperandOwnership operandOwnership) {
948945
case OperandOwnership::ForwardingConsume:
949946
case OperandOwnership::InteriorPointer:
950947
case OperandOwnership::GuaranteedForwarding:
951-
case OperandOwnership::GuaranteedForwardingPhi:
952948
case OperandOwnership::EndBorrow:
953949
case OperandOwnership::Reborrow:
954950
return false;

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ 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-
}
3330
return true;
3431
}
3532

@@ -430,8 +427,8 @@ OperandOwnership OperandOwnershipClassifier::visitBranchInst(BranchInst *bi) {
430427
bi->getDestBB()->getArgument(getOperandIndex())->getOwnershipKind();
431428

432429
if (destBlockArgOwnershipKind == OwnershipKind::Guaranteed) {
433-
return isGuaranteedForwardingPhi(getValue())
434-
? OperandOwnership::GuaranteedForwardingPhi
430+
return isGuaranteedForwarding(getValue())
431+
? OperandOwnership::GuaranteedForwarding
435432
: OperandOwnership::Reborrow;
436433
}
437434
return destBlockArgOwnershipKind.getForwardingOperandOwnership(

lib/SIL/IR/SILValue.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,6 @@ StringRef OperandOwnership::asString() const {
441441
return "interior-pointer";
442442
case OperandOwnership::GuaranteedForwarding:
443443
return "guaranteed-forwarding";
444-
case OperandOwnership::GuaranteedForwardingPhi:
445-
return "guaranteed-forwarding-phi";
446444
case OperandOwnership::EndBorrow:
447445
return "end-borrow";
448446
case OperandOwnership::Reborrow:

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 70 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ bool swift::hasPointerEscape(BorrowedValue value) {
5353
case OperandOwnership::InteriorPointer:
5454
case OperandOwnership::BitwiseEscape:
5555
break;
56-
57-
case OperandOwnership::GuaranteedForwardingPhi:
5856
case OperandOwnership::Reborrow: {
5957
SILArgument *phi = cast<BranchInst>(op->getUser())
6058
->getDestBB()
@@ -84,17 +82,23 @@ bool swift::hasPointerEscape(BorrowedValue value) {
8482
return false;
8583
}
8684

87-
bool swift::canOpcodeForwardGuaranteedValues(SILValue value) {
88-
if (auto *inst = value->getDefiningInstructionOrTerminator()) {
89-
if (auto *mixin = OwnershipForwardingMixin::get(inst)) {
85+
bool swift::canOpcodeForwardInnerGuaranteedValues(SILValue value) {
86+
// If we have an argument from a transforming terminator, we can forward
87+
// guaranteed.
88+
if (auto *arg = dyn_cast<SILArgument>(value))
89+
if (auto *ti = arg->getSingleTerminator())
90+
if (ti->mayHaveTerminatorResult())
91+
return OwnershipForwardingMixin::get(ti)->preservesOwnership();
92+
93+
if (auto *inst = value->getDefiningInstruction())
94+
if (auto *mixin = OwnershipForwardingMixin::get(inst))
9095
return mixin->preservesOwnership() &&
91-
!isa<OwnedFirstArgForwardingSingleValueInst>(inst);
92-
}
93-
}
96+
!isa<OwnedFirstArgForwardingSingleValueInst>(inst);
97+
9498
return false;
9599
}
96100

97-
bool swift::canOpcodeForwardGuaranteedValues(Operand *use) {
101+
bool swift::canOpcodeForwardInnerGuaranteedValues(Operand *use) {
98102
if (auto *mixin = OwnershipForwardingMixin::get(use->getUser()))
99103
return mixin->preservesOwnership() &&
100104
!isa<OwnedFirstArgForwardingSingleValueInst>(use->getUser());
@@ -213,6 +217,11 @@ bool swift::findInnerTransitiveGuaranteedUses(
213217
// Do not include transitive uses with 'none' ownership
214218
if (result->getOwnershipKind() == OwnershipKind::None)
215219
return true;
220+
if (auto *phi = SILArgument::asPhi(result)) {
221+
leafUse(use);
222+
foundPointerEscape = true;
223+
return true;
224+
}
216225
for (auto *resultUse : result->getUses()) {
217226
if (resultUse->getOperandOwnership() != OperandOwnership::NonUse) {
218227
nonLeaf = true;
@@ -228,11 +237,6 @@ bool swift::findInnerTransitiveGuaranteedUses(
228237
}
229238
break;
230239
}
231-
case OperandOwnership::GuaranteedForwardingPhi: {
232-
leafUse(use);
233-
foundPointerEscape = true;
234-
break;
235-
}
236240
case OperandOwnership::Borrow:
237241
// FIXME: Use visitExtendedScopeEndingUses and audit all clients to handle
238242
// reborrows.
@@ -330,17 +334,6 @@ bool swift::findExtendedUsesOfSimpleBorrowedValue(
330334
}
331335
recordUse(use);
332336
break;
333-
// \p borrowedValue will dominate this GuaranteedForwardingPhi, because we
334-
// return false in the case of Reborrow.
335-
case OperandOwnership::GuaranteedForwardingPhi: {
336-
SILArgument *phi = PhiOperand(use).getValue();
337-
for (auto *use : phi->getUses()) {
338-
if (use->getOperandOwnership() != OperandOwnership::NonUse)
339-
worklist.insert(use);
340-
}
341-
recordUse(use);
342-
break;
343-
}
344337
case OperandOwnership::GuaranteedForwarding: {
345338
ForwardingOperand(use).visitForwardedValues([&](SILValue result) {
346339
// Do not include transitive uses with 'none' ownership
@@ -413,15 +406,12 @@ bool swift::visitGuaranteedForwardingPhisForSSAValue(
413406
// GuaranteedForwardingPhi uses.
414407
for (auto *use : value->getUses()) {
415408
if (use->getOperandOwnership() == OperandOwnership::GuaranteedForwarding) {
416-
guaranteedForwardingOps.insert(use);
417-
continue;
418-
}
419-
if (use->getOperandOwnership() ==
420-
OperandOwnership::GuaranteedForwardingPhi) {
421-
if (!visitor(use)) {
422-
return false;
409+
if (PhiOperand(use)) {
410+
if (!visitor(use)) {
411+
return false;
412+
}
423413
}
424-
continue;
414+
guaranteedForwardingOps.insert(use);
425415
}
426416
}
427417

@@ -431,15 +421,12 @@ bool swift::visitGuaranteedForwardingPhisForSSAValue(
431421
for (auto *valUse : val->getUses()) {
432422
if (valUse->getOperandOwnership() ==
433423
OperandOwnership::GuaranteedForwarding) {
434-
guaranteedForwardingOps.insert(valUse);
435-
continue;
436-
}
437-
if (valUse->getOperandOwnership() ==
438-
OperandOwnership::GuaranteedForwardingPhi) {
439-
if (!visitor(valUse)) {
440-
return false;
424+
if (PhiOperand(valUse)) {
425+
if (!visitor(valUse)) {
426+
return false;
427+
}
441428
}
442-
continue;
429+
guaranteedForwardingOps.insert(valUse);
443430
}
444431
}
445432
}
@@ -1208,11 +1195,12 @@ bool swift::getAllBorrowIntroducingValues(SILValue inputValue,
12081195
if (inputValue->getOwnershipKind() != OwnershipKind::Guaranteed)
12091196
return false;
12101197

1211-
SmallVector<SILValue, 32> worklist;
1212-
worklist.emplace_back(inputValue);
1198+
SmallSetVector<SILValue, 32> worklist;
1199+
worklist.insert(inputValue);
12131200

1214-
while (!worklist.empty()) {
1215-
SILValue value = worklist.pop_back_val();
1201+
// worklist grows in this loop.
1202+
for (unsigned idx = 0; idx < worklist.size(); idx++) {
1203+
SILValue value = worklist[idx];
12161204

12171205
// First check if v is an introducer. If so, stash it and continue.
12181206
if (auto scopeIntroducer = BorrowedValue(value)) {
@@ -1230,11 +1218,26 @@ bool swift::getAllBorrowIntroducingValues(SILValue inputValue,
12301218
// Otherwise if v is an ownership forwarding value, add its defining
12311219
// instruction
12321220
if (isGuaranteedForwarding(value)) {
1233-
if (auto *i = value->getDefiningInstructionOrTerminator()) {
1234-
llvm::copy(i->getNonTypeDependentOperandValues(),
1235-
std::back_inserter(worklist));
1221+
if (auto *i = value->getDefiningInstruction()) {
1222+
for (SILValue opValue : i->getNonTypeDependentOperandValues()) {
1223+
worklist.insert(opValue);
1224+
}
12361225
continue;
12371226
}
1227+
1228+
// Otherwise, we should have a block argument that is defined by a single
1229+
// predecessor terminator.
1230+
auto *arg = cast<SILPhiArgument>(value);
1231+
if (arg->isTerminatorResult()) {
1232+
if (auto *forwardedOper = arg->forwardedTerminatorResultOperand()) {
1233+
worklist.insert(forwardedOper->get());
1234+
continue;
1235+
}
1236+
}
1237+
arg->visitIncomingPhiOperands([&](auto *operand) {
1238+
worklist.insert(operand->get());
1239+
return true;
1240+
});
12381241
}
12391242

12401243
// Otherwise, this is an introducer we do not understand. Bail and return
@@ -1373,31 +1376,16 @@ ForwardingOperand::ForwardingOperand(Operand *use) {
13731376
if (use->isTypeDependent())
13741377
return;
13751378

1376-
if (!OwnershipForwardingMixin::isa(use->getUser())) {
1377-
return;
1378-
}
1379-
#ifndef NDEBUG
13801379
switch (use->getOperandOwnership()) {
13811380
case OperandOwnership::ForwardingUnowned:
13821381
case OperandOwnership::ForwardingConsume:
13831382
case OperandOwnership::GuaranteedForwarding:
1383+
this->use = use;
13841384
break;
1385-
case OperandOwnership::NonUse:
1386-
case OperandOwnership::TrivialUse:
1387-
case OperandOwnership::InstantaneousUse:
1388-
case OperandOwnership::UnownedInstantaneousUse:
1389-
case OperandOwnership::PointerEscape:
1390-
case OperandOwnership::BitwiseEscape:
1391-
case OperandOwnership::Borrow:
1392-
case OperandOwnership::DestroyingConsume:
1393-
case OperandOwnership::InteriorPointer:
1394-
case OperandOwnership::GuaranteedForwardingPhi:
1395-
case OperandOwnership::EndBorrow:
1396-
case OperandOwnership::Reborrow:
1397-
llvm_unreachable("this isn't the operand being forwarding!");
1385+
default:
1386+
this->use = nullptr;
1387+
return;
13981388
}
1399-
#endif
1400-
this->use = use;
14011389
}
14021390

14031391
ValueOwnershipKind ForwardingOperand::getForwardingOwnershipKind() const {
@@ -1603,15 +1591,22 @@ bool ForwardingOperand::visitForwardedValues(
16031591
// "transforming terminators"... We know that this means that we should at
16041592
// most have a single phi argument.
16051593
auto *ti = cast<TermInst>(user);
1606-
return llvm::all_of(ti->getSuccessorBlocks(), [&](SILBasicBlock *succBlock) {
1607-
// If we do not have any arguments, then continue.
1608-
if (succBlock->args_empty())
1609-
return true;
1594+
if (ti->mayHaveTerminatorResult()) {
1595+
return llvm::all_of(
1596+
ti->getSuccessorBlocks(), [&](SILBasicBlock *succBlock) {
1597+
// If we do not have any arguments, then continue.
1598+
if (succBlock->args_empty())
1599+
return true;
16101600

1611-
auto args = succBlock->getSILPhiArguments();
1612-
assert(args.size() == 1 && "Transforming terminator with multiple args?!");
1613-
return visitor(args[0]);
1614-
});
1601+
auto args = succBlock->getSILPhiArguments();
1602+
assert(args.size() == 1 &&
1603+
"Transforming terminator with multiple args?!");
1604+
return visitor(args[0]);
1605+
});
1606+
}
1607+
1608+
auto *succArg = PhiOperand(use).getValue();
1609+
return visitor(succArg);
16151610
}
16161611

16171612
void swift::visitExtendedReborrowPhiBaseValuePairs(

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,6 @@ PrunedLiveRange<LivenessWithDefs>::updateForDef(SILValue def) {
318318
updateForUse(use->getUser(), /*lifetimeEnding*/false);
319319
break;
320320
}
321-
case OperandOwnership::GuaranteedForwardingPhi: {
322-
updateForDef(PhiOperand(use).getValue());
323-
break;
324-
}
325321
default:
326322
updateForUse(use->getUser(), use->isLifetimeEnding());
327323
break;

0 commit comments

Comments
 (0)