Skip to content

Commit d16c745

Browse files
committed
[SIL] Add hasPointerEscape(SILValue).
There is a preexisting function with this name that takes a BorrowedValue. The new function calls that preexisting function if a BorrowedValue can be constructed from the SILValue. Otherwise, it looks for direct uses of the value which qualify as "pointer escapes".
1 parent f284e72 commit d16c745

File tree

4 files changed

+106
-0
lines changed

4 files changed

+106
-0
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ inline bool isForwardingConsume(SILValue value) {
122122

123123
bool hasPointerEscape(BorrowedValue value);
124124

125+
/// Whether the specified OSSA-lifetime introducer has a pointer escape.
126+
///
127+
/// precondition: \p value introduces an OSSA-lifetime, either a BorrowedValue
128+
/// can be constructed from it or it's an owned value
129+
bool hasPointerEscape(SILValue value);
130+
125131
/// Find leaf "use points" of \p guaranteedValue that determine its lifetime
126132
/// requirement. Return true if no PointerEscape use was found.
127133
///

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,44 @@ bool swift::hasPointerEscape(BorrowedValue value) {
8383
return false;
8484
}
8585

86+
bool swift::hasPointerEscape(SILValue original) {
87+
if (auto borrowedValue = BorrowedValue(original)) {
88+
return hasPointerEscape(borrowedValue);
89+
}
90+
assert(original->getOwnershipKind() == OwnershipKind::Owned);
91+
92+
ValueWorklist worklist(original->getFunction());
93+
worklist.push(original);
94+
if (auto *phi = SILArgument::asPhi(original)) {
95+
phi->visitTransitiveIncomingPhiOperands([&](auto *phi, auto *operand) {
96+
worklist.pushIfNotVisited(operand->get());
97+
return true;
98+
});
99+
}
100+
while (auto value = worklist.popAndForget()) {
101+
for (auto use : value->getUses()) {
102+
switch (use->getOperandOwnership()) {
103+
case OperandOwnership::PointerEscape:
104+
case OperandOwnership::ForwardingUnowned:
105+
return true;
106+
case OperandOwnership::ForwardingConsume: {
107+
SILArgument *phi = dyn_cast<BranchInst>(use->getUser())
108+
->getDestBB()
109+
->getArgument(use->getOperandNumber());
110+
if (!phi) {
111+
break;
112+
}
113+
worklist.pushIfNotVisited(phi);
114+
break;
115+
}
116+
default:
117+
break;
118+
}
119+
}
120+
}
121+
return false;
122+
}
123+
86124
bool swift::canOpcodeForwardInnerGuaranteedValues(SILValue value) {
87125
// If we have an argument from a transforming terminator, we can forward
88126
// guaranteed.

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#include "swift/SIL/MemAccessUtils.h"
7272
#include "swift/SIL/OSSALifetimeCompletion.h"
7373
#include "swift/SIL/OwnershipLiveness.h"
74+
#include "swift/SIL/OwnershipUtils.h"
7475
#include "swift/SIL/PrunedLiveness.h"
7576
#include "swift/SIL/SILArgumentArrayRef.h"
7677
#include "swift/SIL/SILBasicBlock.h"
@@ -267,6 +268,22 @@ struct TestSpecificationTest : UnitTest {
267268
}
268269
};
269270

271+
// Arguments:
272+
// - value: the value to check for escaping
273+
// Dumps:
274+
// - the value
275+
// - whether it has a pointer escape
276+
struct OwnershipUtilsHasPointerEscape : UnitTest {
277+
OwnershipUtilsHasPointerEscape(UnitTestRunner *pass) : UnitTest(pass) {}
278+
void invoke(Arguments &arguments) override {
279+
auto value = arguments.takeValue();
280+
auto has = hasPointerEscape(value);
281+
value->print(llvm::errs());
282+
auto *boolString = has ? "true" : "false";
283+
llvm::errs() << boolString << "\n";
284+
}
285+
};
286+
270287
//===----------------------------------------------------------------------===//
271288
// MARK: OSSA Lifetime Unit Tests
272289
//===----------------------------------------------------------------------===//
@@ -789,6 +806,7 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) {
789806
ADD_UNIT_TEST_SUBCLASS("find-borrow-introducers", FindBorrowIntroducers)
790807
ADD_UNIT_TEST_SUBCLASS("find-enclosing-defs", FindEnclosingDefsTest)
791808
ADD_UNIT_TEST_SUBCLASS("function-get-self-argument-index", FunctionGetSelfArgumentIndex)
809+
ADD_UNIT_TEST_SUBCLASS("has-pointer-escape", OwnershipUtilsHasPointerEscape)
792810
ADD_UNIT_TEST_SUBCLASS("interior-liveness", InteriorLivenessTest)
793811
ADD_UNIT_TEST_SUBCLASS("is-deinit-barrier", IsDeinitBarrierTest)
794812
ADD_UNIT_TEST_SUBCLASS("is-lexical", IsLexicalTest)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %target-sil-opt -unit-test-runner %s -o /dev/null 2>&1 | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
7+
class C {}
8+
9+
sil @getOwned : $@convention(thin) () -> (@owned C)
10+
11+
sil @borrow : $@convention(thin) (@guaranteed C) -> ()
12+
13+
sil @useUnmanaged : $@convention(thin) (@sil_unmanaged C) -> ()
14+
15+
sil [ossa] @test_escape_of_phi_transitive_incoming_value : $@convention(thin) () -> () {
16+
entry:
17+
%getOwned = function_ref @getOwned : $@convention(thin) () -> (@owned C)
18+
%useUnmanaged = function_ref @useUnmanaged : $@convention(thin) (@sil_unmanaged C) -> ()
19+
cond_br undef, left, right
20+
left:
21+
cond_br undef, left_left, left_right
22+
left_left:
23+
%llinstance = apply %getOwned() : $@convention(thin) () -> (@owned C)
24+
br left_bottom(%llinstance : $C)
25+
left_right:
26+
%lrinstance = apply %getOwned() : $@convention(thin) () -> (@owned C)
27+
%escape = ref_to_unmanaged %lrinstance : $C to $@sil_unmanaged C
28+
apply %useUnmanaged(%escape) : $@convention(thin) (@sil_unmanaged C) -> ()
29+
br left_bottom(%lrinstance : $C)
30+
left_bottom(%linstance : @owned $C):
31+
br exit(%linstance : $C)
32+
right:
33+
%rinstance = apply %getOwned() : $@convention(thin) () -> (@owned C)
34+
br exit(%rinstance : $C)
35+
exit(%instance : @owned $C):
36+
// CHECK-LABEL: begin running test {{[0-9]+}} of {{[0-9]+}} on test_escape_of_phi_transitive_incoming_value: has-pointer-escape
37+
// CHECK: %14 = argument of bb6 : $C
38+
// CHECK: true
39+
// CHECK-LABEL: end running test {{[0-9]+}} of {{[0-9]+}} on test_escape_of_phi_transitive_incoming_value: has-pointer-escape with
40+
test_specification "has-pointer-escape @block.argument"
41+
destroy_value %instance : $C
42+
%retval = tuple ()
43+
return %retval : $()
44+
}

0 commit comments

Comments
 (0)