Skip to content

Commit 99b9059

Browse files
committed
[PrunedLiveness] Branch summary merges to ending.
A branch instruction that is both a lifetime-ending user and also a non-lifetime-ending of a value should be regarded as a lifetime-ending user. Without this, utilities that rely on PrunedLiveness such as `LinearLiveness` and `InteriorLiveness` both incorrectly report that a branch featuring a value and also a reborrow or guaranteed phi are non-ending. rdar://130427564
1 parent 88445c5 commit 99b9059

File tree

4 files changed

+85
-4
lines changed

4 files changed

+85
-4
lines changed

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,43 @@ static FunctionTest
193193
// PrunedLiveRange
194194
//===----------------------------------------------------------------------===//
195195

196+
static PrunedLiveness::LifetimeEnding
197+
branchMeet(PrunedLiveness::LifetimeEnding const lhs,
198+
PrunedLiveness::LifetimeEnding const rhs) {
199+
enum BranchLifetimeEnding {
200+
Ending,
201+
NonEnding,
202+
NonUse,
203+
};
204+
auto toBranch =
205+
[](PrunedLiveness::LifetimeEnding const ending) -> BranchLifetimeEnding {
206+
switch (ending) {
207+
case PrunedLiveness::LifetimeEnding::Value::NonEnding:
208+
return NonEnding;
209+
case PrunedLiveness::LifetimeEnding::Value::Ending:
210+
return Ending;
211+
case PrunedLiveness::LifetimeEnding::Value::NonUse:
212+
return NonUse;
213+
}
214+
};
215+
auto toRegular =
216+
[](BranchLifetimeEnding const ending) -> PrunedLiveness::LifetimeEnding {
217+
switch (ending) {
218+
case NonEnding:
219+
return PrunedLiveness::LifetimeEnding::Value::NonEnding;
220+
case Ending:
221+
return PrunedLiveness::LifetimeEnding::Value::Ending;
222+
case NonUse:
223+
return PrunedLiveness::LifetimeEnding::Value::NonUse;
224+
}
225+
};
226+
return toRegular(std::min(toBranch(lhs), toBranch(rhs)));
227+
}
228+
static void branchMeetInPlace(PrunedLiveness::LifetimeEnding &that,
229+
PrunedLiveness::LifetimeEnding const other) {
230+
that = branchMeet(that, other);
231+
}
232+
196233
template <typename LivenessWithDefs>
197234
void PrunedLiveRange<LivenessWithDefs>::updateForUse(
198235
SILInstruction *user,
@@ -211,8 +248,13 @@ void PrunedLiveRange<LivenessWithDefs>::updateForUse(
211248
// This call is not considered the end of %val's lifetime. The @owned
212249
// argument must be copied.
213250
auto iterAndSuccess = users.insert({user, lifetimeEnding});
214-
if (!iterAndSuccess.second)
215-
iterAndSuccess.first->second.meetInPlace(lifetimeEnding);
251+
if (!iterAndSuccess.second) {
252+
if (isa<BranchInst>(user)) {
253+
branchMeetInPlace(iterAndSuccess.first->second, lifetimeEnding);
254+
} else {
255+
iterAndSuccess.first->second.meetInPlace(lifetimeEnding);
256+
}
257+
}
216258
}
217259
template <typename LivenessWithDefs>
218260
void PrunedLiveRange<LivenessWithDefs>::updateForUse(SILInstruction *user,

test/SILOptimizer/liveness_unit.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ bb1(%reborrow : @guaranteed $C, %phi : @guaranteed $PairC):
382382
// CHECK-LABEL: testSSAReborrowedPhi: ssa_liveness
383383
// CHECK: SSA lifetime analysis: %{{.*}} = begin_borrow
384384
// CHECK-NEXT: bb0: LiveWithin
385-
// CHECK-NEXT: regular user: br bb1
385+
// CHECK-NEXT: lifetime-ending user: br bb1
386386
// CHECK-NEXT: regular user: %{{.*}} = struct
387387
// CHECK-NEXT: last user: br bb1
388388
// CHECK-NEXT: end running

test/SILOptimizer/ossa_lifetime_completion.sil

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public enum FakeOptional<T> {
1919

2020
sil @swift_asyncLet_finish : $@convention(thin) @async (Builtin.RawPointer, Builtin.RawPointer) -> ()
2121
sil @swift_asyncLet_get : $@convention(thin) @async (Builtin.RawPointer, Builtin.RawPointer) -> ()
22+
sil @getC : $@convention(thin) () -> (@owned C)
2223

2324
protocol Error {}
2425

@@ -724,3 +725,41 @@ bb0(%existential : @owned $any P):
724725
%ref_existential = init_existential_ref %opened : $@opened("00000000-0000-0000-0000-000000000000", any P) Self : $@opened("00000000-0000-0000-0000-000000000000", any P) Self, $AnyObject
725726
return %ref_existential : $AnyObject
726727
}
728+
729+
// CHECK-LABEL: begin running test {{.*}} on root_of_reborrow: ossa_lifetime_completion
730+
// Verify that no instructions were inserted after backedge2's terminator. (In
731+
// fact, if they were, the test would crash.)
732+
// CHECK-LABEL: sil [ossa] @root_of_reborrow : {{.*}} {
733+
// CHECK: bb1([[C0:%[^,]+]] : @owned $C, [[B0:%[^,]+]] : @reborrow @guaranteed $C):
734+
// CHECK-NEXT: [[B0F:%[^,]+]] = borrowed [[B0]] : $C from ([[C0]] : $C)
735+
// CHECK-NEXT: end_borrow [[B0F]]
736+
// CHECK-NEXT: destroy_value [[C0]]
737+
// CHECK-NEXT: br
738+
// CHECK-LABEL: } // end sil function 'root_of_reborrow'
739+
// CHECK-LABEL: end running test {{.*}} on root_of_reborrow: ossa_lifetime_completion
740+
sil [ossa] @root_of_reborrow : $@convention(thin) () -> () {
741+
entry:
742+
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
743+
%c = apply %getC() : $@convention(thin) () -> (@owned C)
744+
%b = begin_borrow %c : $C
745+
br header(%c : $C, %b : $C)
746+
header(%c0 : @owned $C, %b0 : @reborrow @guaranteed $C):
747+
%b0f = borrowed %b0 : $C from (%c0 : $C)
748+
end_borrow %b0f : $C
749+
destroy_value %c0 : $C
750+
br body
751+
body:
752+
br latch
753+
latch:
754+
cond_br undef, backedge, exit
755+
backedge:
756+
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
757+
%b1 = begin_borrow %c1 : $C
758+
br backedge2(%c1 : $C, %b1 : $C)
759+
backedge2(%c2 : @owned $C, %b2 : @reborrow @guaranteed $C):
760+
%b2f = borrowed %b2 : $C from (%c2 : $C)
761+
specify_test "ossa_lifetime_completion %c2 availability"
762+
br header(%c2 : $C, %b2f : $C)
763+
exit:
764+
unreachable
765+
}

test/SILOptimizer/ownership_liveness_unit.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ bb1(%reborrow : @guaranteed $C):
606606
// CHECK: Interior liveness: %{{.*}} = begin_borrow %0 : $C
607607
// CHECK-NEXT: Inner scope: %{{.*}} = begin_borrow %{{.*}} : $D
608608
// CHECK-NEXT: bb0: LiveWithin
609-
// CHECK-NEXT: regular user: br bb1(%{{.*}} : $C, %{{.*}} : $D)
609+
// CHECK-NEXT: lifetime-ending user: br bb1(%{{.*}} : $C, %{{.*}} : $D)
610610
// CHECK-NEXT: regular user: %{{.*}} = unchecked_ref_cast %{{.*}} : $C to $D
611611
// CHECK-NEXT: Complete liveness
612612
// CHECK-NEXT: Unenclosed phis {

0 commit comments

Comments
 (0)