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(i8* %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.p0i8.p0i8.i32(
105 i8* getelementptr inbounds ([2 x i8],
106 [2 x i8]* @dest, i32 0, i32 0),
107 i8* %src, i32 7, i1 false)
111 ; Perform tail call optimization for function pointer.
113 define i32 @func_ptr_test(i32 ()* nocapture %func_ptr) #0 {
114 ; V8-LABEL: func_ptr_test:
115 ; V8: ! %bb.0: ! %entry
119 ; V9-LABEL: func_ptr_test:
120 ; V9: ! %bb.0: ! %entry
124 %call = tail call i32 %func_ptr() #1
128 define i32 @func_ptr_test2(i32 (i32, i32, i32)* nocapture %func_ptr,
129 ; V8-LABEL: func_ptr_test2:
130 ; V8: ! %bb.0: ! %entry
131 ; V8-NEXT: save %sp, -96, %sp
132 ; V8-NEXT: mov 10, %i3
133 ; V8-NEXT: mov %i0, %i4
134 ; V8-NEXT: mov %i1, %i0
136 ; V8-NEXT: restore %g0, %i3, %o1
138 ; V9-LABEL: func_ptr_test2:
139 ; V9: ! %bb.0: ! %entry
140 ; V9-NEXT: save %sp, -128, %sp
141 ; V9-NEXT: mov 10, %i3
142 ; V9-NEXT: mov %i0, %i4
143 ; V9-NEXT: mov %i1, %i0
145 ; V9-NEXT: restore %g0, %i3, %o1
148 %call = tail call i32 %func_ptr(i32 %r, i32 10, i32 %q) #1
153 ; Do not tail call optimize if stack is used to pass parameters.
155 define i32 @caller_args() #0 {
156 ; V8-LABEL: caller_args:
157 ; V8: ! %bb.0: ! %entry
158 ; V8-NEXT: save %sp, -104, %sp
159 ; V8-NEXT: mov 6, %i0
160 ; V8-NEXT: mov 1, %o1
161 ; V8-NEXT: mov 2, %o2
162 ; V8-NEXT: mov 3, %o3
163 ; V8-NEXT: mov 4, %o4
164 ; V8-NEXT: mov 5, %o5
165 ; V8-NEXT: st %i0, [%sp+92]
167 ; V8-NEXT: mov %g0, %o0
169 ; V8-NEXT: restore %g0, %o0, %o0
171 ; V9-LABEL: caller_args:
172 ; V9: ! %bb.0: ! %entry
173 ; V9-NEXT: save %sp, -192, %sp
174 ; V9-NEXT: mov 6, %i0
175 ; V9-NEXT: mov 1, %o1
176 ; V9-NEXT: mov 2, %o2
177 ; V9-NEXT: mov 3, %o3
178 ; V9-NEXT: mov 4, %o4
179 ; V9-NEXT: mov 5, %o5
180 ; V9-NEXT: stx %i0, [%sp+2223]
182 ; V9-NEXT: mov %g0, %o0
184 ; V9-NEXT: restore %g0, %o0, %o0
186 %r = tail call i32 @foo7(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
190 ; Byval parameters hand the function a pointer directly into the stack area
191 ; we want to reuse during a tail call. Do not tail call optimize functions with
194 define i32 @caller_byval() #0 {
195 ; V8-LABEL: caller_byval:
196 ; V8: ! %bb.0: ! %entry
197 ; V8-NEXT: save %sp, -104, %sp
198 ; V8-NEXT: ld [%fp+-4], %i0
199 ; V8-NEXT: st %i0, [%fp+-8]
200 ; V8-NEXT: call callee_byval
201 ; V8-NEXT: add %fp, -8, %o0
203 ; V8-NEXT: restore %g0, %o0, %o0
205 ; V9-LABEL: caller_byval:
206 ; V9: ! %bb.0: ! %entry
207 ; V9-NEXT: save %sp, -192, %sp
208 ; V9-NEXT: call callee_byval
209 ; V9-NEXT: add %fp, 2039, %o0
211 ; V9-NEXT: restore %g0, %o0, %o0
214 %r = tail call i32 @callee_byval(i32** byval(i32*) %a)
218 ; Perform tail call optimization for sret function.
220 define void @sret_test(%struct.a* noalias sret(%struct.a) %agg.result) #0 {
221 ; V8-LABEL: sret_test:
222 ; V8: ! %bb.0: ! %entry
223 ; V8-NEXT: mov %o7, %g1
224 ; V8-NEXT: call sret_func
225 ; V8-NEXT: mov %g1, %o7
227 ; V9-LABEL: sret_test:
228 ; V9: ! %bb.0: ! %entry
229 ; V9-NEXT: mov %o7, %g1
230 ; V9-NEXT: call sret_func
231 ; V9-NEXT: mov %g1, %o7
233 tail call void bitcast (void (%struct.a*)* @sret_func to
234 void (%struct.a*)*)(%struct.a* sret(%struct.a) %agg.result)
238 ; Do not tail call if either caller or callee returns
239 ; a struct and the other does not. Returning a large
240 ; struct will generate a memcpy as the tail function.
242 define void @ret_large_struct(%struct.big* noalias sret(%struct.big) %agg.result) #0 {
243 ; V8-LABEL: ret_large_struct:
244 ; V8: ! %bb.0: ! %entry
245 ; V8-NEXT: save %sp, -96, %sp
246 ; V8-NEXT: ld [%fp+64], %i0
247 ; V8-NEXT: sethi %hi(bigstruct), %i1
248 ; V8-NEXT: add %i1, %lo(bigstruct), %o1
249 ; V8-NEXT: mov 400, %o2
250 ; V8-NEXT: call memcpy
251 ; V8-NEXT: mov %i0, %o0
252 ; V8-NEXT: jmp %i7+12
255 ; V9-LABEL: ret_large_struct:
256 ; V9: ! %bb.0: ! %entry
257 ; V9-NEXT: save %sp, -176, %sp
258 ; V9-NEXT: sethi %h44(bigstruct), %i1
259 ; V9-NEXT: add %i1, %m44(bigstruct), %i1
260 ; V9-NEXT: sllx %i1, 12, %i1
261 ; V9-NEXT: add %i1, %l44(bigstruct), %o1
262 ; V9-NEXT: mov 400, %o2
263 ; V9-NEXT: call memcpy
264 ; V9-NEXT: mov %i0, %o0
268 %0 = bitcast %struct.big* %agg.result to i8*
269 tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%struct.big* @bigstruct to i8*), i32 400, i1 false)
273 ; Test register + immediate pattern.
275 define void @addri_test(i32 %ptr) #0 {
276 ; V8-LABEL: addri_test:
277 ; V8: ! %bb.0: ! %entry
281 ; V9-LABEL: addri_test:
282 ; V9: ! %bb.0: ! %entry
283 ; V9-NEXT: add %o0, 4, %o0
284 ; V9-NEXT: srl %o0, 0, %o0
288 %add = add nsw i32 %ptr, 4
289 %0 = inttoptr i32 %add to void ()*
290 tail call void %0() #1
294 %struct.a = type { i32, i32 }
295 @dest = global [2 x i8] zeroinitializer
297 %struct.big = type { [100 x i32] }
298 @bigstruct = global %struct.big zeroinitializer
300 declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1)
301 declare void @sret_func(%struct.a* sret(%struct.a))
302 declare i32 @callee_byval(i32** byval(i32*) %a)
303 declare i32 @foo(i32)
304 declare i32 @foo2(i32, i32)
305 declare i32 @foo7(i32, i32, i32, i32, i32, i32, i32)
307 attributes #0 = { nounwind "disable-tail-calls"="false"
308 "frame-pointer"="none" }
309 attributes #1 = { nounwind "disable-tail-calls"="false"
310 "frame-pointer"="all" }