Skip to content

Commit f1108e5

Browse files
committed
[CanonicalizeOSSALifetime] Handle later reborrows.
Properly handle the different sorts of reborrows when they are visited: - non-branch reborrows (tuples, etc) are non-lifetime-ending uses; such reborrows are relevant defs for liveness - branch reborrows which also consume the owned phi are lifetime-ending uses - branch reborrows which DO NOT consume the owned phi are non-lifetime-ending uses, and the corresponding phis are relevant defs for liveness rdar://97399065
1 parent 2bbdeac commit f1108e5

File tree

2 files changed

+132
-2
lines changed

2 files changed

+132
-2
lines changed

lib/SILOptimizer/Utils/CanonicalOSSALifetime.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,32 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
175175
case OperandOwnership::InteriorPointer:
176176
case OperandOwnership::ForwardingBorrow:
177177
case OperandOwnership::EndBorrow:
178-
case OperandOwnership::Reborrow:
179178
// Guaranteed values are considered uses of the value when the value is
180-
// an owned phi and the guaranteed values are adjacent reborrow phis.
179+
// an owned phi and the guaranteed values are adjacent reborrow phis or
180+
// reborrow of such.
181+
liveness.updateForUse(user, /*lifetimeEnding*/ false);
182+
break;
183+
case OperandOwnership::Reborrow:
184+
BranchInst *branch;
185+
if (!(branch = dyn_cast<BranchInst>(user))) {
186+
// Non-phi reborrows (tuples, etc) never end the lifetime of the owned
187+
// value.
188+
liveness.updateForUse(user, /*lifetimeEnding*/ false);
189+
defUseWorklist.insert(cast<SingleValueInstruction>(user));
190+
break;
191+
}
192+
if (is_contained(user->getOperandValues(), currentDef)) {
193+
// An adjacent phi consumes the value being reborrowed. Although this
194+
// use doesn't end the lifetime, this user does.
195+
liveness.updateForUse(user, /*lifetimeEnding*/ true);
196+
break;
197+
}
198+
// No adjacent phi consumes the value. This use is not lifetime ending.
181199
liveness.updateForUse(user, /*lifetimeEnding*/ false);
200+
// This branch reborrows a guaranteed phi whose lifetime is dependent on
201+
// currentDef. Uses of the reborrowing phi extend liveness.
202+
auto *reborrow = branch->getArgForOperand(use);
203+
defUseWorklist.insert(reborrow);
182204
break;
183205
}
184206
}

