Skip to content

Commit 2bbdeac

Browse files
committed
[CanonicalizeOSSALifetime] Handle adj reborrows.
When canonicalizing lifetime of an owned phi, add adjacent phis which are reborrows of its reaching values to the worklist. Update liveness to consider uses whose operand ownership is specific to guaranteed values (i.e. uses which are derived from these adjacent reborrow phis) as standard, non-lifetime-ending uses. rdar://94346482
1 parent fe43531 commit 2bbdeac

File tree

2 files changed

+209
-1
lines changed

2 files changed

+209
-1
lines changed

lib/SILOptimizer/Utils/CanonicalOSSALifetime.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ void swift::copyLiveUse(Operand *use, InstModCallbacks &instModCallbacks) {
114114
bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
115115
defUseWorklist.initialize(currentDef);
116116
while (SILValue value = defUseWorklist.pop()) {
117+
SILPhiArgument *arg;
118+
if ((arg = dyn_cast<SILPhiArgument>(value)) && arg->isPhi()) {
119+
visitAdjacentReborrowsOfPhi(arg, [&](SILPhiArgument *reborrow) {
120+
defUseWorklist.insert(reborrow);
121+
return true;
122+
});
123+
}
117124
for (Operand *use : value->getUses()) {
118125
auto *user = use->getUser();
119126

@@ -169,7 +176,10 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
169176
case OperandOwnership::ForwardingBorrow:
170177
case OperandOwnership::EndBorrow:
171178
case OperandOwnership::Reborrow:
172-
llvm_unreachable("operand kind cannot take an owned value");
179+
// Guaranteed values are considered uses of the value when the value is
180+
// an owned phi and the guaranteed values are adjacent reborrow phis.
181+
liveness.updateForUse(user, /*lifetimeEnding*/ false);
182+
break;
173183
}
174184
}
175185
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// RUN: %target-sil-opt -copy-propagation -enable-sil-verify-all %s | %FileCheck %s --check-prefixes=CHECK,CHECK-OPT
2+
3+
class X {}
4+
5+
enum FakeOptional<T> {
6+
case some(T)
7+
case none
8+
}
9+
10+
sil [ossa] @getX : $@convention(thin) () -> (@owned X)
11+
sil [ossa] @holdX : $@convention(thin) (@guaranteed X) -> ()
12+
13+
// CHECK-LABEL: sil [ossa] @nohoist_destroy_over_reborrow_endborrow : {{.*}} {
14+
// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X):
15+
// CHECK: end_borrow [[REBORROW]]
16+
// CHECK: destroy_value [[VALUE]]
17+
// CHECK-LABEL: } // end sil function 'nohoist_destroy_over_reborrow_endborrow'
18+
sil [ossa] @nohoist_destroy_over_reborrow_endborrow : $@convention(thin) () -> () {
19+
entry:
20+
%get = function_ref @getX : $@convention(thin) () -> @owned X
21+
%value_1 = apply %get() : $@convention(thin) () -> @owned X
22+
%lifetime = begin_borrow %value_1 : $X
23+
br body(%lifetime : $X, %value_1 : $X)
24+
25+
body(%reborrow : @guaranteed $X, %value_2 : @owned $X):
26+
// TODO: The copy is currently needed to trigger canonicalization of the
27+
// lifetime. Remove once it is no longer needed.
28+
%copy = copy_value %value_2 : $X
29+
destroy_value %copy : $X
30+
31+
end_borrow %reborrow : $X
32+
destroy_value %value_2 : $X
33+
br exit
34+
35+
exit:
36+
%retval = tuple ()
37+
return %retval : $()
38+
}
39+
40+
// CHECK-LABEL: sil [ossa] @hoist_destroy_over_unrelated_endborrow : {{.*}} {
41+
// CHECK: {{bb[0-9]+}}([[UNRELATED:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X):
42+
// CHECK: destroy_value [[VALUE]]
43+
// CHECK: end_borrow [[UNRELATED]]
44+
// CHECK-LABEL: } // end sil function 'hoist_destroy_over_unrelated_endborrow'
45+
sil [ossa] @hoist_destroy_over_unrelated_endborrow : $@convention(thin) (@guaranteed X) -> () {
46+
entry(%unrelated : @guaranteed $X):
47+
%get = function_ref @getX : $@convention(thin) () -> @owned X
48+
%value_1 = apply %get() : $@convention(thin) () -> @owned X
49+
%borrow_1 = begin_borrow %unrelated : $X
50+
br body(%borrow_1 : $X, %value_1 : $X)
51+
52+
body(%borrow_2 : @guaranteed $X, %value_2 : @owned $X):
53+
// TODO: The copy is currently needed to trigger canonicalization of the
54+
// lifetime. Remove once it is no longer needed.
55+
%copy = copy_value %value_2 : $X
56+
destroy_value %copy : $X
57+
58+
%hold = function_ref @holdX : $@convention(thin) (@guaranteed X) -> ()
59+
apply %hold(%borrow_2) : $@convention(thin) (@guaranteed X) -> ()
60+
end_borrow %borrow_2 : $X
61+
destroy_value %value_2 : $X
62+
br exit
63+
64+
exit:
65+
%retval = tuple ()
66+
return %retval : $()
67+
}
68+
69+
// CHECK-LABEL: sil [ossa] @nohoist_destroy_over_reborrow_reborrow_endborrow : {{.*}} {
70+
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @guaranteed $X, {{%[^,]+}} : @owned $X):
71+
// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X):
72+
// CHECK: end_borrow [[REBORROW]]
73+
// CHECK: destroy_value [[VALUE]]
74+
// CHECK-LABEL: } // end sil function 'nohoist_destroy_over_reborrow_reborrow_endborrow'
75+
sil [ossa] @nohoist_destroy_over_reborrow_reborrow_endborrow : $@convention(thin) () -> () {
76+
entry:
77+
%get = function_ref @getX : $@convention(thin) () -> @owned X
78+
%value_1 = apply %get() : $@convention(thin) () -> @owned X
79+
%lifetime = begin_borrow %value_1 : $X
80+
br body1(%lifetime : $X, %value_1 : $X)
81+
82+
body1(%lifetime_2 : @guaranteed $X, %value_2 : @owned $X):
83+
br body2(%lifetime_2 : $X, %value_2 : $X)
84+
85+
body2(%lifetime_3 : @guaranteed $X, %value_3 : @owned $X):
86+
// TODO: Remove the copy once it isn't necessary to trigger canonicalization.
87+
%copy_3 = copy_value %value_3 : $X
88+
destroy_value %copy_3 : $X
89+
90+
end_borrow %lifetime_3 : $X
91+
destroy_value %value_3 : $X
92+
br exit
93+
94+
exit:
95+
%14 = tuple ()
96+
return %14 : $()
97+
}
98+
99+
// CHECK-LABEL: sil [ossa] @hoist_destroy_over_unrelated_reborrow_reborrow_endborrow : {{.*}} {
100+
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @guaranteed $X, {{%[^,]+}} : @owned $X):
101+
// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X):
102+
// CHECK: destroy_value [[VALUE]]
103+
// CHECK: end_borrow [[REBORROW]]
104+
// CHECK-LABEL: } // end sil function 'hoist_destroy_over_unrelated_reborrow_reborrow_endborrow'
105+
sil [ossa] @hoist_destroy_over_unrelated_reborrow_reborrow_endborrow : $@convention(thin) (@guaranteed X) -> () {
106+
entry(%unrelated : @guaranteed $X):
107+
%get = function_ref @getX : $@convention(thin) () -> @owned X
108+
%value_1 = apply %get() : $@convention(thin) () -> @owned X
109+
%borrow_1 = begin_borrow %unrelated : $X
110+
br body1(%borrow_1 : $X, %value_1 : $X)
111+
112+
body1(%borrow_2 : @guaranteed $X, %value_2 : @owned $X):
113+
br body2(%borrow_2 : $X, %value_2 : $X)
114+
115+
body2(%borrow_3 : @guaranteed $X, %value_3 : @owned $X):
116+
// TODO: Remove the copy once it isn't necessary to trigger canonicalization.
117+
%copy_3 = copy_value %value_3 : $X
118+
destroy_value %copy_3 : $X
119+
120+
%hold = function_ref @holdX : $@convention(thin) (@guaranteed X) -> ()
121+
apply %hold(%borrow_3) : $@convention(thin) (@guaranteed X) -> ()
122+
end_borrow %borrow_3 : $X
123+
destroy_value %value_3 : $X
124+
br exit
125+
126+
exit:
127+
%14 = tuple ()
128+
return %14 : $()
129+
}
130+
131+
// CHECK-LABEL: sil [ossa] @nohoist_destroy_over_forward_reborrow_endborrow : {{.*}} {
132+
// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X):
133+
// CHECK: end_borrow [[REBORROW]]
134+
// CHECK: destroy_value [[VALUE]]
135+
// CHECK-LABEL: } // end sil function 'nohoist_destroy_over_forward_reborrow_endborrow'
136+
sil [ossa] @nohoist_destroy_over_forward_reborrow_endborrow : $@convention(thin) () -> () {
137+
entry:
138+
%get = function_ref @getX : $@convention(thin) () -> @owned X
139+
%value_1 = apply %get() : $@convention(thin) () -> @owned X
140+
br body1(%value_1 : $X)
141+
142+
body1(%value_2 : @owned $X):
143+
%lifetime_2 = begin_borrow %value_2 : $X
144+
br body2(%lifetime_2 : $X, %value_2 : $X)
145+
146+
body2(%lifetime_3 : @guaranteed $X, %value_3 : @owned $X):
147+
// TODO: Remove the copy once it isn't necessary to trigger canonicalization.
148+
%copy_3 = copy_value %value_3 : $X
149+
destroy_value %copy_3 : $X
150+
151+
end_borrow %lifetime_3 : $X
152+
destroy_value %value_3 : $X
153+
br exit
154+
155+
exit:
156+
%retval = tuple ()
157+
return %retval : $()
158+
}
159+
160+
// CHECK-LABEL: sil [ossa] @nohoist_destroy_over_reborrow_loop : {{.*}} {
161+
// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $FakeOptional<X>, [[VALUE:%[^,]+]] : @owned $FakeOptional<X>):
162+
// CHECK: cond_br undef, [[LOOP:bb[0-9]+]], [[BODY:bb[0-9]+]]
163+
// CHECK: [[LOOP]]:
164+
// CHECK: end_borrow [[REBORROW]] : $FakeOptional<X>
165+
// CHECK: destroy_value [[VALUE]] : $FakeOptional<X>
166+
// CHECK: [[BODY]]:
167+
// CHECK: end_borrow [[REBORROW]] : $FakeOptional<X>
168+
// CHECK: destroy_value [[VALUE]] : $FakeOptional<X>
169+
// CHECK-LABEL: } // end sil function 'nohoist_destroy_over_reborrow_loop'
170+
sil [ossa] @nohoist_destroy_over_reborrow_loop : $@convention(thin) () -> () {
171+
entry:
172+
%none1 = enum $FakeOptional<X>, #FakeOptional.none!enumelt
173+
%none2 = enum $FakeOptional<X>, #FakeOptional.none!enumelt
174+
br head(%none2 : $FakeOptional<X>, %none1 : $FakeOptional<X>)
175+
176+
head(%reborrow : @guaranteed $FakeOptional<X>, %value : @owned $FakeOptional<X>):
177+
cond_br undef, body, exit
178+
179+
body:
180+
%get = function_ref @getX : $@convention(thin) () -> (@owned X)
181+
%value_0 = apply %get() : $@convention(thin) () -> (@owned X)
182+
end_borrow %reborrow : $FakeOptional<X>
183+
184+
// TODO: Remove the copy once it isn't necessary to trigger canonicalization.
185+
%bogus = copy_value %value : $FakeOptional<X>
186+
destroy_value %bogus : $FakeOptional<X>
187+
188+
destroy_value %value : $FakeOptional<X>
189+
%some_value_0 = enum $FakeOptional<X>, #FakeOptional.some!enumelt, %value_0 : $X
190+
%some_borrow_0 = begin_borrow %some_value_0 : $FakeOptional<X>
191+
br head(%some_borrow_0 : $FakeOptional<X>, %some_value_0 : $FakeOptional<X>)
192+
193+
exit:
194+
%retval = tuple ()
195+
end_borrow %reborrow : $FakeOptional<X>
196+
destroy_value %value : $FakeOptional<X>
197+
return %retval : $()
198+
}

0 commit comments

Comments
 (0)