Skip to content

Commit e09b267

Browse files
committed
[CanOSSALife] Lexical lifetimes go to unreachables
When canonicalizing the lifetime of a lexical value, deinit barriers are respected. This is done by walking backwards from lifetime ends and adding encountered deinit barriers to liveness. Only destroy lifetime ends were walked back from under the assumption that lifetimes would be complete. Without complete OSSA lifetimes, however, it's necessary to also necessary to consider lifetimes that end with unreachables. Unfortunately, we can't simply walk back from those unreachables because there may be instructions which are secretly users of the value being canonicalized (e.g. destroys of `partial_apply`s to which a `begin_borrow` of the value was passed). Such uses don't appear in the use list because lifetime canonicalization expects complete lifetimes and only visits lifetime ends of `begin_borrow`s. Here, instead, the instructions before the relevant unreachables are added to liveness. In order to determine which unreachables are relevant, it's necessary to have a liveness that includes the original destroys. So a copy of liveness is created and those destroys are added to it. rdar://115468707
1 parent a7a4b5a commit e09b267

File tree

4 files changed

+71
-7
lines changed

4 files changed

+71
-7
lines changed

include/swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ class CanonicalizeOSSALifetime final {
319319

320320
currentDef = def;
321321

322-
if (maximizeLifetime) {
322+
if (maximizeLifetime || respectsDeinitBarriers()) {
323323
liveness->initializeDiscoveredBlocks(&discoveredBlocks);
324324
}
325325
liveness->initializeDef(getCurrentDef());
@@ -405,8 +405,9 @@ class CanonicalizeOSSALifetime final {
405405

406406
void recordDebugValue(DebugValueInst *dvi) { debugValues.insert(dvi); }
407407

408-
void recordConsumingUse(Operand *use) {
409-
consumingBlocks.insert(use->getUser()->getParent());
408+
void recordConsumingUse(Operand *use) { recordConsumingUser(use->getUser()); }
409+
void recordConsumingUser(SILInstruction *user) {
410+
consumingBlocks.insert(user->getParent());
410411
}
411412
bool computeCanonicalLiveness();
412413

lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#include "swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h"
6969
#include "swift/SIL/InstructionUtils.h"
7070
#include "swift/SIL/NodeDatastructures.h"
71+
#include "swift/SIL/OSSALifetimeCompletion.h"
7172
#include "swift/SIL/OwnershipUtils.h"
7273
#include "swift/SIL/PrunedLiveness.h"
7374
#include "swift/SIL/Test.h"
@@ -249,6 +250,33 @@ void CanonicalizeOSSALifetime::extendLivenessToDeinitBarriers() {
249250
SmallVector<SILInstruction *, 4> outsideDestroys;
250251
findDestroysOutsideBoundary(outsideDestroys);
251252

253+
SmallVector<SILBasicBlock *, 32> discoveredBlocks(this->discoveredBlocks);
254+
SSAPrunedLiveness completeLiveness(*liveness, &discoveredBlocks);
255+
256+
for (auto *end : outsideDestroys) {
257+
completeLiveness.updateForUse(end, /*lifetimeEnding*/ true);
258+
}
259+
260+
OSSALifetimeCompletion::visitUnreachableLifetimeEnds(
261+
getCurrentDef(), completeLiveness, [&](auto *unreachable) {
262+
recordConsumingUser(unreachable);
263+
if (auto *previous = unreachable->getPreviousInstruction()) {
264+
if (liveness->isInterestingUser(previous) ==
265+
PrunedLiveness::IsInterestingUser::NonUser) {
266+
liveness->updateForUse(previous, /*lifetimeEnding=*/false);
267+
}
268+
return;
269+
}
270+
for (auto *predecessor :
271+
unreachable->getParent()->getPredecessorBlocks()) {
272+
auto *previous = &predecessor->back();
273+
if (liveness->isInterestingUser(previous) ==
274+
PrunedLiveness::IsInterestingUser::NonUser) {
275+
liveness->updateForUse(previous, /*lifetimeEnding=*/false);
276+
}
277+
}
278+
});
279+
252280
auto *def = getCurrentDef()->getDefiningInstruction();
253281
using InitialBlocks = ArrayRef<SILBasicBlock *>;
254282
auto *defBlock = getCurrentDef()->getParentBlock();

test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,19 @@ entry(%instance : @owned $MoE):
181181
return %retval : $()
182182
}
183183

184-
// CHECK-LABEL: begin running test 1 of 1 on respect_boundary_edges_when_extending_to_deinit_barriers: canonicalize-ossa-lifetime with: true, false, true, @argument
185-
// respect_boundary_edges_when_extending_to_deinit_barriers
184+
// CHECK-LABEL: begin running test 1 of 1 on respect_boundary_edges_when_extending_to_deinit_barriers
186185
// CHECK-LABEL: sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers : {{.*}} {
187186
// CHECK: bb0([[INSTANCE:%[^,]+]] :
188187
// CHECK: apply {{%[^,]+}}()
189188
// CHECK: cond_br undef, [[DIE:bb[0-9]+]], [[DESTROY:bb[0-9]+]]
190189
// CHECK: [[DIE]]:
190+
// CHECK: destroy_value [[INSTANCE]] : $C
191191
// CHECK: unreachable
192192
// CHECK: [[DESTROY]]:
193193
// CHECK: destroy_value [[INSTANCE]] : $C
194+
// CHECK: return
194195
// CHECK-LABEL: } // end sil function 'respect_boundary_edges_when_extending_to_deinit_barriers'
195-
// CHECK-LABEL: end running test 1 of 1 on respect_boundary_edges_when_extending_to_deinit_barriers: canonicalize-ossa-lifetime with: true, false, true, @argument
196+
// CHECK-LABEL: end running test 1 of 1 on respect_boundary_edges_when_extending_to_deinit_barriers
196197
sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers : $@convention(thin) (@owned C) -> () {
197198
entry(%instance : @owned $C):
198199
test_specification "canonicalize-ossa-lifetime true false true @argument"
@@ -208,3 +209,36 @@ destroy:
208209
%retval = tuple ()
209210
return %retval : $()
210211
}
212+
213+
// CHECK-LABEL: begin running test {{.*}} on respect_boundary_edges_when_extending_to_deinit_barriers_2
214+
// CHECK-LABEL: sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers_2 : {{.*}} {
215+
// CHECK: bb0([[INSTANCE:%[^,]+]] :
216+
// CHECK: apply
217+
// CHECK: cond_br undef, [[DIE:bb[0-9]+]], [[DESTROY:bb[0-9]+]]
218+
// CHECK: [[DIE]]:
219+
// CHECK: apply
220+
// CHECK: destroy_value [[INSTANCE]]
221+
// CHECK: unreachable
222+
// CHECK: [[DESTROY]]:
223+
// CHECK: destroy_value [[INSTANCE]]
224+
// CHECK-LABEL: } // end sil function 'respect_boundary_edges_when_extending_to_deinit_barriers_2'
225+
// CHECK-LABEL: end running test {{.*}} on respect_boundary_edges_when_extending_to_deinit_barriers_2
226+
sil [ossa] @respect_boundary_edges_when_extending_to_deinit_barriers_2 : $@convention(thin) (@owned C) -> () {
227+
entry(%instance : @owned $C):
228+
test_specification "canonicalize-ossa-lifetime true false true @argument"
229+
%barrier = function_ref @barrier : $@convention(thin) () -> ()
230+
apply %barrier() : $@convention(thin) () -> ()
231+
cond_br undef, die, destroy
232+
233+
die:
234+
apply %barrier() : $@convention(thin) () -> ()
235+
br rlydie
236+
237+
rlydie:
238+
unreachable
239+
240+
destroy:
241+
destroy_value %instance : $C
242+
%retval = tuple ()
243+
return %retval : $()
244+
}

test/SILOptimizer/mem2reg_lifetime.sil

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1858,7 +1858,8 @@ right:
18581858
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
18591859
// CHECK: cond_br undef, [[BB1:bb[0-9]+]], [[BB4:bb[0-9]+]]
18601860
// CHECK: [[BB1]]:
1861-
// CHECK: [[LIFETIME_OWNED:%[^,]+]] = move_value [lexical] [[INSTANCE]]
1861+
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE]]
1862+
// CHECK: [[LIFETIME_OWNED:%[^,]+]] = move_value [lexical] [[COPY]]
18621863
// CHECK: cond_br undef, [[BB2:bb[0-9]+]], [[BB3:bb[0-9]+]]
18631864
// CHECK: [[BB2]]:
18641865
// CHECK: destroy_value [[LIFETIME_OWNED]]

0 commit comments

Comments
 (0)