Skip to content

Commit 12589b6

Browse files
committed
[LifetimeCompletion] Add extend_lifetimes.
The new instructions are inserted after every "user" (according to InteriorLiveness' SSAPrunedLiveness instance) outside the linear liveness boundary.
1 parent 73dbe12 commit 12589b6

File tree

4 files changed

+178
-3
lines changed

4 files changed

+178
-3
lines changed

include/swift/SIL/OSSALifetimeCompletion.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class OSSALifetimeCompletion {
123123
enum class LifetimeEnd : uint8_t {
124124
/// The lifetime ends at the boundary.
125125
Boundary,
126+
/// The lifetime "ends" in a loop.
127+
Loop,
126128
};
127129

128130
static void visitAvailabilityBoundary(

lib/SIL/Utils/OSSALifetimeCompletion.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ static SILInstruction *endOSSALifetime(SILValue value,
6363
SILBuilder &builder) {
6464
auto loc =
6565
RegularLocation::getAutoGeneratedLocation(builder.getInsertionPointLoc());
66+
if (end == OSSALifetimeCompletion::LifetimeEnd::Loop) {
67+
return builder.createExtendLifetime(loc, value);
68+
}
6669
if (value->getOwnershipKind() == OwnershipKind::Owned) {
6770
if (value->getType().is<SILBoxType>()) {
6871
return builder.createDeallocBox(loc, value);
@@ -147,9 +150,10 @@ static FunctionTest LivenessPartialBoundaryOutsideUsersTest(
147150
} // end namespace swift::test
148151

149152
namespace {
150-
/// Implements OSSALifetimeCompletion::visitAvailabilityBoundary. Finds
151-
/// positions as near as possible to unreachables at which `value`'s lifetime
152-
/// is available.
153+
/// Visits the latest instructions at which `value` is available.
154+
///
155+
/// Together with visitUsersOutsideLinearLivenessBoundary, implements
156+
/// OSSALifetimeCompletion::visitAvailabilityBoundary.
153157
///
154158
/// Finding these positions is a three step process:
155159
/// 1) computeRegion: Forward CFG walk from non-lifetime-ending boundary to find
@@ -396,6 +400,14 @@ void OSSALifetimeCompletion::visitAvailabilityBoundary(
396400
AvailabilityBoundaryVisitor visitor(value, allowLeaks);
397401
AvailabilityBoundaryVisitor::Result result(value->getFunction());
398402
visitor.visit(liveness, result, visit);
403+
404+
visitUsersOutsideLinearLivenessBoundary(
405+
value, liveness, [&](auto *instruction) {
406+
instruction->visitSubsequentInstructions([&](auto *next) {
407+
visit(next, LifetimeEnd::Loop);
408+
return true;
409+
});
410+
});
399411
}
400412

401413
static bool endLifetimeAtAvailabilityBoundary(

lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@ void CanonicalizeOSSALifetime::extendLivenessToDeinitBarriers() {
276276
OSSALifetimeCompletion::visitAvailabilityBoundary(
277277
getCurrentDef(), OSSALifetimeCompletion::DoNotAllowLeaks,
278278
completeLiveness, [&](auto *unreachable, auto end) {
279+
if (end == OSSALifetimeCompletion::LifetimeEnd::Boundary) {
280+
recordUnreachableLifetimeEnd(unreachable);
281+
}
279282
unreachable->visitPriorInstructions([&](auto *inst) {
280283
liveness->extendToNonUse(inst);
281284
return true;

test/SILOptimizer/ossa_lifetime_completion.sil

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,9 +545,24 @@ right:
545545
// CHECK-LABEL: begin running test {{.*}} on loopy: liveness_partial_boundary_outside_users with: %o
546546
// CHECK: end_borrow
547547
// CHECK-LABEL: end running test {{.*}} on loopy: liveness_partial_boundary_outside_users with: %o
548+
// CHECK-LABEL: begin running test {{.*}} on loopy: ossa_lifetime_completion
549+
// CHECK-LABEL: sil [ossa] @loopy : {{.*}} {
550+
// CHECK: [[O:%[^,]+]] = apply undef
551+
// CHECK: [[B:%[^,]+]] = begin_borrow [[O]]
552+
// CHECK: end_borrow [[B]]
553+
// CHECK: extend_lifetime [[O]]
554+
// CHECK: br bb1
555+
// CHECK: bb1:
556+
// CHECK: br bb1
557+
// CHECK-LABEL: } // end sil function 'loopy'
558+
// CHECK-LABEL: end running test {{.*}} on loopy: ossa_lifetime_completion
559+
// CHECK-LABEL: begin running test {{.*}} on loopy: liveness_partial_boundary_outside_users with: %o
560+
// CHECK-NEXT: end running test {{.*}} on loopy: liveness_partial_boundary_outside_users with: %o
548561
sil [ossa] @loopy : $@convention(thin) () -> () {
549562
%o = apply undef() : $@convention(thin) () -> (@owned C)
550563
specify_test "liveness_partial_boundary_outside_users %o"
564+
specify_test "ossa_lifetime_completion %o availability"
565+
specify_test "liveness_partial_boundary_outside_users %o"
551566
%b = begin_borrow %o : $C
552567
end_borrow %b : $C
553568
br loop
@@ -556,6 +571,149 @@ loop:
556571
br loop
557572
}
558573

574+
sil [ossa] @loopyComplete : $@convention(thin) () -> () {
575+
%o = apply undef() : $@convention(thin) () -> (@owned C)
576+
specify_test "ossa_lifetime_completion %o availability"
577+
specify_test "liveness_partial_boundary_outside_users %o"
578+
%b = begin_borrow %o : $C
579+
end_borrow %b : $C
580+
extend_lifetime %o : $C
581+
br loop
582+
583+
loop:
584+
br loop
585+
}
586+
587+
// When there are no users in the loop, do not extend the lifetime into it.
588+
// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes: ossa_lifetime_completion with: %c, availability
589+
// CHECK-LABEL: sil [ossa] @loopy_sometimes : {{.*}} {
590+
// CHECK-NOT: extend_lifetime
591+
// CHECK-LABEL: } // end sil function 'loopy_sometimes'
592+
// CHECK-LABEL: end running test {{.*}} on loopy_sometimes: ossa_lifetime_completion with: %c, availability
593+
// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes: liveness_partial_boundary_outside_users with: %c
594+
// CHECK-NEXT: end running test {{.*}} on loopy_sometimes: liveness_partial_boundary_outside_users with: %c
595+
sil [ossa] @loopy_sometimes : $@convention(thin) (@owned C) -> () {
596+
entry(%c : @owned $C):
597+
specify_test "ossa_lifetime_completion %c availability"
598+
specify_test "liveness_partial_boundary_outside_users %c"
599+
cond_br undef, header, exit
600+
601+
header:
602+
br loop
603+
604+
loop:
605+
br loop
606+
607+
exit:
608+
destroy_value %c : $C
609+
%retval = tuple ()
610+
return %retval : $()
611+
}
612+
613+
// When there are no users in the loop, do not extend the lifetime into it.
614+
// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_guaranteed: ossa_lifetime_completion with: %b, availability
615+
// CHECK-LABEL: sil [ossa] @loopy_sometimes_guaranteed : {{.*}} {
616+
// CHECK-NOT: extend_lifetime
617+
// CHECK-LABEL: } // end sil function 'loopy_sometimes_guaranteed'
618+
// CHECK-LABEL: end running test {{.*}} on loopy_sometimes_guaranteed: ossa_lifetime_completion with: %b, availability
619+
// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_guaranteed: liveness_partial_boundary_outside_users with: %b
620+
// CHECK-LABEL: end running test {{.*}} on loopy_sometimes_guaranteed: liveness_partial_boundary_outside_users with: %b
621+
sil [ossa] @loopy_sometimes_guaranteed : $@convention(thin) (@owned C) -> () {
622+
entry(%c : @owned $C):
623+
%b = begin_borrow %c : $C
624+
specify_test "ossa_lifetime_completion %b availability"
625+
specify_test "liveness_partial_boundary_outside_users %b"
626+
cond_br undef, header, exit
627+
628+
header:
629+
br loop
630+
631+
loop:
632+
br loop
633+
634+
exit:
635+
end_borrow %b : $C
636+
destroy_value %c : $C
637+
%retval = tuple ()
638+
return %retval : $()
639+
}
640+
641+
// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_2: ossa_lifetime_completion with: %c, availability
642+
// CHECK-LABEL: sil [ossa] @loopy_sometimes_2 : {{.*}} {
643+
// CHECK: bb0([[O:%[^,]+]] :
644+
// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]]
645+
// CHECK: [[HEADER]]:
646+
// CHECK: br [[LOOP:bb[0-9]+]]
647+
// CHECK: [[LOOP]]:
648+
// CHECK: [[B:%[^,]+]] = begin_borrow [[O]]
649+
// CHECK: end_borrow [[B]]
650+
// CHECK: extend_lifetime [[O]]
651+
// CHECK: br [[LOOP]]
652+
// CHECK: [[EXIT]]:
653+
// CHECK: destroy_value [[O]]
654+
// CHECK-LABEL: } // end sil function 'loopy_sometimes_2'
655+
// CHECK-LABEL: end running test {{.*}} on loopy_sometimes_2: ossa_lifetime_completion with: %c, availability
656+
sil [ossa] @loopy_sometimes_2 : $@convention(thin) (@owned C) -> () {
657+
entry(%c : @owned $C):
658+
specify_test "ossa_lifetime_completion %c availability"
659+
specify_test "liveness_partial_boundary_outside_users %c"
660+
cond_br undef, header, exit
661+
662+
header:
663+
br loop
664+
665+
loop:
666+
%b = begin_borrow %c : $C
667+
end_borrow %b : $C
668+
br loop
669+
670+
exit:
671+
destroy_value %c : $C
672+
%retval = tuple ()
673+
return %retval : $()
674+
}
675+
676+
// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_2_guaranteed: ossa_lifetime_completion with: %c, availability
677+
// CHECK-LABEL: sil [ossa] @loopy_sometimes_2_guaranteed : {{.*}} {
678+
// CHECK: bb0([[C:%[^,]+]] :
679+
// CHECK: [[B:%[^,]+]] = begin_borrow [[C]]
680+
// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]]
681+
// CHECK: [[HEADER]]:
682+
// CHECK: br [[LOOP:bb[0-9]+]]
683+
// CHECK: [[LOOP]]:
684+
// CHECK: [[I:%[^,]+]] = begin_borrow [[B]]
685+
// CHECK: end_borrow [[I]]
686+
// CHECK: extend_lifetime [[B]]
687+
// CHECK: br [[LOOP]]
688+
// CHECK: [[EXIT]]:
689+
// CHECK: end_borrow [[B]]
690+
// CHECK: destroy_value [[C]]
691+
// CHECK-LABEL: } // end sil function 'loopy_sometimes_2_guaranteed'
692+
// CHECK-LABEL: end running test {{.*}} on loopy_sometimes_2_guaranteed: ossa_lifetime_completion with: %c, availability
693+
// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_2_guaranteed: liveness_partial_boundary_outside_users with: %c
694+
// CHECK-NEXT: end running test {{.*}} on loopy_sometimes_2_guaranteed: liveness_partial_boundary_outside_users with: %c
695+
sil [ossa] @loopy_sometimes_2_guaranteed : $@convention(thin) (@owned C) -> () {
696+
entry(%c : @owned $C):
697+
%b = begin_borrow %c : $C
698+
specify_test "ossa_lifetime_completion %c availability"
699+
specify_test "liveness_partial_boundary_outside_users %c"
700+
cond_br undef, header, exit
701+
702+
header:
703+
br loop
704+
705+
loop:
706+
%i = begin_borrow %b : $C
707+
end_borrow %i : $C
708+
br loop
709+
710+
exit:
711+
end_borrow %b : $C
712+
destroy_value %c : $C
713+
%retval = tuple ()
714+
return %retval : $()
715+
}
716+
559717
// CHECK-LABEL: begin running test {{.*}} on type_dependent_operand: liveness_partial_boundary_outside_users
560718
// There should be no out-of-boundary users.
561719
// CHECK-NEXT: end running test {{.*}} on type_dependent_operand: liveness_partial_boundary_outside_users

0 commit comments

Comments
 (0)