Skip to content

Commit 159259a

Browse files
Merge pull request #78034 from nate-chandler/rdar141037060
[OSSACompleteLifetime] Handle scoped addresses.
2 parents 56e292d + be7518b commit 159259a

File tree

6 files changed

+162
-28
lines changed

6 files changed

+162
-28
lines changed

include/swift/SIL/OSSALifetimeCompletion.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,20 +90,29 @@ class OSSALifetimeCompletion {
9090
///
9191
/// Returns true if any new instructions were created to complete the
9292
/// lifetime.
93-
///
94-
/// TODO: We also need to complete scoped addresses (e.g. store_borrow)!
9593
LifetimeCompletion completeOSSALifetime(SILValue value, Boundary boundary) {
96-
if (value->getOwnershipKind() == OwnershipKind::None)
97-
return LifetimeCompletion::NoLifetime;
98-
99-
if (value->getOwnershipKind() != OwnershipKind::Owned) {
94+
switch (value->getOwnershipKind()) {
95+
case OwnershipKind::None: {
96+
auto scopedAddress = ScopedAddressValue(value);
97+
if (!scopedAddress)
98+
return LifetimeCompletion::NoLifetime;
99+
break;
100+
}
101+
case OwnershipKind::Owned:
102+
break;
103+
case OwnershipKind::Any:
104+
llvm::report_fatal_error("value with any ownership kind!?");
105+
case OwnershipKind::Guaranteed:
106+
case OwnershipKind::Unowned: {
100107
BorrowedValue borrowedValue(value);
101108
if (!borrowedValue)
102109
return LifetimeCompletion::NoLifetime;
103110

104111
if (!borrowedValue.isLocalScope())
105112
return LifetimeCompletion::AlreadyComplete;
106113
}
114+
}
115+
107116
if (!completedValues.insert(value))
108117
return LifetimeCompletion::AlreadyComplete;
109118

include/swift/SIL/ScopedAddressUtils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ struct ScopedAddressValue {
122122
AddressUseKind updateTransitiveLiveness(SSAPrunedLiveness &liveness) const;
123123

124124
/// Create appropriate scope ending instruction at \p insertPt.
125-
void createScopeEnd(SILBasicBlock::iterator insertPt, SILLocation loc) const;
125+
SILInstruction *createScopeEnd(SILBasicBlock::iterator insertPt,
126+
SILLocation loc) const;
126127

127128
/// Create scope ending instructions at \p liveness boundary.
128129
void endScopeAtLivenessBoundary(SSAPrunedLiveness *liveness) const;

lib/SIL/Utils/OSSALifetimeCompletion.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ static SILInstruction *endOSSALifetime(SILValue value,
7676
}
7777
return builder.createDestroyValue(loc, value, DontPoisonRefs, isDeadEnd);
7878
}
79+
if (auto scopedAddress = ScopedAddressValue(value)) {
80+
return scopedAddress.createScopeEnd(builder.getInsertionPoint(), loc);
81+
}
7982
return builder.createEndBorrow(loc, lookThroughBorrowedFromUser(value));
8083
}
8184

@@ -419,36 +422,49 @@ static bool endLifetimeAtAvailabilityBoundary(SILValue value,
419422
return changed;
420423
}
421424

425+
static bool endLifetimeAtBoundary(SILValue value,
426+
SSAPrunedLiveness const &liveness,
427+
OSSALifetimeCompletion::Boundary boundary,
428+
DeadEndBlocks &deadEndBlocks) {
429+
bool changed = false;
430+
switch (boundary) {
431+
case OSSALifetimeCompletion::Boundary::Liveness:
432+
changed |= endLifetimeAtLivenessBoundary(value, liveness, deadEndBlocks);
433+
break;
434+
case OSSALifetimeCompletion::Boundary::Availability:
435+
changed |=
436+
endLifetimeAtAvailabilityBoundary(value, liveness, deadEndBlocks);
437+
break;
438+
}
439+
return changed;
440+
}
441+
422442
/// End the lifetime of \p value at unreachable instructions.
423443
///
424444
/// Returns true if any new instructions were created to complete the lifetime.
425445
bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(SILValue value,
426446
Boundary boundary) {
447+
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);
452+
}
453+
427454
// Called for inner borrows, inner adjacent reborrows, inner reborrows, and
428455
// scoped addresses.
429456
auto handleInnerScope = [this, boundary](SILValue innerBorrowedValue) {
430457
completeOSSALifetime(innerBorrowedValue, boundary);
431458
};
432459
InteriorLiveness liveness(value);
433460
liveness.compute(domInfo, handleInnerScope);
434-
435-
bool changed = false;
436-
switch (boundary) {
437-
case Boundary::Liveness:
438-
changed |= endLifetimeAtLivenessBoundary(value, liveness.getLiveness(),
439-
deadEndBlocks);
440-
break;
441-
case Boundary::Availability:
442-
changed |= endLifetimeAtAvailabilityBoundary(value, liveness.getLiveness(),
443-
deadEndBlocks);
444-
break;
445-
}
446461
// TODO: Rebuild outer adjacent phis on demand (SILGen does not currently
447462
// produce guaranteed phis). See FindEnclosingDefs &
448463
// findSuccessorDefsFromPredDefs. If no enclosing phi is found, we can create
449464
// it here and use updateSSA to recursively populate phis.
450465
assert(liveness.getUnenclosedPhis().empty());
451-
return changed;
466+
return endLifetimeAtBoundary(value, liveness.getLiveness(), boundary,
467+
deadEndBlocks);
452468
}
453469

