1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc < %s -mtriple=sparc -verify-machineinstrs | FileCheck %s --check-prefix=V8
3 ; RUN: llc < %s -mtriple=sparcv9 -verify-machineinstrs | FileCheck %s --check-prefix=V9
5 define i32 @simple_leaf(i32 %i) #0 {
6 ; V8-LABEL: simple_leaf:
7 ; V8: ! %bb.0: ! %entry
8 ; V8-NEXT: mov %o7, %g1
10 ; V8-NEXT: mov %g1, %o7
12 ; V9-LABEL: simple_leaf:
13 ; V9: ! %bb.0: ! %entry
14 ; V9-NEXT: mov %o7, %g1
16 ; V9-NEXT: mov %g1, %o7
18 %call = tail call i32 @foo(i32 %i)
22 define i32 @simple_standard(i32 %i) #1 {
23 ; V8-LABEL: simple_standard:
24 ; V8: ! %bb.0: ! %entry
25 ; V8-NEXT: save %sp, -96, %sp
29 ; V9-LABEL: simple_standard:
30 ; V9: ! %bb.0: ! %entry
31 ; V9-NEXT: save %sp, -128, %sp
35 %call = tail call i32 @foo(i32 %i)
39 define i32 @extra_arg_leaf(i32 %i) #0 {
40 ; V8-LABEL: extra_arg_leaf:
41 ; V8: ! %bb.0: ! %entry
42 ; V8-NEXT: mov 12, %o1
43 ; V8-NEXT: mov %o7, %g1
45 ; V8-NEXT: mov %g1, %o7
47 ; V9-LABEL: extra_arg_leaf:
48 ; V9: ! %bb.0: ! %entry
49 ; V9-NEXT: mov 12, %o1
50 ; V9-NEXT: mov %o7, %g1
52 ; V9-NEXT: mov %g1, %o7
54 %call = tail call i32 @foo2(i32 %i, i32 12)
58 define i32 @extra_arg_standard(i32 %i) #1 {
59 ; V8-LABEL: extra_arg_standard:
60 ; V8: ! %bb.0: ! %entry
61 ; V8-NEXT: save %sp, -96, %sp
63 ; V8-NEXT: restore %g0, 12, %o1
65 ; V9-LABEL: extra_arg_standard:
66 ; V9: ! %bb.0: ! %entry
67 ; V9-NEXT: save %sp, -128, %sp
69 ; V9-NEXT: restore %g0, 12, %o1
71 %call = tail call i32 @foo2(i32 %i, i32 12)
75 ; Perform tail call optimization for external symbol.
77 define void @caller_extern(ptr %src) optsize #0 {
78 ; V8-LABEL: caller_extern:
79 ; V8: ! %bb.0: ! %entry
80 ; V8-NEXT: sethi %hi(dest), %o1
81 ; V8-NEXT: add %o1, %lo(dest), %o1
83 ; V8-NEXT: mov %o0, %o3
84 ; V8-NEXT: mov %o1, %o0
85 ; V8-NEXT: mov %o3, %o1
86 ; V8-NEXT: mov %o7, %g1
87 ; V8-NEXT: call memcpy
88 ; V8-NEXT: mov %g1, %o7
90 ; V9-LABEL: caller_extern:
91 ; V9: ! %bb.0: ! %entry
92 ; V9-NEXT: sethi %h44(dest), %o1
93 ; V9-NEXT: add %o1, %m44(dest), %o1
94 ; V9-NEXT: sllx %o1, 12, %o1
95 ; V9-NEXT: add %o1, %l44(dest), %o1
97 ; V9-NEXT: mov %o0, %o3
98 ; V9-NEXT: mov %o1, %o0
99 ; V9-NEXT: mov %o3, %o1
100 ; V9-NEXT: mov %o7, %g1
101 ; V9-NEXT: call memcpy
102 ; V9-NEXT: mov %g1, %o7
104 tail call void @llvm.memcpy.p0.p0.i32(
106 ptr %src, i32 7, i1 false)
110 ; Perform tail call optimization for function pointer.
112 define i32 @func_ptr_test(ptr nocapture %func_ptr) #0 {
113 ; V8-LABEL: func_ptr_test:
114 ; V8: ! %bb.0: ! %entry
118 ; V9-LABEL: func_ptr_test:
119 ; V9: ! %bb.0: ! %entry
123 %call = tail call i32 %func_ptr() #1
127 define i32 @func_ptr_test2(ptr nocapture %func_ptr,
128 ; V8-LABEL: func_ptr_test2:
129 ; V8: ! %bb.0: ! %entry
130 ; V8-NEXT: save %sp, -96, %sp
131 ; V8-NEXT: mov 10, %i3
132 ; V8-NEXT: mov %i0, %i4
133 ; V8-NEXT: mov %i1, %i0
135 ; V8-NEXT: restore %g0, %i3, %o1
137 ; V9-LABEL: func_ptr_test2:
138 ; V9: ! %bb.0: ! %entry
139 ; V9-NEXT: save %sp, -128, %sp
140 ; V9-NEXT: mov 10, %i3
141 ; V9-NEXT: mov %i0, %i4
142 ; V9-NEXT: mov %i1, %i0
144 ; V9-NEXT: restore %g0, %i3, %o1
147 %call = tail call i32 %func_ptr(i32 %r, i32 10, i32 %q) #1
152 ; Do not tail call optimize if stack is used to pass parameters.
154 define i32 @caller_args() #0 {
155 ; V8-LABEL: caller_args:
156 ; V8: ! %bb.0: ! %entry
157 ; V8-NEXT: save %sp, -104, %sp
158 ; V8-NEXT: mov 6, %i0
159 ; V8-NEXT: mov 1, %o1
160 ; V8-NEXT: mov 2, %o2
161 ; V8-NEXT: mov 3, %o3
162 ; V8-NEXT: mov 4, %o4
163 ; V8-NEXT: mov 5, %o5
164 ; V8-NEXT: st %i0, [%sp+92]
166 ; V8-NEXT: mov %g0, %o0
168 ; V8-NEXT: restore %g0, %o0, %o0
170 ; V9-LABEL: caller_args:
171 ; V9: ! %bb.0: ! %entry
172 ; V9-NEXT: save %sp, -192, %sp
173 ; V9-NEXT: mov 6, %i0
174 ; V9-NEXT: mov 1, %o1
175 ; V9-NEXT: mov 2, %o2
176 ; V9-NEXT: mov 3, %o3
177 ; V9-NEXT: mov 4, %o4
178 ; V9-NEXT: mov 5, %o5
179 ; V9-NEXT: stx %i0, [%sp+2223]
181 ; V9-NEXT: mov %g0, %o0
183 ; V9-NEXT: restore %g0, %o0, %o0
185 %r = tail call i32 @foo7(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
189 ; Byval parameters hand the function a pointer directly into the stack area
190 ; we want to reuse during a tail call. Do not tail call optimize functions with
193 define i32 @caller_byval() #0 {
194 ; V8-LABEL: caller_byval:
195 ; V8: ! %bb.0: ! %entry
196 ; V8-NEXT: save %sp, -104, %sp
197 ; V8-NEXT: ld [%fp+-4], %i0
198 ; V8-NEXT: st %i0, [%fp+-8]
199 ; V8-NEXT: call callee_byval
200 ; V8-NEXT: add %fp, -8, %o0
202 ; V8-NEXT: restore %g0, %o0, %o0
204 ; V9-LABEL: caller_byval:
205 ; V9: ! %bb.0: ! %entry
206 ; V9-NEXT: save %sp, -192, %sp
207 ; V9-NEXT: call callee_byval
208 ; V9-NEXT: add %fp, 2039, %o0
210 ; V9-NEXT: restore %g0, %o0, %o0
213 %r = tail call i32 @callee_byval(ptr byval(ptr) %a)
217 ; Perform tail call optimization for sret function.
219 define void @sret_test(ptr noalias sret(%struct.a) %agg.result) #0 {
220 ; V8-LABEL: sret_test:
221 ; V8: ! %bb.0: ! %entry
222 ; V8-NEXT: mov %o7, %g1
223 ; V8-NEXT: call sret_func
224 ; V8-NEXT: mov %g1, %o7
226 ; V9-LABEL: sret_test:
227 ; V9: ! %bb.0: ! %entry
228 ; V9-NEXT: mov %o7, %g1
229 ; V9-NEXT: call sret_func
230 ; V9-NEXT: mov %g1, %o7
232 tail call void @sret_func(ptr sret(%struct.a) %agg.result)
236 ; Do not tail call if either caller or callee returns
237 ; a struct and the other does not. Returning a large
238 ; struct will generate a memcpy as the tail function.
240 define void @ret_large_struct(ptr noalias sret(%struct.big) %agg.result) #0 {
241 ; V8-LABEL: ret_large_struct:
242 ; V8: ! %bb.0: ! %entry
243 ; V8-NEXT: save %sp, -96, %sp
244 ; V8-NEXT: ld [%fp+64], %i0
245 ; V8-NEXT: sethi %hi(bigstruct), %i1
246 ; V8-NEXT: add %i1, %lo(bigstruct), %o1
247 ; V8-NEXT: mov 400, %o2
248 ; V8-NEXT: call memcpy
249 ; V8-NEXT: mov %i0, %o0
250 ; V8-NEXT: jmp %i7+12
253 ; V9-LABEL: ret_large_struct:
254 ; V9: ! %bb.0: ! %entry
255 ; V9-NEXT: save %sp, -176, %sp
256 ; V9-NEXT: sethi %h44(bigstruct), %i1
257 ; V9-NEXT: add %i1, %m44(bigstruct), %i1
258 ; V9-NEXT: sllx %i1, 12, %i1
259 ; V9-NEXT: add %i1, %l44(bigstruct), %o1
260 ; V9-NEXT: mov 400, %o2
261 ; V9-NEXT: call memcpy
262 ; V9-NEXT: mov %i0, %o0
266 %0 = bitcast ptr %agg.result to ptr
267 tail call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 @bigstruct, i32 400, i1 false)
271 ; Test register + immediate pattern.
273 define void @addri_test(i32 %ptr) #0 {
274 ; V8-LABEL: addri_test:
275 ; V8: ! %bb.0: ! %entry
279 ; V9-LABEL: addri_test:
280 ; V9: ! %bb.0: ! %entry
281 ; V9-NEXT: add %o0, 4, %o0
282 ; V9-NEXT: srl %o0, 0, %o0
286 %add = add nsw i32 %ptr, 4
287 %0 = inttoptr i32 %add to ptr
288 tail call void %0() #1
292 %struct.a = type { i32, i32 }
293 @dest = global [2 x i8] zeroinitializer
295 %struct.big = type { [100 x i32] }
296 @bigstruct = global %struct.big zeroinitializer
298 declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1)
299 declare void @sret_func(ptr sret(%struct.a))
300 declare i32 @callee_byval(ptr byval(ptr) %a)
301 declare i32 @foo(i32)
302 declare i32 @foo2(i32, i32)
303 declare i32 @foo7(i32, i32, i32, i32, i32, i32, i32)
305 attributes #0 = { nounwind "disable-tail-calls"="false"
306 "frame-pointer"="none" }
307 attributes #1 = { nounwind "disable-tail-calls"="false"
308 "frame-pointer"="all" }