Skip to content

Commit 98ab6b2

Browse files
Merge pull request #78207 from nate-chandler/cherrypick/release/6.1/rdar141246601
6.1: [OSSACompleteLifetime] Recurse into scoped addresses.
2 parents 06c5bda + 1726b32 commit 98ab6b2

File tree

4 files changed

+229
-4
lines changed

4 files changed

+229
-4
lines changed

include/swift/SIL/OSSALifetimeCompletion.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class OSSALifetimeCompletion {
134134

135135
protected:
136136
bool analyzeAndUpdateLifetime(SILValue value, Boundary boundary);
137+
bool analyzeAndUpdateLifetime(ScopedAddressValue value, Boundary boundary);
137138
};
138139

139140
//===----------------------------------------------------------------------===//

lib/SIL/Utils/OSSALifetimeCompletion.cpp

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151

5252
#include "swift/SIL/OSSALifetimeCompletion.h"
5353
#include "swift/Basic/Assertions.h"
54+
#include "swift/SIL/AddressWalker.h"
5455
#include "swift/SIL/BasicBlockUtils.h"
5556
#include "swift/SIL/SILBuilder.h"
5657
#include "swift/SIL/SILFunction.h"
@@ -439,16 +440,62 @@ static bool endLifetimeAtBoundary(SILValue value,
439440
return changed;
440441
}
441442

443+
bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(
444+
ScopedAddressValue scopedAddress, Boundary boundary) {
445+
SmallVector<SILBasicBlock *, 8> discoveredBlocks;
446+
SSAPrunedLiveness liveness(scopedAddress->getFunction(), &discoveredBlocks);
447+
liveness.initializeDef(scopedAddress.value);
448+
449+
struct Walker : TransitiveAddressWalker<Walker> {
450+
OSSALifetimeCompletion &completion;
451+
ScopedAddressValue scopedAddress;
452+
Boundary boundary;
453+
SSAPrunedLiveness &liveness;
454+
Walker(OSSALifetimeCompletion &completion, ScopedAddressValue scopedAddress,
455+
Boundary boundary, SSAPrunedLiveness &liveness)
456+
: completion(completion), scopedAddress(scopedAddress),
457+
boundary(boundary), liveness(liveness) {}
458+
bool visitUse(Operand *use) {
459+
auto *user = use->getUser();
460+
if (scopedAddress.isScopeEndingUse(use)) {
461+
liveness.updateForUse(user, /*lifetimeEnding=*/true);
462+
return true;
463+
}
464+
liveness.updateForUse(user, /*lifetimeEnding=*/false);
465+
for (auto result : user->getResults()) {
466+
auto shouldComplete =
467+
(bool)BorrowedValue(result) || (bool)ScopedAddressValue(result);
468+
if (!shouldComplete)
469+
continue;
470+
auto completed = completion.completeOSSALifetime(result, boundary);
471+
switch (completed) {
472+
case LifetimeCompletion::NoLifetime:
473+
break;
474+
case LifetimeCompletion::AlreadyComplete:
475+
case LifetimeCompletion::WasCompleted:
476+
for (auto *consume : result->getConsumingUses()) {
477+
liveness.updateForUse(consume->getUser(), /*lifetimeEnding=*/false);
478+
}
479+
break;
480+
}
481+
}
482+
return true;
483+
}
484+
};
485+
Walker walker(*this, scopedAddress, boundary, liveness);
486+
std::move(walker).walk(scopedAddress.value);
487+
488+
return endLifetimeAtBoundary(scopedAddress.value, liveness, boundary,
489+
deadEndBlocks);
490+
}
491+
442492
/// End the lifetime of \p value at unreachable instructions.
443493
///
444494
/// Returns true if any new instructions were created to complete the lifetime.
445495
bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(SILValue value,
446496
Boundary boundary) {
447497
if (auto scopedAddress = ScopedAddressValue(value)) {
448-
SmallVector<SILBasicBlock *, 8> discoveredBlocks;
449-
SSAPrunedLiveness liveness(value->getFunction(), &discoveredBlocks);
450-
scopedAddress.computeTransitiveLiveness(liveness);
451-
return endLifetimeAtBoundary(value, liveness, boundary, deadEndBlocks);
498+
return analyzeAndUpdateLifetime(scopedAddress, boundary);
452499
}
453500

454501
// Called for inner borrows, inner adjacent reborrows, inner reborrows, and

test/SILOptimizer/mem2reg_ossa_nontrivial.sil

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ sil [ossa] @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStr
6262
sil [ossa] @get_nontrivialenum : $@convention(thin) () -> @owned NonTrivialEnum
6363
sil [ossa] @get_optionalnontrivialstruct : $@convention(thin) () -> @owned FakeOptional<NonTrivialStruct>
6464
sil [ossa] @take_nontrivialstruct : $@convention(thin) (@owned NonTrivialStruct) -> ()
65+
sil @get : $@convention(thin) () -> @owned FakeOptional<Klass>
66+
sil @use : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
6567

6668
///////////
6769
// Tests //
@@ -1487,3 +1489,63 @@ bb1:
14871489
%t = tuple ()
14881490
return %t : $()
14891491
}
1492+
1493+
// Ensure no verification failure
1494+
sil [ossa] @test_store_enum_value_in_multiple_locs1 : $@convention(thin) () -> () {
1495+
bb0:
1496+
%0 = function_ref @get : $@convention(thin) () -> @owned FakeOptional<Klass>
1497+
%1 = apply %0() : $@convention(thin) () -> @owned FakeOptional<Klass>
1498+
%2 = begin_borrow [lexical] %1 : $FakeOptional<Klass>
1499+
cond_br undef, bb2, bb1
1500+
1501+
bb1:
1502+
br bb3
1503+
1504+
bb2:
1505+
%5 = alloc_stack [lexical] $FakeOptional<Klass>
1506+
%6 = store_borrow %2 to %5 : $*FakeOptional<Klass>
1507+
cond_br undef, bb8, bb9
1508+
1509+
bb3:
1510+
cond_br undef, bb5, bb4
1511+
1512+
bb4:
1513+
unreachable
1514+
1515+
bb5:
1516+
%11 = alloc_stack $FakeOptional<Klass>
1517+
%12 = store_borrow %2 to %11 : $*FakeOptional<Klass>
1518+
%14 = load_borrow %12 : $*FakeOptional<Klass>
1519+
%15 = begin_borrow [lexical] %14 : $FakeOptional<Klass>
1520+
%16 = alloc_stack $FakeOptional<Klass>
1521+
%17 = store_borrow %15 to %16 : $*FakeOptional<Klass>
1522+
cond_br undef, bb6, bb7
1523+
1524+
bb6:
1525+
fix_lifetime %17 : $*FakeOptional<Klass>
1526+
end_borrow %17 : $*FakeOptional<Klass>
1527+
dealloc_stack %16 : $*FakeOptional<Klass>
1528+
end_borrow %15 : $FakeOptional<Klass>
1529+
end_borrow %14 : $FakeOptional<Klass>
1530+
end_borrow %12 : $*FakeOptional<Klass>
1531+
dealloc_stack %11 : $*FakeOptional<Klass>
1532+
end_borrow %2 : $FakeOptional<Klass>
1533+
destroy_value %1 : $FakeOptional<Klass>
1534+
%29 = tuple ()
1535+
return %29 : $()
1536+
1537+
bb7:
1538+
end_borrow %17 : $*FakeOptional<Klass>
1539+
dealloc_stack %16 : $*FakeOptional<Klass>
1540+
unreachable
1541+
1542+
bb8:
1543+
end_borrow %6 : $*FakeOptional<Klass>
1544+
dealloc_stack %5 : $*FakeOptional<Klass>
1545+
unreachable
1546+
1547+
bb9:
1548+
end_borrow %6 : $*FakeOptional<Klass>
1549+
dealloc_stack %5 : $*FakeOptional<Klass>
1550+
br bb3
1551+
}

