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