Skip to content

Commit 3b5e198

Browse files
committed
Add OSSA liveness tests for incomplete lifetimes
These tests all involve unreachable terminators.
1 parent 6daebfd commit 3b5e198

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// RUN: %target-sil-opt %s -ossa-lifetime-analysis -o /dev/null | %FileCheck %s
2+
//
3+
// These tests rely on "incomplete" OSSA lifetimes. Incomplete OSSA
4+
// lifetimes are invalid SIL, but the OSSA liveness utilities still
5+
// need to handle them! SILGen and textual SIL is allowed to produce
6+
// incomplete lifetimes. The OSSA liveness utilities need to be able
7+
// to fixup those incomplete lifetimes. So the utilities need to
8+
// handle invalid SIL in order to produce valid SIL.
9+
10+
sil_stage canonical
11+
12+
import Builtin
13+
14+
enum FakeOptional<T> {
15+
case none
16+
case some(T)
17+
}
18+
19+
enum Never {}
20+
21+
class C {}
22+
23+
// CHECK-LABEL: @testDeadTerminatorResult
24+
// CHECK-LABEL: SSA lifetime analysis: %{{.*}} = argument of bb1 : $C
25+
// CHECK: bb1: LiveWithin
26+
// CHECK-NOT: "last user"
27+
// CHECK-NOT: "boundary edge"
28+
// CHECK: dead def: %{{.*}} = argument of bb1 : $C
29+
sil [ossa] @testDeadTerminatorResult : $@convention(thin) (@owned FakeOptional<C>) -> () {
30+
bb0(%0 : @owned $FakeOptional<C>):
31+
switch_enum %0 : $FakeOptional<C>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
32+
33+
bb1(%payload : @owned $C):
34+
debug_value [trace] %payload : $C
35+
unreachable
36+
37+
bb2:
38+
%99 = tuple()
39+
return %99 : $()
40+
}
41+
42+
// CHECK-LABEL: @testDeadPhi
43+
// CHECK: SSA lifetime analysis: %{{.*}} = argument of bb3 : $C
44+
// CHECK: bb3: LiveWithin
45+
// CHECK: dead def: %{{.*}} = argument of bb3 : $C
46+
sil [ossa] @testDeadPhi : $@convention(thin) (@owned C, @owned C) -> () {
47+
bb0(%0 : @owned $C, %1 : @owned $C):
48+
cond_br undef, bb1, bb2
49+
50+
bb1:
51+
br bb3(%0 : $C)
52+
53+
bb2:
54+
br bb3(%1 : $C)
55+
56+
bb3(%2 : @owned $C):
57+
debug_value [trace] %2 : $C
58+
unreachable
59+
}
60+
61+
// CHECK-LABEL: @testDeadInstruction
62+
// CHECK: SSA lifetime analysis: %{{.*}} = copy_value %0 : $C
63+
// CHECK: bb0: LiveWithin
64+
// CHECK: dead def: %{{.*}} = copy_value %0 : $C
65+
sil [ossa] @testDeadInstruction : $@convention(thin) (@guaranteed C) -> () {
66+
bb0(%0 : @guaranteed $C):
67+
%1 = copy_value %0 : $C
68+
debug_value [trace] %1 : $C
69+
unreachable
70+
}
71+
72+
// A single instruction occurs twice on the same liveness
73+
// boundary. Once as a last use, and once as a dead def.
74+
// This is a particularly problematic corner case.
75+
//
76+
// CHECK-LABEL: @testDeadSelfKill
77+
// CHECK: MultiDef lifetime analysis:
78+
// CHECK: def: %1 = argument of bb1 : $C
79+
// CHECK: def: [[V:%.*]] = move_value %1 : $C
80+
// CHECK: bb1: LiveWithin
81+
// CHECK: lifetime-ending user: [[V]] = move_value %1 : $C
82+
// CHECK: last user: [[V]] = move_value %1 : $C
83+
// CHECK: dead def: [[V]] = move_value %1 : $C
84+
sil [ossa] @testDeadSelfKill : $@convention(thin) () -> () {
85+
bb0:
86+
br bb3
87+
88+
bb1(%1 : @owned $C):
89+
debug_value [trace] %1 : $C
90+
%2 = move_value %1 : $C
91+
debug_value [trace] %2 : $C
92+
unreachable
93+
94+
bb3:
95+
%99 = tuple()
96+
return %99 : $()
97+
}
98+
99+
sil @genericReturn : $@convention(thin) <τ_0_0> (@guaranteed C) -> @out τ_0_0
100+
101+
// The store_borrow scope has an inner load_borrow scope, which is
102+
// incomplete. Since the store_borrow produces an address, the load
103+
// borrow is considered a ScopedAddressUse, and all of its uses,
104+
// including the Apply will contribute to the store_borrow liveness.
105+
// CHECK-LABEL: @testInnerUnreachable
106+
// CHECK: Scoped address analysis: [[SB:%.*]] = store_borrow %0
107+
// CHECK: bb0: LiveWithin
108+
// CHECK-NEXT: regular user: %{{.*}} = apply
109+
// CHECK-NEXT: last user: %{{.*}} = apply
110+
sil shared [ossa] @testInnerUnreachable : $@convention(thin) (@guaranteed C, @thick Never.Type) -> () {
111+
bb0(%0 : @guaranteed $C, %1 : $@thick Never.Type):
112+
%2 = alloc_stack $C
113+
%3 = store_borrow %0 to %2 : $*C
114+
debug_value [trace] %3 : $*C
115+
%5 = load_borrow %3 : $*C
116+
%6 = function_ref @genericReturn : $@convention(thin) <τ_0_0> (@guaranteed C) -> @out τ_0_0
117+
%7 = alloc_stack $Never
118+
%8 = apply %6<Never>(%7, %5) : $@convention(thin) <τ_0_0> (@guaranteed C) -> @out τ_0_0
119+
unreachable
120+
}

0 commit comments

Comments
 (0)