test/SILOptimizer/copy_propagation_canonicalize_with_reborrows.sil

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,111 @@ exit:
196196
destroy_value %value : $FakeOptional<X>
197197
return %retval : $()
198198
}
199+
200+
// Ensure that an adjacent reborrow phi being reborrowed doesn't get counted as
201+
// a non-lifetime ending use and extend liveness beyond the instruction where
202+
// the reborrow occurs.
203+
// CHECK-LABEL: sil [ossa] @reborrow_adjacent_to_consume_doesnt_extend_lifetime : {{.*}} {
204+
// CHECK: bb1([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] :
205+
// CHECK: {{bb[0-9]+}}:
206+
// CHECK: end_borrow [[REBORROW]]
207+
// CHECK: destroy_value [[VALUE]]
208+
// CHECK-LABEL: } // end sil function 'reborrow_adjacent_to_consume_doesnt_extend_lifetime'
209+
sil [ossa] @reborrow_adjacent_to_consume_doesnt_extend_lifetime : $@convention(thin) (@owned X) -> () {
210+
bb0(%0 : @owned $X):
211+
%1 = begin_borrow %0 : $X
212+
br bb1(%1 : $X, %0 : $X)
213+
214+
bb1(%3 : @guaranteed $X, %4 : @owned $X):
215+
cond_br undef, bb2, bb10
216+
217+
bb2:
218+
br bb3
219+
220+
bb3:
221+
br bb4(%3 : $X, %4 : $X)
222+
223+
bb4(%8 : @guaranteed $X, %9 : @owned $X):
224+
cond_br undef, bb5, bb8
225+
226+
bb5:
227+
br bb6
228+
229+
bb6:
230+
br bb7
231+
232+
bb7:
233+
%13 = function_ref @getX : $@convention(thin) () -> @owned X
234+
%14 = apply %13() : $@convention(thin) () -> @owned X
235+
end_borrow %8 : $X
236+
destroy_value %9 : $X
237+
%17 = begin_borrow %14 : $X
238+
br bb4(%17 : $X, %14 : $X)
239+
240+
bb8:
241+
br bb9
242+
243+
bb9:
244+
br bb1(%8 : $X, %9 : $X)
245+
246+
bb10:
247+
// TODO: Remove the copy once it isn't necessary to trigger canonicalization.
248+
%bogus = copy_value %4 : $X
249+
destroy_value %bogus : $X
250+
%23 = tuple ()
251+
end_borrow %3 : $X
252+
destroy_value %4 : $X
253+
return %23 : $()
254+
}
255+
256+
// CHECK-LABEL: sil [ossa] @nohoist_destroy_over_endborrow_nonadjacent_reborrow : {{.*}} {
257+
// CHECK: end_borrow {{%[^,]+}}
258+
// CHECK: destroy_value {{%[^,]+}}
259+
// CHECK-LABEL: } // end sil function 'nohoist_destroy_over_endborrow_nonadjacent_reborrow'
260+
sil [ossa] @nohoist_destroy_over_endborrow_nonadjacent_reborrow : $@convention(thin) (@owned X) -> () {
261+
entry(%value_1 : @owned $X):
262+
%lifetime_1 = begin_borrow %value_1 : $X
263+
br consume_and_reborrow(%lifetime_1 : $X, %value_1 : $X)
264+
265+
consume_and_reborrow(%lifetime_2 : @guaranteed $X, %value_2 : @owned $X):
266+
br reborrow_only(%lifetime_2 : $X)
267+
268+
reborrow_only(%lifetime_3 : @guaranteed $X):
269+
br exit
270+
271+
exit:
272+
%bogus = copy_value %value_2 : $X
273+
destroy_value %bogus : $X
274+
%retval = tuple ()
275+
end_borrow %lifetime_3 : $X
276+
destroy_value %value_2 : $X
277+
return %retval : $()
278+
}
279+
280+
// CHECK-LABEL: sil [ossa] @nohoist_destroy_over_endborrow_nonadjacent_reborrow_2 : {{.*}} {
281+
// CHECK: end_borrow {{%[^,]+}}
282+
// CHECK: destroy_value {{%[^,]+}}
283+
// CHECK-LABEL: } // end sil function 'nohoist_destroy_over_endborrow_nonadjacent_reborrow_2'
284+
sil [ossa] @nohoist_destroy_over_endborrow_nonadjacent_reborrow_2 : $@convention(thin) (@owned X) -> () {
285+
entry(%value_1 : @owned $X):
286+
%lifetime_1 = begin_borrow %value_1 : $X
287+
br consume_and_reborrow(%lifetime_1 : $X, %value_1 : $X)
288+
289+
consume_and_reborrow(%lifetime_2 : @guaranteed $X, %value_2 : @owned $X):
290+
br reborrow_only_1(%lifetime_2 : $X)
291+
292+
reborrow_only_1(%lifetime_3 : @guaranteed $X):
293+
br reborrow_only_2(%lifetime_3 : $X)
294+
295+
reborrow_only_2(%lifetime_4 : @guaranteed $X):
296+
br exit
297+
298+
exit:
299+
%bogus = copy_value %value_2 : $X
300+
destroy_value %bogus : $X
301+
%retval = tuple ()
302+
end_borrow %lifetime_4 : $X
303+
destroy_value %value_2 : $X
304+
return %retval : $()
305+
}
306+

0 commit comments

Comments
 (0)