Skip to content

Commit 28df449

Browse files
authored
Merge pull request #66723 from meg-gupta/improvefindpointerescape
Refactor swift::findPointerEscape and handle additional cases
2 parents fd369cd + 6d3b4e0 commit 28df449

File tree

8 files changed

+47
-75
lines changed

8 files changed

+47
-75
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,13 @@ inline bool isForwardingConsume(SILValue value) {
9090
// Ownership Def-Use Utilities
9191
//===----------------------------------------------------------------------===//
9292

93-
bool hasPointerEscape(BorrowedValue value);
93+
bool findPointerEscape(BorrowedValue value);
9494

9595
/// Whether the specified OSSA-lifetime introducer has a pointer escape.
9696
///
9797
/// precondition: \p value introduces an OSSA-lifetime, either a BorrowedValue
9898
/// can be constructed from it or it's an owned value
99-
bool hasPointerEscape(SILValue value);
99+
bool findPointerEscape(SILValue value);
100100

101101
/// Find leaf "use points" of \p guaranteedValue that determine its lifetime
102102
/// requirement. Return true if no PointerEscape use was found.

lib/SIL/Utils/AddressWalker.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,6 @@ AddressUseKind TransitiveAddressWalker::walk(SILValue projectedAddress) && {
2525
// When we exit, set the result to be invalidated so we can't use this again.
2626
SWIFT_DEFER { didInvalidate = true; };
2727

28-
// If the projectedAddress is dead, it is itself a leaf use. Since we don't
29-
// have an operand for it, simply bail. Dead projectedAddress is unexpected.
30-
//
31-
// TODO: store_borrow is currently an InteriorPointer with no uses, so we end
32-
// up bailing. It should be in a dependence scope instead. It's not clear why
33-
// it produces an address at all.
34-
if (projectedAddress->use_empty()) {
35-
return AddressUseKind::PointerEscape;
36-
}
37-
3828
StackList<Operand *> worklist(projectedAddress->getFunction());
3929
SmallPtrSet<Operand *, 32> visitedOperands;
4030

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 39 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,52 @@
2525

2626
using namespace swift;
2727

28-
bool swift::hasPointerEscape(BorrowedValue original) {
29-
ValueWorklist worklist(original->getFunction());
30-
worklist.push(*original);
28+
bool swift::findPointerEscape(SILValue original) {
29+
if (original->getOwnershipKind() != OwnershipKind::Owned &&
30+
original->getOwnershipKind() != OwnershipKind::Guaranteed) {
31+
return false;
32+
}
3133

32-
if (auto *phi = SILArgument::asPhi(*original)) {
34+
ValueWorklist worklist(original->getFunction());
35+
worklist.push(original);
36+
if (auto *phi = SILArgument::asPhi(original)) {
3337
phi->visitTransitiveIncomingPhiOperands([&](auto *phi, auto *operand) {
3438
worklist.pushIfNotVisited(operand->get());
3539
return true;
3640
});
3741
}
3842

3943
while (auto value = worklist.pop()) {
40-
for (auto *op : value->getUses()) {
41-
switch (op->getOperandOwnership()) {
42-
case OperandOwnership::ForwardingUnowned:
44+
for (auto use : value->getUses()) {
45+
switch (use->getOperandOwnership()) {
4346
case OperandOwnership::PointerEscape:
47+
case OperandOwnership::ForwardingUnowned:
4448
return true;
45-
49+
case OperandOwnership::ForwardingConsume: {
50+
auto *branch = dyn_cast<BranchInst>(use->getUser());
51+
if (!branch) {
52+
// Non-phi forwarding consumes end the lifetime of an owned value.
53+
break;
54+
}
55+
auto *phi = branch->getDestBB()->getArgument(use->getOperandNumber());
56+
worklist.pushIfNotVisited(phi);
57+
break;
58+
}
59+
case OperandOwnership::Borrow: {
60+
auto borrowOp = BorrowingOperand(use);
61+
if (auto borrowValue = borrowOp.getBorrowIntroducingUserResult()) {
62+
worklist.pushIfNotVisited(borrowValue.value);
63+
}
64+
break;
65+
}
4666
case OperandOwnership::Reborrow: {
47-
SILArgument *phi = PhiOperand(op).getValue();
67+
SILArgument *phi = PhiOperand(use).getValue();
4868
worklist.pushIfNotVisited(phi);
4969
break;
5070
}
51-
5271
case OperandOwnership::GuaranteedForwarding: {
5372
// This may follow guaranteed phis.
54-
ForwardingOperand(op).visitForwardedValues([&](SILValue result) {
73+
ForwardingOperand(use).visitForwardedValues([&](SILValue result) {
5574
// Do not include transitive uses with 'none' ownership
5675
if (result->getOwnershipKind() == OwnershipKind::None)
5776
return true;
@@ -60,42 +79,11 @@ bool swift::hasPointerEscape(BorrowedValue original) {
6079
});
6180
break;
6281
}
63-
default:
64-
break;
65-
}
66-
}
67-
}
68-
return false;
69-
}
70-
71-
bool swift::hasPointerEscape(SILValue original) {
72-
if (auto borrowedValue = BorrowedValue(original)) {
73-
return hasPointerEscape(borrowedValue);
74-
}
75-
assert(original->getOwnershipKind() == OwnershipKind::Owned);
76-
77-
ValueWorklist worklist(original->getFunction());
78-
worklist.push(original);
79-
if (auto *phi = SILArgument::asPhi(original)) {
80-
phi->visitTransitiveIncomingPhiOperands([&](auto *phi, auto *operand) {
81-
worklist.pushIfNotVisited(operand->get());
82-
return true;
83-
});
84-
}
85-
while (auto value = worklist.pop()) {
86-
for (auto use : value->getUses()) {
87-
switch (use->getOperandOwnership()) {
88-
case OperandOwnership::PointerEscape:
89-
case OperandOwnership::ForwardingUnowned:
90-
return true;
91-
case OperandOwnership::ForwardingConsume: {
92-
auto *branch = dyn_cast<BranchInst>(use->getUser());
93-
if (!branch) {
94-
// Non-phi forwarding consumes end the lifetime of an owned value.
95-
break;
82+
case OperandOwnership::InteriorPointer: {
83+
if (InteriorPointerOperand(use).findTransitiveUses() !=
84+
AddressUseKind::NonEscaping) {
85+
return true;
9686
}
97-
auto *phi = branch->getDestBB()->getArgument(use->getOperandNumber());
98-
worklist.pushIfNotVisited(phi);
9987
break;
10088
}
10189
default:
@@ -2282,27 +2270,27 @@ bool swift::isRedundantMoveValue(MoveValueInst *mvi) {
22822270
//
22832271
// Check this in two ways, one cheaper than the other.
22842272

2285-
// First, avoid calling hasPointerEscape(original).
2273+
// First, avoid calling findPointerEscape(original).
22862274
//
22872275
// If the original value is not a phi (a phi's incoming values might have
22882276
// escaping uses) and its only user is the move, then it doesn't escape. Also
22892277
// if its only user is the move, then its only _consuming_ user is the move.
22902278
auto *singleUser =
22912279
original->getSingleUse() ? original->getSingleUse()->getUser() : nullptr;
22922280
if (mvi == singleUser && !SILArgument::asPhi(original)) {
2293-
assert(!hasPointerEscape(original));
2281+
assert(!findPointerEscape(original));
22942282
assert(original->getSingleConsumingUse()->getUser() == mvi);
22952283
// - !escaping(original)
22962284
// - singleConsumingUser(original) == move
22972285
return true;
22982286
}
22992287

2300-
// Second, call hasPointerEscape(original).
2288+
// Second, call findPointerEscape(original).
23012289
//
23022290
// Explicitly check both
23032291
// - !escaping(original)
23042292
// - singleConsumingUser(original) == move
2305-
auto originalHasEscape = hasPointerEscape(original);
2293+
auto originalHasEscape = findPointerEscape(original);
23062294
auto *singleConsumingUser = original->getSingleConsumingUse()
23072295
? original->getSingleConsumingUse()->getUser()
23082296
: nullptr;
@@ -2311,6 +2299,6 @@ bool swift::isRedundantMoveValue(MoveValueInst *mvi) {
23112299
}
23122300

23132301
// (3) Escaping matches? (Expensive check, saved for last.)
2314-
auto moveHasEscape = hasPointerEscape(mvi);
2302+
auto moveHasEscape = findPointerEscape(mvi);
23152303
return moveHasEscape == originalHasEscape;
23162304
}

lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ static bool tryJoinIfDestroyConsumingUseInSameBlock(
511511
// Check whether the uses considered immediately above are all effectively
512512
// instantaneous uses. Pointer escapes propagate values ways that may not be
513513
// discoverable.
514-
if (hasPointerEscape(operand)) {
514+
if (findPointerEscape(operand)) {
515515
return false;
516516
}
517517

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ void DCE::markLive() {
277277
case SILInstructionKind::DestroyValueInst: {
278278
auto phi = PhiValue(I.getOperand(0));
279279
// Disable DCE of phis which are lexical or may have a pointer escape.
280-
if (phi && (phi->isLexical() || hasPointerEscape(phi))) {
280+
if (phi && (phi->isLexical() || findPointerEscape(phi))) {
281281
markInstructionLive(&I);
282282
}
283283
// The instruction is live only if it's operand value is also live
@@ -287,7 +287,7 @@ void DCE::markLive() {
287287
case SILInstructionKind::EndBorrowInst: {
288288
auto phi = PhiValue(I.getOperand(0));
289289
// If there is a pointer escape or phi is lexical, disable DCE.
290-
if (phi && (hasPointerEscape(phi) || phi->isLexical())) {
290+
if (phi && (findPointerEscape(phi) || phi->isLexical())) {
291291
markInstructionLive(&I);
292292
}
293293
// The instruction is live only if it's operand value is also live

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ struct OwnershipUtilsHasPointerEscape : UnitTest {
281281
OwnershipUtilsHasPointerEscape(UnitTestRunner *pass) : UnitTest(pass) {}
282282
void invoke(Arguments &arguments) override {
283283
auto value = arguments.takeValue();
284-
auto has = hasPointerEscape(value);
284+
auto has = findPointerEscape(value);
285285
value->print(llvm::errs());
286286
auto *boolString = has ? "true" : "false";
287287
llvm::errs() << boolString << "\n";

test/SILOptimizer/copy_propagation_borrow.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ bb0:
501501
%copy1 = copy_value %borrow1 : $C
502502
%borrow2 = begin_borrow %copy1 : $C
503503
%addr = ref_element_addr %borrow2 : $C, #C.a
504+
%ptr = address_to_pointer %addr : $*Int64 to $Builtin.RawPointer
504505
cond_br undef, bb1, bb2
505506
bb1:
506507
// inside use
@@ -1201,4 +1202,3 @@ bb0(%0 : @guaranteed $C):
12011202
%7 = tuple ()
12021203
return %7 : $()
12031204
}
1204-

test/SILOptimizer/liveness_unit.sil

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -222,19 +222,13 @@ bb4(%phi : @owned $C):
222222
return %99 : $()
223223
}
224224

225-
// A dead (ref_element_addr) projection is treated like a pointer
226-
// escape for convenience. Make sure the pointer escape bubbles up
227-
// through the phi and casts.
228-
//
229225
// CHECK-LABEL: testSSADeadRefElementAddr: ssa-liveness
230226
// CHECK: SSA lifetime analysis: %0 = argument of bb0 : $C
231-
// CHECK-NEXT: Incomplete liveness: Escaping address
232227
// CHECK-NEXT: bb0: LiveOut
233228
// CHECK-NEXT: bb2: LiveOut
234229
// CHECK-NEXT: bb3: LiveWithin
235230
// CHECK-NEXT: bb1: LiveOut
236-
// CHECK: last user:
237-
// CHECK-SAME: ref_element_addr %6 : $D, #D.object
231+
// CHECK: ref_element_addr %6 : $D, #D.object
238232
// CHECK-NEXT-LABEL: end running test 1 of 1 on testSSADeadRefElementAddr: ssa-liveness
239233
sil [ossa] @testSSADeadRefElementAddr : $@convention(thin) (@guaranteed C) -> () {
240234
bb0(%0 : @guaranteed $C):

0 commit comments

Comments
 (0)