Skip to content

Commit 7ea4523

Browse files
committed
[SIL] Phi with incoming lexical value is lexical.
Added SILPhiArgument::isLexical. It's true for phis which have an incoming value that's lexical. Dispatch to this member from ValueBase::isLexical.
1 parent 5d4b915 commit 7ea4523

File tree

4 files changed

+340
-0
lines changed

4 files changed

+340
-0
lines changed

include/swift/SIL/SILArgument.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ class SILPhiArgument : public SILArgument {
241241
/// result.
242242
bool isPhi() const;
243243

244+
/// Whether any of the values incoming to this phi are lexical.
245+
bool isLexical() const;
246+
244247
/// Return true if this block argument is a terminator result.
245248
bool isTerminatorResult() const { return !isPhi(); }
246249

lib/SIL/IR/SILValue.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,38 @@ ValueBase::getDefiningInstructionResult() {
115115
return None;
116116
}
117117

118+
bool SILPhiArgument::isLexical() const {
119+
if (!isPhi())
120+
return false;
121+
122+
// FIXME: Cache this on the node.
123+
124+
// Does there exist an incoming value which is lexical?
125+
//
126+
// Invert the condition to "is every incoming value non-lexical?" in order to
127+
// stop visiting incoming values once one lexical value is
128+
// found--visitTransitiveIncomingPhiOperands stops once false is returned
129+
// from it.
130+
auto isEveryIncomingValueNonLexical =
131+
visitTransitiveIncomingPhiOperands([&](auto *, auto *operand) {
132+
auto value = operand->get();
133+
SILPhiArgument *phi = dyn_cast<SILPhiArgument>(value);
134+
if (phi && phi->isPhi()) {
135+
return true;
136+
}
137+
// If this non-phi incoming value is lexical, then there is one at least
138+
// one lexical value incoming to this phi, to it's lexical.
139+
return !value->isLexical();
140+
});
141+
return !isEveryIncomingValueNonLexical;
142+
}
143+
118144
bool ValueBase::isLexical() const {
119145
if (auto *argument = dyn_cast<SILFunctionArgument>(this))
120146
return argument->getLifetime().isLexical();
147+
auto *phi = dyn_cast<SILPhiArgument>(this);
148+
if (phi && phi->isPhi())
149+
return phi->isLexical();
121150
if (auto *bbi = dyn_cast<BeginBorrowInst>(this))
122151
return bbi->isLexical();
123152
if (auto *mvi = dyn_cast<MoveValueInst>(this))

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,22 @@ struct IsDeinitBarrierTest : UnitTest {
434434
}
435435
};
436436

437+
// Arguments:
438+
// - value
439+
// Dumps:
440+
// - value
441+
// - whether it's lexical
442+
struct IsLexicalTest : UnitTest {
443+
IsLexicalTest(UnitTestRunner *pass) : UnitTest(pass) {}
444+
void invoke(Arguments &arguments) override {
445+
auto value = arguments.takeValue();
446+
auto isLexical = value->isLexical();
447+
value->dump();
448+
auto *boolString = isLexical ? "true" : "false";
449+
llvm::errs() << boolString << "\n";
450+
}
451+
};
452+
437453
struct ShrinkBorrowScopeTest : UnitTest {
438454
ShrinkBorrowScopeTest(UnitTestRunner *pass) : UnitTest(pass) {}
439455
void invoke(Arguments &arguments) override {
@@ -759,6 +775,7 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) {
759775
ADD_UNIT_TEST_SUBCLASS("function-get-self-argument-index", FunctionGetSelfArgumentIndex)
760776
ADD_UNIT_TEST_SUBCLASS("interior-liveness", InteriorLivenessTest)
761777
ADD_UNIT_TEST_SUBCLASS("is-deinit-barrier", IsDeinitBarrierTest)
778+
ADD_UNIT_TEST_SUBCLASS("is-lexical", IsLexicalTest)
762779
ADD_UNIT_TEST_SUBCLASS("linear-liveness", LinearLivenessTest)
763780
ADD_UNIT_TEST_SUBCLASS("multidef-liveness", MultiDefLivenessTest)
764781
ADD_UNIT_TEST_SUBCLASS("pruned-liveness-boundary-with-list-of-last-users-insertion-points", PrunedLivenessBoundaryWithListOfLastUsersInsertionPointsTest)

test/SILOptimizer/lexical_unit.sil

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
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 [ossa] @getC : $@convention(thin) () -> (@owned C)
10+
11+
// CHECK-LABEL: begin running test 1 of 1 on phi_direct_no_lexical: is-lexical
12+
// CHECK: argument of bb3
13+
// CHECK: false
14+
// CHECK-LABEL: end running test 1 of 1 on phi_direct_no_lexical: is-lexical
15+
sil [ossa] @phi_direct_no_lexical : $() -> () {
16+
entry:
17+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
18+
cond_br undef, left, right
19+
left:
20+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
21+
br exit(%c1 : $C)
22+
right:
23+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
24+
br exit(%c2 : $C)
25+
exit(%cm : @owned $C):
26+
test_specification "is-lexical @block.argument"
27+
destroy_value %cm : $C
28+
%retval = tuple ()
29+
return %retval : $()
30+
}
31+
32+
// CHECK-LABEL: begin running test 1 of 1 on phi_direct_first_lexical: is-lexical
33+
// CHECK: argument of bb3
34+
// CHECK: true
35+
// CHECK-LABEL: end running test 1 of 1 on phi_direct_first_lexical: is-lexical
36+
sil [ossa] @phi_direct_first_lexical : $() -> () {
37+
entry:
38+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
39+
cond_br undef, left, right
40+
left:
41+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
42+
%m1 = move_value [lexical] %c1 : $C
43+
br exit(%m1 : $C)
44+
right:
45+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
46+
br exit(%c2 : $C)
47+
exit(%cm : @owned $C):
48+
test_specification "is-lexical @block.argument"
49+
destroy_value %cm : $C
50+
%retval = tuple ()
51+
return %retval : $()
52+
}
53+
54+
// CHECK-LABEL: begin running test 1 of 1 on phi_direct_second_lexical: is-lexical
55+
// CHECK: argument of bb3
56+
// CHECK: true
57+
// CHECK-LABEL: end running test 1 of 1 on phi_direct_second_lexical: is-lexical
58+
sil [ossa] @phi_direct_second_lexical : $() -> () {
59+
entry:
60+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
61+
cond_br undef, left, right
62+
left:
63+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
64+
br exit(%c1 : $C)
65+
right:
66+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
67+
%m2 = move_value [lexical] %c2 : $C
68+
br exit(%m2 : $C)
69+
exit(%cm : @owned $C):
70+
test_specification "is-lexical @block.argument"
71+
destroy_value %cm : $C
72+
%retval = tuple ()
73+
return %retval : $()
74+
}
75+
76+
// CHECK-LABEL: begin running test 1 of 1 on phi_direct_both_lexical: is-lexical
77+
// CHECK: argument of bb3
78+
// CHECK: true
79+
// CHECK-LABEL: end running test 1 of 1 on phi_direct_both_lexical: is-lexical
80+
sil [ossa] @phi_direct_both_lexical : $() -> () {
81+
entry:
82+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
83+
cond_br undef, left, right
84+
left:
85+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
86+
%m1 = move_value [lexical] %c1 : $C
87+
br exit(%m1 : $C)
88+
right:
89+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
90+
%m2 = move_value [lexical] %c2 : $C
91+
br exit(%m2 : $C)
92+
exit(%cm : @owned $C):
93+
test_specification "is-lexical @block.argument"
94+
destroy_value %cm : $C
95+
%retval = tuple ()
96+
return %retval : $()
97+
}
98+
99+
// CHECK-LABEL: begin running test 1 of 1 on phi_indirect_0000_lexical: is-lexical
100+
// CHECK: argument of bb9
101+
// CHECK: false
102+
// CHECK-LABEL: end running test 1 of 1 on phi_indirect_0000_lexical: is-lexical
103+
sil [ossa] @phi_indirect_0000_lexical : $() -> () {
104+
entry:
105+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
106+
cond_br undef, lt, rt
107+
108+
lt:
109+
cond_br undef, ll, lr
110+
ll:
111+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
112+
br lb(%c1 : $C)
113+
lr:
114+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
115+
br lb(%c2 : $C)
116+
lb(%cl : @owned $C):
117+
br exit(%cl : $C)
118+
119+
rt:
120+
cond_br undef, rl, rr
121+
rl:
122+
%c3 = apply %getC() : $@convention(thin) () -> (@owned C)
123+
br rb(%c3 : $C)
124+
rr:
125+
%c4 = apply %getC() : $@convention(thin) () -> (@owned C)
126+
br rb(%c4 : $C)
127+
rb(%cr : @owned $C):
128+
br exit(%cr : $C)
129+
130+
exit(%cm : @owned $C):
131+
test_specification "is-lexical @block.argument"
132+
destroy_value %cm : $C
133+
%retval = tuple ()
134+
return %retval : $()
135+
}
136+
137+
// CHECK-LABEL: begin running test 1 of 1 on phi_indirect_1000_lexical: is-lexical
138+
// CHECK: argument of bb9
139+
// CHECK: true
140+
// CHECK-LABEL: end running test 1 of 1 on phi_indirect_1000_lexical: is-lexical
141+
sil [ossa] @phi_indirect_1000_lexical : $() -> () {
142+
entry:
143+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
144+
cond_br undef, lt, rt
145+
146+
lt:
147+
cond_br undef, ll, lr
148+
ll:
149+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
150+
%m1 = move_value [lexical] %c1 : $C
151+
br lb(%m1 : $C)
152+
lr:
153+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
154+
br lb(%c2 : $C)
155+
lb(%cl : @owned $C):
156+
br exit(%cl : $C)
157+
158+
rt:
159+
cond_br undef, rl, rr
160+
rl:
161+
%c3 = apply %getC() : $@convention(thin) () -> (@owned C)
162+
br rb(%c3 : $C)
163+
rr:
164+
%c4 = apply %getC() : $@convention(thin) () -> (@owned C)
165+
br rb(%c4 : $C)
166+
rb(%cr : @owned $C):
167+
br exit(%cr : $C)
168+
169+
exit(%cm : @owned $C):
170+
test_specification "is-lexical @block.argument"
171+
destroy_value %cm : $C
172+
%retval = tuple ()
173+
return %retval : $()
174+
}
175+
176+
// CHECK-LABEL: begin running test 1 of 1 on phi_indirect_0100_lexical: is-lexical
177+
// CHECK: argument of bb9
178+
// CHECK: true
179+
// CHECK-LABEL: end running test 1 of 1 on phi_indirect_0100_lexical: is-lexical
180+
sil [ossa] @phi_indirect_0100_lexical : $() -> () {
181+
entry:
182+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
183+
cond_br undef, lt, rt
184+
185+
lt:
186+
cond_br undef, ll, lr
187+
ll:
188+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
189+
br lb(%c1 : $C)
190+
lr:
191+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
192+
%m2 = move_value [lexical] %c2 : $C
193+
br lb(%m2 : $C)
194+
lb(%cl : @owned $C):
195+
br exit(%cl : $C)
196+
197+
rt:
198+
cond_br undef, rl, rr
199+
rl:
200+
%c3 = apply %getC() : $@convention(thin) () -> (@owned C)
201+
br rb(%c3 : $C)
202+
rr:
203+
%c4 = apply %getC() : $@convention(thin) () -> (@owned C)
204+
br rb(%c4 : $C)
205+
rb(%cr : @owned $C):
206+
br exit(%cr : $C)
207+
208+
exit(%cm : @owned $C):
209+
test_specification "is-lexical @block.argument"
210+
destroy_value %cm : $C
211+
%retval = tuple ()
212+
return %retval : $()
213+
}
214+
215+
// CHECK-LABEL: begin running test 1 of 1 on phi_indirect_0010_lexical: is-lexical
216+
// CHECK: argument of bb9
217+
// CHECK: true
218+
// CHECK-LABEL: end running test 1 of 1 on phi_indirect_0010_lexical: is-lexical
219+
sil [ossa] @phi_indirect_0010_lexical : $() -> () {
220+
entry:
221+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
222+
cond_br undef, lt, rt
223+
224+
lt:
225+
cond_br undef, ll, lr
226+
ll:
227+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
228+
br lb(%c1 : $C)
229+
lr:
230+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
231+
br lb(%c2 : $C)
232+
lb(%cl : @owned $C):
233+
br exit(%cl : $C)
234+
235+
rt:
236+
cond_br undef, rl, rr
237+
rl:
238+
%c3 = apply %getC() : $@convention(thin) () -> (@owned C)
239+
%m3 = move_value [lexical] %c3 : $C
240+
br rb(%m3 : $C)
241+
rr:
242+
%c4 = apply %getC() : $@convention(thin) () -> (@owned C)
243+
br rb(%c4 : $C)
244+
rb(%cr : @owned $C):
245+
br exit(%cr : $C)
246+
247+
exit(%cm : @owned $C):
248+
test_specification "is-lexical @block.argument"
249+
destroy_value %cm : $C
250+
%retval = tuple ()
251+
return %retval : $()
252+
}
253+
254+
// CHECK-LABEL: begin running test 1 of 1 on phi_indirect_0001_lexical: is-lexical
255+
// CHECK: argument of bb9
256+
// CHECK: true
257+
// CHECK-LABEL: end running test 1 of 1 on phi_indirect_0001_lexical: is-lexical
258+
sil [ossa] @phi_indirect_0001_lexical : $() -> () {
259+
entry:
260+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
261+
cond_br undef, lt, rt
262+
263+
lt:
264+
cond_br undef, ll, lr
265+
ll:
266+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
267+
br lb(%c1 : $C)
268+
lr:
269+
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
270+
br lb(%c2 : $C)
271+
lb(%cl : @owned $C):
272+
br exit(%cl : $C)
273+
274+
rt:
275+
cond_br undef, rl, rr
276+
rl:
277+
%c3 = apply %getC() : $@convention(thin) () -> (@owned C)
278+
br rb(%c3 : $C)
279+
rr:
280+
%c4 = apply %getC() : $@convention(thin) () -> (@owned C)
281+
%m4 = move_value [lexical] %c4 : $C
282+
br rb(%m4 : $C)
283+
rb(%cr : @owned $C):
284+
br exit(%cr : $C)
285+
286+
exit(%cm : @owned $C):
287+
test_specification "is-lexical @block.argument"
288+
destroy_value %cm : $C
289+
%retval = tuple ()
290+
return %retval : $()
291+
}

0 commit comments

Comments
 (0)