454470
namespace swift::test {

lib/SIL/Utils/ScopedAddressUtils.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,15 @@ AddressUseKind ScopedAddressValue::updateTransitiveLiveness(
151151
return addressKind;
152152
}
153153

154-
void ScopedAddressValue::createScopeEnd(SILBasicBlock::iterator insertPt,
155-
SILLocation loc) const {
154+
SILInstruction *
155+
ScopedAddressValue::createScopeEnd(SILBasicBlock::iterator insertPt,
156+
SILLocation loc) const {
156157
switch (kind) {
157158
case ScopedAddressValueKind::StoreBorrow: {
158-
SILBuilderWithScope(insertPt).createEndBorrow(loc, value);
159-
return;
159+
return SILBuilderWithScope(insertPt).createEndBorrow(loc, value);
160160
}
161161
case ScopedAddressValueKind::BeginAccess: {
162-
SILBuilderWithScope(insertPt).createEndAccess(loc, value, false);
163-
return;
162+
return SILBuilderWithScope(insertPt).createEndAccess(loc, value, false);
164163
}
165164
case ScopedAddressValueKind::Invalid:
166165
llvm_unreachable("Using invalid case?!");

test/SILOptimizer/ossa_lifetime_completion.sil

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,3 +792,52 @@ bb3:
792792
return %0 : $C
793793
}
794794

795+
// CHECK-LABEL: begin running test {{.*}} on store_borrow: ossa_lifetime_completion
796+
// CHECK-LABEL: sil [ossa] @store_borrow : {{.*}} {
797+
// CHECK: [[TOKEN:%[^,]+]] = store_borrow
798+
// CHECK: cond_br undef, {{bb[0-9]+}}, [[DIE:bb[0-9]+]]
799+
// CHECK: [[DIE]]:
800+
// CHECK-NEXT: end_borrow [[TOKEN]]
801+
// CHECK-NEXT: unreachable
802+
// CHECK-LABEL: } // end sil function 'store_borrow'
803+
// CHECK-LABEL: end running test {{.*}} on store_borrow: ossa_lifetime_completion
804+
sil [ossa] @store_borrow : $@convention(thin) (@guaranteed C) -> () {
805+
entry(%instance : @guaranteed $C):
806+
specify_test "ossa_lifetime_completion %token availability"
807+
%addr = alloc_stack $C
808+
%token = store_borrow %instance to %addr : $*C
809+
cond_br undef, exit, die
810+
811+
exit:
812+
end_borrow %token : $*C
813+
dealloc_stack %addr : $*C
814+
%retval = tuple ()
815+
return %retval : $()
816+
die:
817+
unreachable
818+
}
819+
820+
// CHECK-LABEL: begin running test {{.*}} on begin_access: ossa_lifetime_completion
821+
// CHECK-LABEL: sil [ossa] @begin_access : {{.*}} {
822+
// CHECK: [[TOKEN:%[^,]+]] = begin_access
823+
// CHECK: cond_br undef, {{bb[0-9]+}}, [[DIE:bb[0-9]+]]
824+
// CHECK: [[DIE]]:
825+
// CHECK-NEXT: end_access [[TOKEN]]
826+
// CHECK-NEXT: unreachable
827+
// CHECK-LABEL: } // end sil function 'begin_access'
828+
// CHECK-LABEL: end running test {{.*}} on begin_access: ossa_lifetime_completion
829+
sil [ossa] @begin_access : $@convention(thin) (@guaranteed C) -> () {
830+
entry(%instance : @guaranteed $C):
831+
specify_test "ossa_lifetime_completion %access availability"
832+
%addr = alloc_stack $C
833+
%access = begin_access [static] [read] %addr : $*C
834+
cond_br undef, exit, die
835+
836+
exit:
837+
end_access %access : $*C
838+
dealloc_stack %addr : $*C
839+
%retval = tuple ()
840+
return %retval : $()
841+
die:
842+
unreachable
843+
}

test/SILOptimizer/silgen_cleanup_complete_ossa.sil

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class Klass {
1111
}
1212
class SubKlass : Klass {}
1313

14+
class C {}
15+
1416
enum FakeOptional<T> {
1517
case none
1618
case some(T)
@@ -32,14 +34,15 @@ protocol P : AnyObject {}
3234

3335
sil @unreachableHandler : $@convention(thin) () -> ()
3436

35-
// CHECK-LABEL: sil [ossa] @testCompleteOSSALifetimes : $@convention(thin) (@owned FakeOptional<Klass>) -> () {
37+
// CHECK-LABEL: sil [ossa] @testCompleteOSSALifetimes : {{.*}} {
3638
// CHECK: [[BOX:%.*]] = alloc_box ${ var FakeOptional<Klass> }, var, name "c"
3739
// CHECK: [[BORROW:%.,*]] = begin_borrow [lexical] [[BOX]] : ${ var FakeOptional<Klass> }
3840
// CHECK: bb2:
3941
// CHECK: apply
4042
// CHECK: end_borrow [[BORROW]] : ${ var FakeOptional<Klass> }
4143
// CHECK: dealloc_box [dead_end] [[BOX]] : ${ var FakeOptional<Klass> }
4244
// CHECK: unreachable
45+
// CHECK-LABEL: } // end sil function 'testCompleteOSSALifetimes'
4346
sil [ossa] @testCompleteOSSALifetimes : $@convention(thin) (@owned FakeOptional<Klass>) -> () {
4447
bb0(%0 : @owned $FakeOptional<Klass>):
4548
%box = alloc_box ${ var FakeOptional<Klass> }, var, name "c"
@@ -73,11 +76,68 @@ bb5:
7376
return %36 : $()
7477
}
7578

76-
// CHECK-LABEL: sil [ossa] @testExistentialLifetime : $@convention(thin) (@owned any P) -> @owned AnyObject {
79+
// CHECK-LABEL: sil [ossa] @testExistentialLifetime : {{.*}} {
7780
// CHECK-NOT: destroy
81+
// CHECK-LABEL: } // end sil function 'testExistentialLifetime'
7882
sil [ossa] @testExistentialLifetime : $@convention(thin) (@owned any P) -> @owned AnyObject {
7983
bb0(%0 : @owned $any P):
8084
%1 = open_existential_ref %0 : $any P to $@opened("34B79428-2E49-11ED-901A-8AC134504E1C", any P) Self
8185
%2 = init_existential_ref %1 : $@opened("34B79428-2E49-11ED-901A-8AC134504E1C", any P) Self : $@opened("34B79428-2E49-11ED-901A-8AC134504E1C", any P) Self, $AnyObject
8286
return %2 : $AnyObject
8387
}
88+
89+
// CHECK-LABEL: sil [ossa] @store_borrow : {{.*}} {
90+
// CHECK: bb0([[INSTANCE:%[^,]+]] :
91+
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $C
92+
// CHECK: [[TOKEN:%[^,]+]] = store_borrow [[INSTANCE]] to [[ADDR]]
93+
// CHECK: [[LOAD:%[^,]+]] = load_borrow [[TOKEN]]
94+
// CHECK: cond_br undef, {{bb[0-9]+}}, [[DIE:bb[0-9]+]]
95+
// CHECK: [[DIE]]:
96+
// CHECK: end_borrow [[LOAD]]
97+
// CHECK: end_borrow [[TOKEN]]
98+
// CHECK: destroy_value [dead_end] [[INSTANCE]]
99+
// CHECK: unreachable
100+
// CHECK-LABEL: } // end sil function 'store_borrow'
101+
sil [ossa] @store_borrow : $@convention(thin) (@owned C) -> () {
102+
entry(%instance : @owned $C):
103+
%addr = alloc_stack $C
104+
%token = store_borrow %instance to %addr : $*C
105+
%load = load_borrow %token : $*C
106+
cond_br undef, exit, die
107+
exit:
108+
end_borrow %load : $C
109+
end_borrow %token : $*C
110+
dealloc_stack %addr : $*C
111+
apply undef(%instance) : $@convention(thin) (@guaranteed C) -> ()
112+
destroy_value %instance : $C
113+
%retval = tuple ()
114+
return %retval : $()
115+
die:
116+
unreachable
117+
}
118+
119+
// CHECK-LABEL: sil [ossa] @begin_access : {{.*}} {
120+
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $C
121+
// CHECK: [[ACCESS:%[^,]+]] = begin_access [modify] [static] [[ADDR]]
122+
// CHECK: cond_br undef, {{bb[0-9]+}}, [[DIE:bb[0-9]+]]
123+
// CHECK: [[DIE]]:
124+
// CHECK: end_access [[ACCESS]]
125+
// CHECK: unreachable
126+
// CHECK-LABEL: } // end sil function 'begin_access'
127+
sil [ossa] @begin_access : $@convention(thin) () -> () {
128+
entry:
129+
%addr2 = alloc_stack $C
130+
%access = begin_access [static] [modify] %addr2 : $*C
131+
apply undef(%access) : $@convention(thin) () -> (@out C)
132+
destroy_addr %access : $*C
133+
cond_br undef, exit, die
134+
135+
exit:
136+
end_access %access : $*C
137+
dealloc_stack %addr2 : $*C
138+
%retval = tuple ()
139+
return %retval : $()
140+
141+
die:
142+
unreachable
143+
}

0 commit comments

Comments
 (0)