1; A collection of liveness test cases to ensure we're reporting the
2; correct live values at statepoints
3; RUN: opt -rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S < %s | FileCheck %s
4; RUN: opt -passes=rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S < %s | FileCheck %s
5
6; Tests to make sure we consider %obj live in both the taken and untaken
7; predeccessor of merge.
8
9define i64 addrspace(1)* @test1(i1 %cmp, i64 addrspace(1)* %obj) gc "statepoint-example" {
10; CHECK-LABEL: @test1
11entry:
12  br i1 %cmp, label %taken, label %untaken
13
14taken:                                            ; preds = %entry
15; CHECK-LABEL: taken:
16; CHECK-NEXT: gc.statepoint
17; CHECK-NEXT: %obj.relocated = call coldcc i8 addrspace(1)*
18; CHECK-NEXT: bitcast
19; CHECK-NEXT: br label %merge
20  call void @foo() [ "deopt"() ]
21  br label %merge
22
23untaken:                                          ; preds = %entry
24; CHECK-LABEL: untaken:
25; CHECK-NEXT: gc.statepoint
26; CHECK-NEXT: %obj.relocated2 = call coldcc i8 addrspace(1)*
27; CHECK-NEXT: bitcast
28; CHECK-NEXT: br label %merge
29  call void @foo() [ "deopt"() ]
30  br label %merge
31
32merge:                                            ; preds = %untaken, %taken
33; CHECK-LABEL: merge:
34; CHECK-NEXT: %.0 = phi i64 addrspace(1)* [ %obj.relocated.casted, %taken ], [ %obj.relocated2.casted, %untaken ]
35; CHECK-NEXT: ret i64 addrspace(1)* %.0
36; A local kill should not effect liveness in predecessor block
37  ret i64 addrspace(1)* %obj
38}
39
40define i64 addrspace(1)* @test2(i1 %cmp, i64 addrspace(1)** %loc) gc "statepoint-example" {
41; CHECK-LABEL: @test2
42entry:
43; CHECK-LABEL: entry:
44; CHECK-NEXT:  gc.statepoint
45; CHECK-NEXT:  br
46  call void @foo() [ "deopt"() ]
47  br i1 %cmp, label %taken, label %untaken
48
49taken:                                            ; preds = %entry
50; CHECK-LABEL: taken:
51; CHECK-NEXT:  %obj = load
52; CHECK-NEXT:  gc.statepoint
53; CHECK-NEXT:  gc.relocate
54; CHECK-NEXT: bitcast
55; CHECK-NEXT:  ret i64 addrspace(1)* %obj.relocated.casted
56; A local kill should effect values live from a successor phi.  Also, we
57; should only propagate liveness from a phi to the appropriate predecessors.
58  %obj = load i64 addrspace(1)*, i64 addrspace(1)** %loc
59  call void @foo() [ "deopt"() ]
60  ret i64 addrspace(1)* %obj
61
62untaken:                                          ; preds = %entry
63  ret i64 addrspace(1)* null
64}
65
66define i64 addrspace(1)* @test3(i1 %cmp, i64 addrspace(1)** %loc) gc "statepoint-example" {
67; CHECK-LABEL: @test3
68entry:
69  br i1 %cmp, label %taken, label %untaken
70
71taken:                                            ; preds = %entry
72; CHECK-LABEL: taken:
73; CHECK-NEXT: gc.statepoint
74; CHECK-NEXT: %obj = load
75; CHECK-NEXT: gc.statepoint
76; CHECK-NEXT: %obj.relocated = call coldcc i8 addrspace(1)*
77; CHECK-NEXT: bitcast
78; CHECK-NEXT: br label %merge
79  call void @foo() [ "deopt"() ]
80  %obj = load i64 addrspace(1)*, i64 addrspace(1)** %loc
81  call void @foo() [ "deopt"() ]
82  br label %merge
83
84untaken:                                          ; preds = %entry
85; CHECK-LABEL: taken:
86; CHECK-NEXT: gc.statepoint
87; CHECK-NEXT: br label %merge
88; A base pointer must be live if it is needed at a later statepoint,
89; even if the base pointer is otherwise unused.
90  call void @foo() [ "deopt"() ]
91  br label %merge
92
93merge:                                            ; preds = %untaken, %taken
94  %phi = phi i64 addrspace(1)* [ %obj, %taken ], [ null, %untaken ]
95  ret i64 addrspace(1)* %phi
96}
97
98define i64 addrspace(1)* @test4(i1 %cmp, i64 addrspace(1)* %obj) gc "statepoint-example" {
99; CHECK-LABEL: @test4
100entry:
101; CHECK-LABEL: entry:
102; CHECK-NEXT:  %derived = getelementptr
103; CHECK-NEXT:  gc.statepoint
104; CHECK-NEXT:  %derived.relocated =
105; CHECK-NEXT:  bitcast
106; CHECK-NEXT:  %obj.relocated =
107; CHECK-NEXT:  bitcast
108; CHECK-NEXT:  gc.statepoint
109; CHECK-NEXT:  %derived.relocated2 =
110; CHECK-NEXT:  bitcast
111
112; Note: It's legal to relocate obj again, but not strictly needed
113; CHECK-NEXT:  %obj.relocated3 =
114; CHECK-NEXT:  bitcast
115; CHECK-NEXT:  ret i64 addrspace(1)* %derived.relocated2.casted
116;
117; Make sure that a phi def visited during iteration is considered a kill.
118; Also, liveness after base pointer analysis can change based on new uses,
119; not just new defs.
120  %derived = getelementptr i64, i64 addrspace(1)* %obj, i64 8
121  call void @foo() [ "deopt"() ]
122  call void @foo() [ "deopt"() ]
123  ret i64 addrspace(1)* %derived
124}
125
126declare void @consume(...) readonly "gc-leaf-function"
127
128define i64 addrspace(1)* @test5(i1 %cmp, i64 addrspace(1)* %obj) gc "statepoint-example" {
129; CHECK-LABEL: @test5
130entry:
131  br i1 %cmp, label %taken, label %untaken
132
133taken:                                            ; preds = %entry
134; CHECK-LABEL: taken:
135; CHECK-NEXT: gc.statepoint
136; CHECK-NEXT: %obj.relocated = call coldcc i8 addrspace(1)*
137; CHECK-NEXT: bitcast
138; CHECK-NEXT: br label %merge
139  call void @foo() [ "deopt"() ]
140  br label %merge
141
142untaken:                                          ; preds = %entry
143; CHECK-LABEL: untaken:
144; CHECK-NEXT: br label %merge
145  br label %merge
146
147merge:                                            ; preds = %untaken, %taken
148; CHECK-LABEL: merge:
149; CHECK-NEXT: %.0 = phi i64 addrspace(1)*
150; CHECK-NEXT: %obj2a = phi
151; CHECK-NEXT: @consume
152; CHECK-NEXT: br label %final
153  %obj2a = phi i64 addrspace(1)* [ %obj, %taken ], [ null, %untaken ]
154  call void (...) @consume(i64 addrspace(1)* %obj2a)
155  br label %final
156
157final:                                            ; preds = %merge
158; CHECK-LABEL: final:
159; CHECK-NEXT: @consume
160; CHECK-NEXT: ret i64 addrspace(1)* %.0
161  call void (...) @consume(i64 addrspace(1)* %obj2a)
162  ret i64 addrspace(1)* %obj
163}
164
165declare void @foo()
166
167