Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / test / CodeGen / SPARC / tailcall.ll
blob9a0e7bc5c792371bfe02571173128a7b889ad9ea
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
9 ; V8-NEXT:    call foo
10 ; V8-NEXT:    mov %g1, %o7
12 ; V9-LABEL: simple_leaf:
13 ; V9:       ! %bb.0: ! %entry
14 ; V9-NEXT:    mov %o7, %g1
15 ; V9-NEXT:    call foo
16 ; V9-NEXT:    mov %g1, %o7
17 entry:
18   %call = tail call i32 @foo(i32 %i)
19   ret i32 %call
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
26 ; V8-NEXT:    call foo
27 ; V8-NEXT:    restore
29 ; V9-LABEL: simple_standard:
30 ; V9:       ! %bb.0: ! %entry
31 ; V9-NEXT:    save %sp, -128, %sp
32 ; V9-NEXT:    call foo
33 ; V9-NEXT:    restore
34 entry:
35   %call = tail call i32 @foo(i32 %i)
36   ret i32 %call
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
44 ; V8-NEXT:    call foo2
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
51 ; V9-NEXT:    call foo2
52 ; V9-NEXT:    mov %g1, %o7
53 entry:
54   %call = tail call i32 @foo2(i32 %i, i32 12)
55   ret i32 %call
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
62 ; V8-NEXT:    call foo2
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
68 ; V9-NEXT:    call foo2
69 ; V9-NEXT:    restore %g0, 12, %o1
70 entry:
71   %call = tail call i32 @foo2(i32 %i, i32 12)
72   ret i32 %call
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
82 ; V8-NEXT:    mov 7, %o2
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
96 ; V9-NEXT:    mov 7, %o2
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
103 entry:
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)
108   ret void
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
116 ; V8-NEXT:    jmp %o0
117 ; V8-NEXT:    nop
119 ; V9-LABEL: func_ptr_test:
120 ; V9:       ! %bb.0: ! %entry
121 ; V9-NEXT:    jmp %o0
122 ; V9-NEXT:    nop
123 entry:
124   %call = tail call i32 %func_ptr() #1
125   ret i32 %call
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
135 ; V8-NEXT:    jmp %i4
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
144 ; V9-NEXT:    jmp %i4
145 ; V9-NEXT:    restore %g0, %i3, %o1
146                            i32 %r, i32 %q) #1 {
147 entry:
148   %call = tail call i32 %func_ptr(i32 %r, i32 10, i32 %q) #1
149   ret i32 %call
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]
166 ; V8-NEXT:    call foo7
167 ; V8-NEXT:    mov %g0, %o0
168 ; V8-NEXT:    ret
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]
181 ; V9-NEXT:    call foo7
182 ; V9-NEXT:    mov %g0, %o0
183 ; V9-NEXT:    ret
184 ; V9-NEXT:    restore %g0, %o0, %o0
185 entry:
186   %r = tail call i32 @foo7(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
187   ret i32 %r
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
192 ; byval parameters.
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
202 ; V8-NEXT:    ret
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
210 ; V9-NEXT:    ret
211 ; V9-NEXT:    restore %g0, %o0, %o0
212 entry:
213   %a = alloca i32*
214   %r = tail call i32 @callee_byval(i32** byval(i32*) %a)
215   ret i32 %r
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
232 entry:
233   tail call void bitcast (void (%struct.a*)* @sret_func to
234                           void (%struct.a*)*)(%struct.a* sret(%struct.a) %agg.result)
235   ret void
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
253 ; V8-NEXT:    restore
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
265 ; V9-NEXT:    ret
266 ; V9-NEXT:    restore
267 entry:
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)
270   ret void
273 ; Test register + immediate pattern.
275 define void @addri_test(i32 %ptr) #0 {
276 ; V8-LABEL: addri_test:
277 ; V8:       ! %bb.0: ! %entry
278 ; V8-NEXT:    jmp %o0+4
279 ; V8-NEXT:    nop
281 ; V9-LABEL: addri_test:
282 ; V9:       ! %bb.0: ! %entry
283 ; V9-NEXT:    add %o0, 4, %o0
284 ; V9-NEXT:    srl %o0, 0, %o0
285 ; V9-NEXT:    jmp %o0
286 ; V9-NEXT:    nop
287 entry:
288   %add = add nsw i32 %ptr, 4
289   %0 = inttoptr i32 %add to void ()*
290   tail call void %0() #1
291   ret void
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" }