xref: /llvm-project/llvm/test/CodeGen/SPARC/tailcall.ll (revision ff9af4c43ad71eeba2cabe99609cfaa0fd54c1d0)
11c235c37SDaniel Cederman; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2f63a19baSKoakuma; RUN: llc < %s -mtriple=sparc -verify-machineinstrs | FileCheck %s --check-prefix=V8
3f63a19baSKoakuma; RUN: llc < %s -mtriple=sparcv9 -verify-machineinstrs | FileCheck %s --check-prefix=V9
41c235c37SDaniel Cederman
51c235c37SDaniel Cedermandefine i32 @simple_leaf(i32 %i) #0 {
6f63a19baSKoakuma; V8-LABEL: simple_leaf:
7f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
8f63a19baSKoakuma; V8-NEXT:    mov %o7, %g1
9f63a19baSKoakuma; V8-NEXT:    call foo
10f63a19baSKoakuma; V8-NEXT:    mov %g1, %o7
11f63a19baSKoakuma;
12f63a19baSKoakuma; V9-LABEL: simple_leaf:
13f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
14f63a19baSKoakuma; V9-NEXT:    mov %o7, %g1
15f63a19baSKoakuma; V9-NEXT:    call foo
16f63a19baSKoakuma; V9-NEXT:    mov %g1, %o7
171c235c37SDaniel Cedermanentry:
181c235c37SDaniel Cederman  %call = tail call i32 @foo(i32 %i)
191c235c37SDaniel Cederman  ret i32 %call
201c235c37SDaniel Cederman}
211c235c37SDaniel Cederman
221c235c37SDaniel Cedermandefine i32 @simple_standard(i32 %i) #1 {
23f63a19baSKoakuma; V8-LABEL: simple_standard:
24f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
25f63a19baSKoakuma; V8-NEXT:    save %sp, -96, %sp
26f63a19baSKoakuma; V8-NEXT:    call foo
27f63a19baSKoakuma; V8-NEXT:    restore
28f63a19baSKoakuma;
29f63a19baSKoakuma; V9-LABEL: simple_standard:
30f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
31f63a19baSKoakuma; V9-NEXT:    save %sp, -128, %sp
32f63a19baSKoakuma; V9-NEXT:    call foo
33f63a19baSKoakuma; V9-NEXT:    restore
341c235c37SDaniel Cedermanentry:
351c235c37SDaniel Cederman  %call = tail call i32 @foo(i32 %i)
361c235c37SDaniel Cederman  ret i32 %call
371c235c37SDaniel Cederman}
381c235c37SDaniel Cederman
391c235c37SDaniel Cedermandefine i32 @extra_arg_leaf(i32 %i) #0 {
40f63a19baSKoakuma; V8-LABEL: extra_arg_leaf:
41f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
42f63a19baSKoakuma; V8-NEXT:    mov 12, %o1
43f63a19baSKoakuma; V8-NEXT:    mov %o7, %g1
44f63a19baSKoakuma; V8-NEXT:    call foo2
45f63a19baSKoakuma; V8-NEXT:    mov %g1, %o7
46f63a19baSKoakuma;
47f63a19baSKoakuma; V9-LABEL: extra_arg_leaf:
48f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
49f63a19baSKoakuma; V9-NEXT:    mov 12, %o1
50f63a19baSKoakuma; V9-NEXT:    mov %o7, %g1
51f63a19baSKoakuma; V9-NEXT:    call foo2
52f63a19baSKoakuma; V9-NEXT:    mov %g1, %o7
531c235c37SDaniel Cedermanentry:
541c235c37SDaniel Cederman  %call = tail call i32 @foo2(i32 %i, i32 12)
551c235c37SDaniel Cederman  ret i32 %call
561c235c37SDaniel Cederman}
571c235c37SDaniel Cederman
581c235c37SDaniel Cedermandefine i32 @extra_arg_standard(i32 %i) #1 {
59f63a19baSKoakuma; V8-LABEL: extra_arg_standard:
60f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
61f63a19baSKoakuma; V8-NEXT:    save %sp, -96, %sp
62f63a19baSKoakuma; V8-NEXT:    call foo2
63f63a19baSKoakuma; V8-NEXT:    restore %g0, 12, %o1
64f63a19baSKoakuma;
65f63a19baSKoakuma; V9-LABEL: extra_arg_standard:
66f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
67f63a19baSKoakuma; V9-NEXT:    save %sp, -128, %sp
68f63a19baSKoakuma; V9-NEXT:    call foo2
69f63a19baSKoakuma; V9-NEXT:    restore %g0, 12, %o1
701c235c37SDaniel Cedermanentry:
711c235c37SDaniel Cederman  %call = tail call i32 @foo2(i32 %i, i32 12)
721c235c37SDaniel Cederman  ret i32 %call
731c235c37SDaniel Cederman}
741c235c37SDaniel Cederman
751c235c37SDaniel Cederman; Perform tail call optimization for external symbol.
761c235c37SDaniel Cederman
77*ff9af4c4SNikita Popovdefine void @caller_extern(ptr %src) optsize #0 {
78f63a19baSKoakuma; V8-LABEL: caller_extern:
79f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
80f63a19baSKoakuma; V8-NEXT:    sethi %hi(dest), %o1
81f63a19baSKoakuma; V8-NEXT:    add %o1, %lo(dest), %o1
82f63a19baSKoakuma; V8-NEXT:    mov 7, %o2
83f63a19baSKoakuma; V8-NEXT:    mov %o0, %o3
84f63a19baSKoakuma; V8-NEXT:    mov %o1, %o0
85f63a19baSKoakuma; V8-NEXT:    mov %o3, %o1
86f63a19baSKoakuma; V8-NEXT:    mov %o7, %g1
87f63a19baSKoakuma; V8-NEXT:    call memcpy
88f63a19baSKoakuma; V8-NEXT:    mov %g1, %o7
89f63a19baSKoakuma;
90f63a19baSKoakuma; V9-LABEL: caller_extern:
91f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
92f63a19baSKoakuma; V9-NEXT:    sethi %h44(dest), %o1
93f63a19baSKoakuma; V9-NEXT:    add %o1, %m44(dest), %o1
94f63a19baSKoakuma; V9-NEXT:    sllx %o1, 12, %o1
95f63a19baSKoakuma; V9-NEXT:    add %o1, %l44(dest), %o1
96f63a19baSKoakuma; V9-NEXT:    mov 7, %o2
97f63a19baSKoakuma; V9-NEXT:    mov %o0, %o3
98f63a19baSKoakuma; V9-NEXT:    mov %o1, %o0
99f63a19baSKoakuma; V9-NEXT:    mov %o3, %o1
100f63a19baSKoakuma; V9-NEXT:    mov %o7, %g1
101f63a19baSKoakuma; V9-NEXT:    call memcpy
102f63a19baSKoakuma; V9-NEXT:    mov %g1, %o7
1031c235c37SDaniel Cedermanentry:
104*ff9af4c4SNikita Popov  tail call void @llvm.memcpy.p0.p0.i32(
105*ff9af4c4SNikita Popov    ptr @dest,
106*ff9af4c4SNikita Popov    ptr %src, i32 7, i1 false)
1071c235c37SDaniel Cederman  ret void
1081c235c37SDaniel Cederman}
1091c235c37SDaniel Cederman
1101c235c37SDaniel Cederman; Perform tail call optimization for function pointer.
1111c235c37SDaniel Cederman
112*ff9af4c4SNikita Popovdefine i32 @func_ptr_test(ptr nocapture %func_ptr) #0 {
113f63a19baSKoakuma; V8-LABEL: func_ptr_test:
114f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
115f63a19baSKoakuma; V8-NEXT:    jmp %o0
116f63a19baSKoakuma; V8-NEXT:    nop
117f63a19baSKoakuma;
118f63a19baSKoakuma; V9-LABEL: func_ptr_test:
119f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
120f63a19baSKoakuma; V9-NEXT:    jmp %o0
121f63a19baSKoakuma; V9-NEXT:    nop
1221c235c37SDaniel Cedermanentry:
1231c235c37SDaniel Cederman  %call = tail call i32 %func_ptr() #1
1241c235c37SDaniel Cederman  ret i32 %call
1251c235c37SDaniel Cederman}
1261c235c37SDaniel Cederman
127*ff9af4c4SNikita Popovdefine i32 @func_ptr_test2(ptr nocapture %func_ptr,
128f63a19baSKoakuma; V8-LABEL: func_ptr_test2:
129f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
130f63a19baSKoakuma; V8-NEXT:    save %sp, -96, %sp
131f63a19baSKoakuma; V8-NEXT:    mov 10, %i3
132f63a19baSKoakuma; V8-NEXT:    mov %i0, %i4
133f63a19baSKoakuma; V8-NEXT:    mov %i1, %i0
134f63a19baSKoakuma; V8-NEXT:    jmp %i4
135f63a19baSKoakuma; V8-NEXT:    restore %g0, %i3, %o1
136f63a19baSKoakuma;
137f63a19baSKoakuma; V9-LABEL: func_ptr_test2:
138f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
139f63a19baSKoakuma; V9-NEXT:    save %sp, -128, %sp
140f63a19baSKoakuma; V9-NEXT:    mov 10, %i3
141f63a19baSKoakuma; V9-NEXT:    mov %i0, %i4
142f63a19baSKoakuma; V9-NEXT:    mov %i1, %i0
143f63a19baSKoakuma; V9-NEXT:    jmp %i4
144f63a19baSKoakuma; V9-NEXT:    restore %g0, %i3, %o1
1451c235c37SDaniel Cederman                           i32 %r, i32 %q) #1 {
1461c235c37SDaniel Cedermanentry:
1471c235c37SDaniel Cederman  %call = tail call i32 %func_ptr(i32 %r, i32 10, i32 %q) #1
1481c235c37SDaniel Cederman  ret i32 %call
1491c235c37SDaniel Cederman}
1501c235c37SDaniel Cederman
1511c235c37SDaniel Cederman
1521c235c37SDaniel Cederman; Do not tail call optimize if stack is used to pass parameters.
1531c235c37SDaniel Cederman
1541c235c37SDaniel Cedermandefine i32 @caller_args() #0 {
155f63a19baSKoakuma; V8-LABEL: caller_args:
156f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
157f63a19baSKoakuma; V8-NEXT:    save %sp, -104, %sp
158f63a19baSKoakuma; V8-NEXT:    mov 6, %i0
159f63a19baSKoakuma; V8-NEXT:    mov 1, %o1
160f63a19baSKoakuma; V8-NEXT:    mov 2, %o2
161f63a19baSKoakuma; V8-NEXT:    mov 3, %o3
162f63a19baSKoakuma; V8-NEXT:    mov 4, %o4
163f63a19baSKoakuma; V8-NEXT:    mov 5, %o5
1647806f86aSBrad Smith; V8-NEXT:    st %i0, [%sp+92]
165eaade37fSKoakuma; V8-NEXT:    call foo7
166eaade37fSKoakuma; V8-NEXT:    mov %g0, %o0
167f63a19baSKoakuma; V8-NEXT:    ret
168f63a19baSKoakuma; V8-NEXT:    restore %g0, %o0, %o0
169f63a19baSKoakuma;
170f63a19baSKoakuma; V9-LABEL: caller_args:
171f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
172f63a19baSKoakuma; V9-NEXT:    save %sp, -192, %sp
173f63a19baSKoakuma; V9-NEXT:    mov 6, %i0
174f63a19baSKoakuma; V9-NEXT:    mov 1, %o1
175f63a19baSKoakuma; V9-NEXT:    mov 2, %o2
176f63a19baSKoakuma; V9-NEXT:    mov 3, %o3
177f63a19baSKoakuma; V9-NEXT:    mov 4, %o4
178f63a19baSKoakuma; V9-NEXT:    mov 5, %o5
1797806f86aSBrad Smith; V9-NEXT:    stx %i0, [%sp+2223]
180eaade37fSKoakuma; V9-NEXT:    call foo7
181eaade37fSKoakuma; V9-NEXT:    mov %g0, %o0
182f63a19baSKoakuma; V9-NEXT:    ret
183f63a19baSKoakuma; V9-NEXT:    restore %g0, %o0, %o0
1841c235c37SDaniel Cedermanentry:
1851c235c37SDaniel Cederman  %r = tail call i32 @foo7(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
1861c235c37SDaniel Cederman  ret i32 %r
1871c235c37SDaniel Cederman}
1881c235c37SDaniel Cederman
1891c235c37SDaniel Cederman; Byval parameters hand the function a pointer directly into the stack area
1901c235c37SDaniel Cederman; we want to reuse during a tail call. Do not tail call optimize functions with
1911c235c37SDaniel Cederman; byval parameters.
1921c235c37SDaniel Cederman
1931c235c37SDaniel Cedermandefine i32 @caller_byval() #0 {
194f63a19baSKoakuma; V8-LABEL: caller_byval:
195f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
196f63a19baSKoakuma; V8-NEXT:    save %sp, -104, %sp
197f63a19baSKoakuma; V8-NEXT:    ld [%fp+-4], %i0
198f63a19baSKoakuma; V8-NEXT:    st %i0, [%fp+-8]
199f63a19baSKoakuma; V8-NEXT:    call callee_byval
200f63a19baSKoakuma; V8-NEXT:    add %fp, -8, %o0
201f63a19baSKoakuma; V8-NEXT:    ret
202f63a19baSKoakuma; V8-NEXT:    restore %g0, %o0, %o0
203f63a19baSKoakuma;
204f63a19baSKoakuma; V9-LABEL: caller_byval:
205f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
206f63a19baSKoakuma; V9-NEXT:    save %sp, -192, %sp
207f63a19baSKoakuma; V9-NEXT:    call callee_byval
208f63a19baSKoakuma; V9-NEXT:    add %fp, 2039, %o0
209f63a19baSKoakuma; V9-NEXT:    ret
210f63a19baSKoakuma; V9-NEXT:    restore %g0, %o0, %o0
2111c235c37SDaniel Cedermanentry:
212*ff9af4c4SNikita Popov  %a = alloca ptr
213*ff9af4c4SNikita Popov  %r = tail call i32 @callee_byval(ptr byval(ptr) %a)
2141c235c37SDaniel Cederman  ret i32 %r
2151c235c37SDaniel Cederman}
2161c235c37SDaniel Cederman
2171c235c37SDaniel Cederman; Perform tail call optimization for sret function.
2181c235c37SDaniel Cederman
219*ff9af4c4SNikita Popovdefine void @sret_test(ptr noalias sret(%struct.a) %agg.result) #0 {
220f63a19baSKoakuma; V8-LABEL: sret_test:
221f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
222f63a19baSKoakuma; V8-NEXT:    mov %o7, %g1
223f63a19baSKoakuma; V8-NEXT:    call sret_func
224f63a19baSKoakuma; V8-NEXT:    mov %g1, %o7
225f63a19baSKoakuma;
226f63a19baSKoakuma; V9-LABEL: sret_test:
227f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
228f63a19baSKoakuma; V9-NEXT:    mov %o7, %g1
229f63a19baSKoakuma; V9-NEXT:    call sret_func
230f63a19baSKoakuma; V9-NEXT:    mov %g1, %o7
2311c235c37SDaniel Cedermanentry:
232*ff9af4c4SNikita Popov  tail call void @sret_func(ptr sret(%struct.a) %agg.result)
2331c235c37SDaniel Cederman  ret void
2341c235c37SDaniel Cederman}
2351c235c37SDaniel Cederman
2361c235c37SDaniel Cederman; Do not tail call if either caller or callee returns
2371c235c37SDaniel Cederman; a struct and the other does not. Returning a large
2381c235c37SDaniel Cederman; struct will generate a memcpy as the tail function.
2391c235c37SDaniel Cederman
240*ff9af4c4SNikita Popovdefine void @ret_large_struct(ptr noalias sret(%struct.big) %agg.result) #0 {
241f63a19baSKoakuma; V8-LABEL: ret_large_struct:
242f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
243f63a19baSKoakuma; V8-NEXT:    save %sp, -96, %sp
244f63a19baSKoakuma; V8-NEXT:    ld [%fp+64], %i0
245f63a19baSKoakuma; V8-NEXT:    sethi %hi(bigstruct), %i1
246f63a19baSKoakuma; V8-NEXT:    add %i1, %lo(bigstruct), %o1
247f63a19baSKoakuma; V8-NEXT:    mov 400, %o2
248f63a19baSKoakuma; V8-NEXT:    call memcpy
249f63a19baSKoakuma; V8-NEXT:    mov %i0, %o0
250f63a19baSKoakuma; V8-NEXT:    jmp %i7+12
251f63a19baSKoakuma; V8-NEXT:    restore
252f63a19baSKoakuma;
253f63a19baSKoakuma; V9-LABEL: ret_large_struct:
254f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
255f63a19baSKoakuma; V9-NEXT:    save %sp, -176, %sp
256f63a19baSKoakuma; V9-NEXT:    sethi %h44(bigstruct), %i1
257f63a19baSKoakuma; V9-NEXT:    add %i1, %m44(bigstruct), %i1
258f63a19baSKoakuma; V9-NEXT:    sllx %i1, 12, %i1
259f63a19baSKoakuma; V9-NEXT:    add %i1, %l44(bigstruct), %o1
260f63a19baSKoakuma; V9-NEXT:    mov 400, %o2
261f63a19baSKoakuma; V9-NEXT:    call memcpy
262f63a19baSKoakuma; V9-NEXT:    mov %i0, %o0
263f63a19baSKoakuma; V9-NEXT:    ret
264f63a19baSKoakuma; V9-NEXT:    restore
2651c235c37SDaniel Cedermanentry:
266*ff9af4c4SNikita Popov  %0 = bitcast ptr %agg.result to ptr
267*ff9af4c4SNikita Popov  tail call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 @bigstruct, i32 400, i1 false)
2681c235c37SDaniel Cederman  ret void
2691c235c37SDaniel Cederman}
2701c235c37SDaniel Cederman
2711c235c37SDaniel Cederman; Test register + immediate pattern.
2721c235c37SDaniel Cederman
2731c235c37SDaniel Cedermandefine void @addri_test(i32 %ptr) #0 {
274f63a19baSKoakuma; V8-LABEL: addri_test:
275f63a19baSKoakuma; V8:       ! %bb.0: ! %entry
276f63a19baSKoakuma; V8-NEXT:    jmp %o0+4
277f63a19baSKoakuma; V8-NEXT:    nop
278f63a19baSKoakuma;
279f63a19baSKoakuma; V9-LABEL: addri_test:
280f63a19baSKoakuma; V9:       ! %bb.0: ! %entry
281f63a19baSKoakuma; V9-NEXT:    add %o0, 4, %o0
282f63a19baSKoakuma; V9-NEXT:    srl %o0, 0, %o0
283f63a19baSKoakuma; V9-NEXT:    jmp %o0
284f63a19baSKoakuma; V9-NEXT:    nop
2851c235c37SDaniel Cedermanentry:
2861c235c37SDaniel Cederman  %add = add nsw i32 %ptr, 4
287*ff9af4c4SNikita Popov  %0 = inttoptr i32 %add to ptr
2881c235c37SDaniel Cederman  tail call void %0() #1
2891c235c37SDaniel Cederman  ret void
2901c235c37SDaniel Cederman}
2911c235c37SDaniel Cederman
2921c235c37SDaniel Cederman%struct.a = type { i32, i32 }
2931c235c37SDaniel Cederman@dest = global [2 x i8] zeroinitializer
2941c235c37SDaniel Cederman
2951c235c37SDaniel Cederman%struct.big = type { [100 x i32] }
2961c235c37SDaniel Cederman@bigstruct = global %struct.big zeroinitializer
2971c235c37SDaniel Cederman
298*ff9af4c4SNikita Popovdeclare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1)
299*ff9af4c4SNikita Popovdeclare void @sret_func(ptr sret(%struct.a))
300*ff9af4c4SNikita Popovdeclare i32 @callee_byval(ptr byval(ptr) %a)
3011c235c37SDaniel Cedermandeclare i32 @foo(i32)
3021c235c37SDaniel Cedermandeclare i32 @foo2(i32, i32)
3031c235c37SDaniel Cedermandeclare i32 @foo7(i32, i32, i32, i32, i32, i32, i32)
3041c235c37SDaniel Cederman
3051c235c37SDaniel Cedermanattributes #0 = { nounwind "disable-tail-calls"="false"
3061c235c37SDaniel Cederman                  "frame-pointer"="none" }
3071c235c37SDaniel Cedermanattributes #1 = { nounwind "disable-tail-calls"="false"
3081c235c37SDaniel Cederman                  "frame-pointer"="all" }
309