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