test/SILOptimizer/ossa_lifetime_completion.sil

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,90 @@ die:
817817
unreachable
818818
}
819819

820+
// CHECK-LABEL: begin running test {{.*}} on load_borrow_of_store_borrow_1: ossa_lifetime_completion
821+
// CHECK-LABEL: sil [ossa] @load_borrow_of_store_borrow_1 : {{.*}} {
822+
// CHECK: [[TOKEN:%[^,]+]] = store_borrow
823+
// CHECK: [[LOAD:%[^,]+]] = load_borrow [[TOKEN]]
824+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [[LOAD]]
825+
// CHECK: cond_br undef, {{bb[0-9]+}}, [[DIE:bb[0-9]+]]
826+
// CHECK: [[DIE]]:
827+
// CHECK-NEXT: end_borrow [[BORROW]]
828+
// CHECK-NEXT: end_borrow [[LOAD]]
829+
// CHECK-NEXT: end_borrow [[TOKEN]]
830+
// CHECK-NEXT: unreachable
831+
// CHECK-LABEL: } // end sil function 'load_borrow_of_store_borrow_1'
832+
// CHECK-LABEL: end running test {{.*}} on load_borrow_of_store_borrow_1: ossa_lifetime_completion
833+
sil [ossa] @load_borrow_of_store_borrow_1 : $@convention(thin) (@guaranteed C) -> () {
834+
entry(%instance : @guaranteed $C):
835+
specify_test "ossa_lifetime_completion %token availability"
836+
%addr = alloc_stack $C
837+
%token = store_borrow %instance to %addr : $*C
838+
%load = load_borrow %token : $*C
839+
%borrow = begin_borrow %load : $C
840+
cond_br undef, exit, die
841+
842+
exit:
843+
end_borrow %borrow : $C
844+
end_borrow %load : $C
845+
end_borrow %token : $*C
846+
dealloc_stack %addr : $*C
847+
%retval = tuple ()
848+
return %retval : $()
849+
die:
850+
unreachable
851+
}
852+
853+
// CHECK-LABEL: begin running test {{.*}} on load_borrow_of_store_borrow_2: ossa_lifetime_completion
854+
// CHECK-LABEL: sil [ossa] @load_borrow_of_store_borrow_2 : {{.*}} {
855+
// CHECK: [[TOKEN:%[^,]+]] = store_borrow
856+
// CHECK: [[LOAD:%[^,]+]] = load_borrow [[TOKEN]]
857+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [[LOAD]]
858+
// CHECK: cond_br undef, {{bb[0-9]+}}, [[DIE:bb[0-9]+]]
859+
// CHECK: [[DIE]]:
860+
// CHECK-NEXT: end_borrow [[BORROW]]
861+
// CHECK-NEXT: end_borrow [[LOAD]]
862+
// CHECK-NEXT: end_borrow [[TOKEN]]
863+
// CHECK-NEXT: unreachable
864+
// CHECK-LABEL: } // end sil function 'load_borrow_of_store_borrow_2'
865+
// CHECK-LABEL: end running test {{.*}} on load_borrow_of_store_borrow_2: ossa_lifetime_completion
866+
sil [ossa] @load_borrow_of_store_borrow_2 : $@convention(thin) (@guaranteed C) -> () {
867+
entry(%instance : @guaranteed $C):
868+
specify_test "ossa_lifetime_completion %token availability"
869+
%addr = alloc_stack $C
870+
%token = store_borrow %instance to %addr : $*C
871+
%load = load_borrow %token : $*C
872+
%borrow = begin_borrow %load : $C
873+
cond_br undef, exit, die
874+
875+
exit:
876+
end_borrow %borrow : $C
877+
end_borrow %load : $C
878+
end_borrow %token : $*C
879+
dealloc_stack %addr : $*C
880+
%retval = tuple ()
881+
return %retval : $()
882+
die:
883+
end_borrow %borrow : $C
884+
end_borrow %load : $C
885+
unreachable
886+
}
887+
888+
sil [ossa] @load_borrow_1 : $@convention(thin) (@in_guaranteed C) -> () {
889+
entry(%addr : $*C):
890+
specify_test "ossa_lifetime_completion %load availability"
891+
%load = load_borrow %addr : $*C
892+
%borrow = begin_borrow %load : $C
893+
cond_br undef, exit, die
894+
895+
exit:
896+
end_borrow %borrow : $C
897+
end_borrow %load : $C
898+
%retval = tuple ()
899+
return %retval : $()
900+
die:
901+
unreachable
902+
}
903+
820904
// CHECK-LABEL: begin running test {{.*}} on begin_access: ossa_lifetime_completion
821905
// CHECK-LABEL: sil [ossa] @begin_access : {{.*}} {
822906
// CHECK: [[TOKEN:%[^,]+]] = begin_access
@@ -841,3 +925,34 @@ exit:
841925
die:
842926
unreachable
843927
}
928+
929+
// CHECK-LABEL: begin running test {{.*}} on load_borrow_of_begin_access: ossa_lifetime_completion
930+
// CHECK-LABEL: sil [ossa] @load_borrow_of_begin_access : {{.*}} {
931+
// CHECK: [[ACCESS:%[^,]+]] = begin_access
932+
// CHECK: [[LOAD:%[^,]+]] = load_borrow [[ACCESS]]
933+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [[LOAD]]
934+
// CHECK: cond_br undef, {{bb[0-9]+}}, [[DIE:bb[0-9]+]]
935+
// CHECK: [[DIE]]:
936+
// CHECK-NEXT: end_borrow [[BORROW]]
937+
// CHECK-NEXT: end_borrow [[LOAD]]
938+
// CHECK-NEXT: end_access [[ACCESS]]
939+
// CHECK-NEXT: unreachable
940+
// CHECK-LABEL: } // end sil function 'load_borrow_of_begin_access'
941+
// CHECK-LABEL: end running test {{.*}} on load_borrow_of_begin_access: ossa_lifetime_completion
942+
sil [ossa] @load_borrow_of_begin_access : $@convention(thin) (@in_guaranteed C) -> () {
943+
entry(%addr : $*C):
944+
specify_test "ossa_lifetime_completion %access availability"
945+
%access = begin_access [static] [read] %addr : $*C
946+
%load = load_borrow %access : $*C
947+
%borrow = begin_borrow %load : $C
948+
cond_br undef, exit, die
949+
950+
exit:
951+
end_borrow %borrow : $C
952+
end_borrow %load : $C
953+
end_access %access : $*C
954+
%retval = tuple ()
955+
return %retval : $()
956+
die:
957+
unreachable
958+
}

0 commit comments

Comments
 (0)