Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / CodeGen / SPARC / tailcall.ll
blob45612c51ee13387630e024ae08d13d3aa1722adb
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(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
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.p0.p0.i32(
105     ptr @dest,
106     ptr %src, i32 7, i1 false)
107   ret void
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
115 ; V8-NEXT:    jmp %o0
116 ; V8-NEXT:    nop
118 ; V9-LABEL: func_ptr_test:
119 ; V9:       ! %bb.0: ! %entry
120 ; V9-NEXT:    jmp %o0
121 ; V9-NEXT:    nop
122 entry:
123   %call = tail call i32 %func_ptr() #1
124   ret i32 %call
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
134 ; V8-NEXT:    jmp %i4
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
143 ; V9-NEXT:    jmp %i4
144 ; V9-NEXT:    restore %g0, %i3, %o1
145                            i32 %r, i32 %q) #1 {
146 entry:
147   %call = tail call i32 %func_ptr(i32 %r, i32 10, i32 %q) #1
148   ret i32 %call
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]
165 ; V8-NEXT:    call foo7
166 ; V8-NEXT:    mov %g0, %o0
167 ; V8-NEXT:    ret
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]
180 ; V9-NEXT:    call foo7
181 ; V9-NEXT:    mov %g0, %o0
182 ; V9-NEXT:    ret
183 ; V9-NEXT:    restore %g0, %o0, %o0
184 entry:
185   %r = tail call i32 @foo7(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
186   ret i32 %r
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
191 ; byval parameters.
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
201 ; V8-NEXT:    ret
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
209 ; V9-NEXT:    ret
210 ; V9-NEXT:    restore %g0, %o0, %o0
211 entry:
212   %a = alloca ptr
213   %r = tail call i32 @callee_byval(ptr byval(ptr) %a)
214   ret i32 %r
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
231 entry:
232   tail call void @sret_func(ptr sret(%struct.a) %agg.result)
233   ret void
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
251 ; V8-NEXT:    restore
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
263 ; V9-NEXT:    ret
264 ; V9-NEXT:    restore
265 entry:
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)
268   ret void
271 ; Test register + immediate pattern.
273 define void @addri_test(i32 %ptr) #0 {
274 ; V8-LABEL: addri_test:
275 ; V8:       ! %bb.0: ! %entry
276 ; V8-NEXT:    jmp %o0+4
277 ; V8-NEXT:    nop
279 ; V9-LABEL: addri_test:
280 ; V9:       ! %bb.0: ! %entry
281 ; V9-NEXT:    add %o0, 4, %o0
282 ; V9-NEXT:    srl %o0, 0, %o0
283 ; V9-NEXT:    jmp %o0
284 ; V9-NEXT:    nop
285 entry:
286   %add = add nsw i32 %ptr, 4
287   %0 = inttoptr i32 %add to ptr
288   tail call void %0() #1
289   ret void
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" }