Skip to content

Commit b105639

Browse files
committed
Update isGuaranteedForwarding api and delete isGuaranteedForwardingPhi api
1 parent e5d2475 commit b105639

File tree

10 files changed

+98
-137
lines changed

10 files changed

+98
-137
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;

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 4 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,7 +427,7 @@ OperandOwnership OperandOwnershipClassifier::visitBranchInst(BranchInst *bi) {
430427
bi->getDestBB()->getArgument(getOperandIndex())->getOwnershipKind();
431428

432429
if (destBlockArgOwnershipKind == OwnershipKind::Guaranteed) {
433-
return isGuaranteedForwardingPhi(getValue())
430+
return isGuaranteedForwarding(getValue())
434431
? OperandOwnership::GuaranteedForwardingPhi
435432
: OperandOwnership::Reborrow;
436433
}

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,23 @@ bool swift::hasPointerEscape(BorrowedValue value) {
8484
return false;
8585
}
8686

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

97-
bool swift::canOpcodeForwardGuaranteedValues(Operand *use) {
103+
bool swift::canOpcodeForwardInnerGuaranteedValues(Operand *use) {
98104
if (auto *mixin = OwnershipForwardingMixin::get(use->getUser()))
99105
return mixin->preservesOwnership() &&
100106
!isa<OwnedFirstArgForwardingSingleValueInst>(use->getUser());
@@ -1208,11 +1214,12 @@ bool swift::getAllBorrowIntroducingValues(SILValue inputValue,
12081214
if (inputValue->getOwnershipKind() != OwnershipKind::Guaranteed)
12091215
return false;
12101216

1211-
SmallVector<SILValue, 32> worklist;
1212-
worklist.emplace_back(inputValue);
1217+
SmallSetVector<SILValue, 32> worklist;
1218+
worklist.insert(inputValue);
12131219

1214-
while (!worklist.empty()) {
1215-
SILValue value = worklist.pop_back_val();
1220+
// worklist grows in this loop.
1221+
for (unsigned idx = 0; idx < worklist.size(); idx++) {
1222+
SILValue value = worklist[idx];
12161223

12171224
// First check if v is an introducer. If so, stash it and continue.
12181225
if (auto scopeIntroducer = BorrowedValue(value)) {
@@ -1230,11 +1237,26 @@ bool swift::getAllBorrowIntroducingValues(SILValue inputValue,
12301237
// Otherwise if v is an ownership forwarding value, add its defining
12311238
// instruction
12321239
if (isGuaranteedForwarding(value)) {
1233-
if (auto *i = value->getDefiningInstructionOrTerminator()) {
1234-
llvm::copy(i->getNonTypeDependentOperandValues(),
1235-
std::back_inserter(worklist));
1240+
if (auto *i = value->getDefiningInstruction()) {
1241+
for (SILValue opValue : i->getNonTypeDependentOperandValues()) {
1242+
worklist.insert(opValue);
1243+
}
12361244
continue;
12371245
}
1246+
1247+
// Otherwise, we should have a block argument that is defined by a single
1248+
// predecessor terminator.
1249+
auto *arg = cast<SILPhiArgument>(value);
1250+
if (arg->isTerminatorResult()) {
1251+
if (auto *forwardedOper = arg->forwardedTerminatorResultOperand()) {
1252+
worklist.insert(forwardedOper->get());
1253+
continue;
1254+
}
1255+
}
1256+
arg->visitIncomingPhiOperands([&](auto *operand) {
1257+
worklist.insert(operand->get());
1258+
return true;
1259+
});
12381260
}
12391261

12401262
// Otherwise, this is an introducer we do not understand. Bail and return

lib/SIL/Verifier/SILOwnershipVerifier.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ bool SILValueOwnershipChecker::gatherUsers(
280280
// this value forwards guaranteed ownership. In such a case, we are going to
281281
// validate it as part of the borrow introducer from which the forwarding
282282
// value originates. So we can just return true and continue.
283-
if (isGuaranteedForwarding(value))
283+
if (canOpcodeForwardInnerGuaranteedValues(value))
284284
return true;
285285

286286
// Ok, we have some sort of borrow introducer. We need to recursively validate
@@ -554,10 +554,6 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses(
554554
if (isGuaranteedForwarding(value)) {
555555
return true;
556556
}
557-
auto *phi = dyn_cast<SILPhiArgument>(value);
558-
if (phi && isGuaranteedForwardingPhi(phi)) {
559-
return true;
560-
}
561557
}
562558

563559
// If we have an unowned value, then again there is nothing left to do.
@@ -675,8 +671,7 @@ bool SILValueOwnershipChecker::checkUses() {
675671
// Check if we are an instruction that forwards guaranteed
676672
// ownership. In such a case, we are a subobject projection. We should not
677673
// have any lifetime ending uses.
678-
if (value->getOwnershipKind() == OwnershipKind::Guaranteed &&
679-
isGuaranteedForwarding(value)) {
674+
if (isGuaranteedForwarding(value)) {
680675
if (!isSubobjectProjectionWithLifetimeEndingUses(value,
681676
lifetimeEndingUsers)) {
682677
return false;

lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@ OwnershipLiveRange::OwnershipLiveRange(SILValue value)
6969
// DISCUSSION: For now we do not support forwarding instructions with
7070
// multiple non-trivial arguments since we would need to optimize all of
7171
// the non-trivial arguments at the same time.
72+
//
73+
// NOTE: Today we do not support TermInsts for simplicity... we /could/
74+
// support it though if we need to.
7275
auto *ti = dyn_cast<TermInst>(user);
73-
if ((ti && !ti->forwardedOperand()) ||
74-
!canOpcodeForwardGuaranteedValues(op) ||
76+
if ((ti && !ti->mayHaveTerminatorResult()) ||
77+
!canOpcodeForwardInnerGuaranteedValues(op) ||
7578
1 !=
7679
count_if(user->getNonTypeDependentOperandValues(), [&](SILValue v) {
7780
return v->getOwnershipKind() == OwnershipKind::Owned;

test/SIL/OwnershipVerifier/arguments.sil

Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -54,40 +54,13 @@ bb1(%2 : @guaranteed $Builtin.NativeObject):
5454

5555
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'leak_along_path'
5656
// CHECK: Error! Found a leak due to a consuming post-dominance failure!
57-
// CHECK: Value: %2 = argument of bb1 : $Builtin.NativeObject
57+
// CHECK: Value: %3 = argument of bb1 : $Builtin.NativeObject
5858
// CHECK: Post Dominating Failure Blocks:
5959
// CHECK: bb3
6060
// CHECK: Error#: 0. End Error in Function: 'leak_along_path'
6161
//
6262
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'leak_along_path'
6363
sil [ossa] @leak_along_path : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
64-
bb0(%0 : @guaranteed $Builtin.NativeObject):
65-
br bb1(%0 : $Builtin.NativeObject)
66-
67-
bb1(%1 : @guaranteed $Builtin.NativeObject):
68-
cond_br undef, bb2, bb3
69-
70-
bb2:
71-
end_borrow %1 : $Builtin.NativeObject
72-
br bb4
73-
74-
bb3:
75-
br bb4
76-
77-
bb4:
78-
%9999 = tuple()
79-
return %9999 : $()
80-
}
81-
82-
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'leak_along_path_2'
83-
// CHECK: Error! Found a leak due to a consuming post-dominance failure!
84-
// CHECK: Value: %3 = argument of bb1 : $Builtin.NativeObject
85-
// CHECK: Post Dominating Failure Blocks:
86-
// CHECK: bb3
87-
// CHECK: Error#: 0. End Error in Function: 'leak_along_path_2'
88-
//
89-
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'leak_along_path_2'
90-
sil [ossa] @leak_along_path_2 : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
9164
bb0(%0 : @guaranteed $Builtin.NativeObject):
9265
%1 = begin_borrow %0 : $Builtin.NativeObject
9366
br bb1(%1 : $Builtin.NativeObject)
@@ -109,53 +82,16 @@ bb4:
10982

11083
// Make sure that we only flag the subargument leak and not the parent
11184
// argument. Also check for over consuming due to phi nodes.
112-
//
85+
11386
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'leak_along_subarg_path'
11487
// CHECK: Error! Found a leak due to a consuming post-dominance failure!
115-
// CHECK: Value: %6 = argument of bb4 : $Builtin.NativeObject
88+
// CHECK: Value: %7 = argument of bb3 : $Builtin.NativeObject
11689
// CHECK: Post Dominating Failure Blocks:
11790
// CHECK: bb6
11891
// CHECK: Error#: 0. End Error in Function: 'leak_along_subarg_path'
11992
//
12093
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'leak_along_subarg_path'
12194
sil [ossa] @leak_along_subarg_path : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
122-
bb0(%0 : @guaranteed $Builtin.NativeObject):
123-
br bb1(%0 : $Builtin.NativeObject)
124-
125-
bb1(%1 : @guaranteed $Builtin.NativeObject):
126-
cond_br undef, bb2, bb3
127-
128-
bb2:
129-
br bb7
130-
131-
bb3:
132-
br bb4(%1 : $Builtin.NativeObject)
133-
134-
bb4(%2 : @guaranteed $Builtin.NativeObject):
135-
cond_br undef, bb5, bb6
136-
137-
bb5:
138-
end_borrow %2 : $Builtin.NativeObject
139-
br bb7
140-
141-
bb6:
142-
br bb7
143-
144-
bb7:
145-
end_borrow %1 : $Builtin.NativeObject
146-
%9999 = tuple()
147-
return %9999 : $()
148-
}
149-
150-
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'leak_along_subarg_path_2'
151-
// CHECK: Error! Found a leak due to a consuming post-dominance failure!
152-
// CHECK: Value: %7 = argument of bb3 : $Builtin.NativeObject
153-
// CHECK: Post Dominating Failure Blocks:
154-
// CHECK: bb6
155-
// CHECK: Error#: 0. End Error in Function: 'leak_along_subarg_path_2'
156-
//
157-
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'leak_along_subarg_path_2'
158-
sil [ossa] @leak_along_subarg_path_2 : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
15995
bb0(%0 : @guaranteed $Builtin.NativeObject):
16096
%1 = begin_borrow %0 : $Builtin.NativeObject
16197
br bb1(%1 : $Builtin.NativeObject)

test/SIL/OwnershipVerifier/use_verifier.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,8 @@ bb1:
12061206

12071207
bb2:
12081208
%5 = struct_extract %1 : $NonTrivialStructWithTrivialField, #NonTrivialStructWithTrivialField.owner
1209-
br bb3(%5 : $Builtin.NativeObject)
1209+
%6 = begin_borrow %5 : $Builtin.NativeObject
1210+
br bb3(%6 : $Builtin.NativeObject)
12101211

12111212
bb3(%7 : @guaranteed $Builtin.NativeObject):
12121213
end_borrow %7 : $Builtin.NativeObject
@@ -1366,7 +1367,6 @@ bb2:
13661367
br bb3(%f2thick : $@callee_owned () -> ())
13671368

13681369
bb3(%fUnknown : @guaranteed $@callee_owned () -> ()):
1369-
end_borrow %fUnknown : $@callee_owned () -> ()
13701370
%9999 = tuple()
13711371
return %9999 : $()
13721372
}

test/SILOptimizer/redundant_phi_elimination_ossa.sil

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,6 @@ bb2:
183183
br bb3(%0 : $FakeOptional<Klass>, %0 : $FakeOptional<Klass>)
184184

185185
bb3(%1 : @guaranteed $FakeOptional<Klass>, %2 : @guaranteed $FakeOptional<Klass>):
186-
end_borrow %1 : $FakeOptional<Klass>
187-
end_borrow %2 : $FakeOptional<Klass>
188186
%res = tuple ()
189187
return %res : $()
190188
}
@@ -195,17 +193,18 @@ bb3(%1 : @guaranteed $FakeOptional<Klass>, %2 : @guaranteed $FakeOptional<Klass>
195193
sil [ossa] @test_redundantguaranteedphiarg2 : $@convention(thin) () -> () {
196194
bb0:
197195
%0 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
196+
%b = begin_borrow %0 : $FakeOptional<Klass>
198197
cond_br undef, bb1, bb2
199198

200199
bb1:
201-
br bb3(%0 : $FakeOptional<Klass>, %0 : $FakeOptional<Klass>)
200+
br bb3(%0 : $FakeOptional<Klass>, %b : $FakeOptional<Klass>)
202201

203202
bb2:
204-
br bb3(%0 : $FakeOptional<Klass>, %0 : $FakeOptional<Klass>)
203+
br bb3(%0 : $FakeOptional<Klass>, %b : $FakeOptional<Klass>)
205204

206205
bb3(%1 : @owned $FakeOptional<Klass>, %2 : @guaranteed $FakeOptional<Klass>):
207-
destroy_value %1 : $FakeOptional<Klass>
208206
end_borrow %2 : $FakeOptional<Klass>
207+
destroy_value %1 : $FakeOptional<Klass>
209208
%res = tuple ()
210209
return %res : $()
211210
}
@@ -216,13 +215,15 @@ bb3(%1 : @owned $FakeOptional<Klass>, %2 : @guaranteed $FakeOptional<Klass>):
216215
sil [ossa] @test_redundantguaranteedphiarg3 : $@convention(thin) () -> () {
217216
bb0:
218217
%0 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
218+
%b1 = begin_borrow %0 : $FakeOptional<Klass>
219+
%b2 = begin_borrow %0 : $FakeOptional<Klass>
219220
cond_br undef, bb1, bb2
220221

221222
bb1:
222-
br bb3(%0 : $FakeOptional<Klass>, %0 : $FakeOptional<Klass>)
223+
br bb3(%b1 : $FakeOptional<Klass>, %b2 : $FakeOptional<Klass>)
223224

224225
bb2:
225-
br bb3(%0 : $FakeOptional<Klass>, %0 : $FakeOptional<Klass>)
226+
br bb3(%b1 : $FakeOptional<Klass>, %b2 : $FakeOptional<Klass>)
226227

227228
bb3(%1 : @guaranteed $FakeOptional<Klass>, %2 : @guaranteed $FakeOptional<Klass>):
228229
cond_br undef, bb4, bb5

0 commit comments

Comments
 (0)