xref: /llvm-project/llvm/test/CodeGen/ARM/musttail.ll (revision 376d7b27fa3de4f72c2a3cec4f941c1ca3f1d7f2)
1c1eb790cSOliver Stannard; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2c1eb790cSOliver Stannard; RUN: llc -mtriple=armv7a-none-eabi %s -o - | FileCheck %s
3c1eb790cSOliver Stannard
4c1eb790cSOliver Stannarddeclare i32 @many_args_callee(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5)
5c1eb790cSOliver Stannard
6c1eb790cSOliver Stannarddefine i32 @many_args_tail(i32 %0, i32 %1, i32 %2, i32 %3, i32  %4, i32  %5) {
7c1eb790cSOliver Stannard; CHECK-LABEL: many_args_tail:
8c1eb790cSOliver Stannard; CHECK:       @ %bb.0:
9c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #5
10c1eb790cSOliver Stannard; CHECK-NEXT:    mov r1, #2
11c1eb790cSOliver Stannard; CHECK-NEXT:    str r0, [sp]
12c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #6
13c1eb790cSOliver Stannard; CHECK-NEXT:    str r0, [sp, #4]
14c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #1
15c1eb790cSOliver Stannard; CHECK-NEXT:    mov r2, #3
16c1eb790cSOliver Stannard; CHECK-NEXT:    mov r3, #4
17c1eb790cSOliver Stannard; CHECK-NEXT:    b many_args_callee
18c1eb790cSOliver Stannard  %ret = tail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
19c1eb790cSOliver Stannard  ret i32 %ret
20c1eb790cSOliver Stannard}
21c1eb790cSOliver Stannard
22c1eb790cSOliver Stannarddefine i32 @many_args_musttail(i32 %0, i32 %1, i32 %2, i32 %3, i32  %4, i32  %5) {
23c1eb790cSOliver Stannard; CHECK-LABEL: many_args_musttail:
24c1eb790cSOliver Stannard; CHECK:       @ %bb.0:
25c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #5
26c1eb790cSOliver Stannard; CHECK-NEXT:    mov r1, #2
27c1eb790cSOliver Stannard; CHECK-NEXT:    str r0, [sp]
28c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #6
29c1eb790cSOliver Stannard; CHECK-NEXT:    str r0, [sp, #4]
30c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #1
31c1eb790cSOliver Stannard; CHECK-NEXT:    mov r2, #3
32c1eb790cSOliver Stannard; CHECK-NEXT:    mov r3, #4
33c1eb790cSOliver Stannard; CHECK-NEXT:    b many_args_callee
34c1eb790cSOliver Stannard  %ret = musttail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
35c1eb790cSOliver Stannard  ret i32 %ret
36c1eb790cSOliver Stannard}
37c1eb790cSOliver Stannard
38c1eb790cSOliver Stannard; This function has more arguments than it's tail-callee. This isn't valid for
39c1eb790cSOliver Stannard; the musttail attribute, but can still be tail-called as a non-guaranteed
40c1eb790cSOliver Stannard; optimisation, because the outgoing arguments to @many_args_callee fit in the
41c1eb790cSOliver Stannard; stack space allocated by the caller of @more_args_tail.
42c1eb790cSOliver Stannarddefine i32 @more_args_tail(i32 %0, i32 %1, i32 %2, i32 %3, i32  %4, i32 %5, i32 %6) {
43c1eb790cSOliver Stannard; CHECK-LABEL: more_args_tail:
44c1eb790cSOliver Stannard; CHECK:       @ %bb.0:
45c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #5
46c1eb790cSOliver Stannard; CHECK-NEXT:    mov r1, #2
47c1eb790cSOliver Stannard; CHECK-NEXT:    str r0, [sp]
48c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #6
49c1eb790cSOliver Stannard; CHECK-NEXT:    str r0, [sp, #4]
50c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #1
51c1eb790cSOliver Stannard; CHECK-NEXT:    mov r2, #3
52c1eb790cSOliver Stannard; CHECK-NEXT:    mov r3, #4
53c1eb790cSOliver Stannard; CHECK-NEXT:    b many_args_callee
54c1eb790cSOliver Stannard  %ret = tail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
55c1eb790cSOliver Stannard  ret i32 %ret
56c1eb790cSOliver Stannard}
57c1eb790cSOliver Stannard
58c1eb790cSOliver Stannard; Again, this isn't valid for musttail, but can be tail-called in practice
59c1eb790cSOliver Stannard; because the stack size if the same.
60c1eb790cSOliver Stannarddefine i32 @different_args_tail(i64 %0, i64 %1, i64 %2) {
61c1eb790cSOliver Stannard; CHECK-LABEL: different_args_tail:
62c1eb790cSOliver Stannard; CHECK:       @ %bb.0:
63c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #5
64c1eb790cSOliver Stannard; CHECK-NEXT:    mov r1, #2
65c1eb790cSOliver Stannard; CHECK-NEXT:    str r0, [sp]
66c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #6
67c1eb790cSOliver Stannard; CHECK-NEXT:    str r0, [sp, #4]
68c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #1
69c1eb790cSOliver Stannard; CHECK-NEXT:    mov r2, #3
70c1eb790cSOliver Stannard; CHECK-NEXT:    mov r3, #4
71c1eb790cSOliver Stannard; CHECK-NEXT:    b many_args_callee
72c1eb790cSOliver Stannard  %ret = tail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
73c1eb790cSOliver Stannard  ret i32 %ret
74c1eb790cSOliver Stannard}
75c1eb790cSOliver Stannard
76c1eb790cSOliver Stannard; Here, the caller requires less stack space for it's arguments than the
77c1eb790cSOliver Stannard; callee, so it would not ba valid to do a tail-call.
78c1eb790cSOliver Stannarddefine i32 @fewer_args_tail(i32 %0, i32 %1, i32 %2, i32 %3, i32  %4) {
79c1eb790cSOliver Stannard; CHECK-LABEL: fewer_args_tail:
80c1eb790cSOliver Stannard; CHECK:       @ %bb.0:
81c1eb790cSOliver Stannard; CHECK-NEXT:    .save {r11, lr}
82c1eb790cSOliver Stannard; CHECK-NEXT:    push {r11, lr}
83c1eb790cSOliver Stannard; CHECK-NEXT:    .pad #8
84c1eb790cSOliver Stannard; CHECK-NEXT:    sub sp, sp, #8
85c1eb790cSOliver Stannard; CHECK-NEXT:    mov r1, #6
86c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #5
87c1eb790cSOliver Stannard; CHECK-NEXT:    strd r0, r1, [sp]
88c1eb790cSOliver Stannard; CHECK-NEXT:    mov r0, #1
89c1eb790cSOliver Stannard; CHECK-NEXT:    mov r1, #2
90c1eb790cSOliver Stannard; CHECK-NEXT:    mov r2, #3
91c1eb790cSOliver Stannard; CHECK-NEXT:    mov r3, #4
92c1eb790cSOliver Stannard; CHECK-NEXT:    bl many_args_callee
93c1eb790cSOliver Stannard; CHECK-NEXT:    add sp, sp, #8
94c1eb790cSOliver Stannard; CHECK-NEXT:    pop {r11, pc}
95c1eb790cSOliver Stannard  %ret = tail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
96c1eb790cSOliver Stannard  ret i32 %ret
97c1eb790cSOliver Stannard}
9882e64721SOliver Stannard
9982e64721SOliver Stannarddeclare void @sret_callee(ptr sret({ double, double }) align 8)
10082e64721SOliver Stannard
10182e64721SOliver Stannard; Functions which return by sret can be tail-called because the incoming sret
10282e64721SOliver Stannard; pointer gets passed through to the callee.
10382e64721SOliver Stannarddefine void @sret_caller_tail(ptr sret({ double, double }) align 8 %result) {
10482e64721SOliver Stannard; CHECK-LABEL: sret_caller_tail:
10582e64721SOliver Stannard; CHECK:       @ %bb.0: @ %entry
10682e64721SOliver Stannard; CHECK-NEXT:    b sret_callee
10782e64721SOliver Stannardentry:
10882e64721SOliver Stannard  tail call void @sret_callee(ptr sret({ double, double }) align 8 %result)
10982e64721SOliver Stannard  ret void
11082e64721SOliver Stannard}
11182e64721SOliver Stannard
11282e64721SOliver Stannarddefine void @sret_caller_musttail(ptr sret({ double, double }) align 8 %result) {
11382e64721SOliver Stannard; CHECK-LABEL: sret_caller_musttail:
11482e64721SOliver Stannard; CHECK:       @ %bb.0: @ %entry
11582e64721SOliver Stannard; CHECK-NEXT:    b sret_callee
11682e64721SOliver Stannardentry:
11782e64721SOliver Stannard  musttail call void @sret_callee(ptr sret({ double, double }) align 8 %result)
11882e64721SOliver Stannard  ret void
11982e64721SOliver Stannard}
12078ec2e2eSOliver Stannard
12178ec2e2eSOliver Stannard; Clang only uses byval for arguments of 65 bytes or larger, but we test with a
12278ec2e2eSOliver Stannard; 20 byte struct to keep the tests more readable. This size was chosen to still
12378ec2e2eSOliver Stannard; make sure that it will be split between registers and the stack, to test all
12478ec2e2eSOliver Stannard; of the interesting code paths in the backend.
12578ec2e2eSOliver Stannard%twenty_bytes = type { [5 x i32] }
12678ec2e2eSOliver Stannarddeclare void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4)
12778ec2e2eSOliver Stannard
12878ec2e2eSOliver Stannard; Functions with byval parameters can be tail-called, because the value is
12978ec2e2eSOliver Stannard; actually passed in registers and the stack in the same way for the caller and
13078ec2e2eSOliver Stannard; callee. Within @large_caller the first 16 bytes of the argument are spilled
13178ec2e2eSOliver Stannard; to the local stack frame, but for the tail-call they are passed in r0-r3, so
132*376d7b27SOliver Stannard; it's safe to de-allocate that memory before the call.
133*376d7b27SOliver Stannard; TODO: The SUB and STM instructions are unnecessary and could be optimised
134*376d7b27SOliver Stannard; out, but the behaviour of this is still correct.
13578ec2e2eSOliver Stannarddefine void @large_caller(%twenty_bytes* byval(%twenty_bytes) align 4 %a) {
13678ec2e2eSOliver Stannard; CHECK-LABEL: large_caller:
13778ec2e2eSOliver Stannard; CHECK:       @ %bb.0: @ %entry
13878ec2e2eSOliver Stannard; CHECK-NEXT:    .pad #16
13978ec2e2eSOliver Stannard; CHECK-NEXT:    sub sp, sp, #16
140*376d7b27SOliver Stannard; CHECK-NEXT:    stm sp!, {r0, r1, r2, r3}
14178ec2e2eSOliver Stannard; CHECK-NEXT:    b large_callee
14278ec2e2eSOliver Stannardentry:
14378ec2e2eSOliver Stannard  musttail call void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %a)
14478ec2e2eSOliver Stannard  ret void
14578ec2e2eSOliver Stannard}
14678ec2e2eSOliver Stannard
14778ec2e2eSOliver Stannard; As above, but with some inline asm to test that the arguments in r0-r3 are
14878ec2e2eSOliver Stannard; re-loaded before the call.
14978ec2e2eSOliver Stannarddefine void @large_caller_check_regs(%twenty_bytes* byval(%twenty_bytes) align 4 %a) {
15078ec2e2eSOliver Stannard; CHECK-LABEL: large_caller_check_regs:
15178ec2e2eSOliver Stannard; CHECK:       @ %bb.0: @ %entry
15278ec2e2eSOliver Stannard; CHECK-NEXT:    .pad #16
15378ec2e2eSOliver Stannard; CHECK-NEXT:    sub sp, sp, #16
154*376d7b27SOliver Stannard; CHECK-NEXT:    stm sp, {r0, r1, r2, r3}
15578ec2e2eSOliver Stannard; CHECK-NEXT:    @APP
15678ec2e2eSOliver Stannard; CHECK-NEXT:    @NO_APP
157*376d7b27SOliver Stannard; CHECK-NEXT:    pop {r0, r1, r2, r3}
15878ec2e2eSOliver Stannard; CHECK-NEXT:    b large_callee
15978ec2e2eSOliver Stannardentry:
16078ec2e2eSOliver Stannard  tail call void asm sideeffect "", "~{r0},~{r1},~{r2},~{r3}"()
16178ec2e2eSOliver Stannard  musttail call void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %a)
16278ec2e2eSOliver Stannard  ret void
16378ec2e2eSOliver Stannard}
16478ec2e2eSOliver Stannard
16578ec2e2eSOliver Stannard; The IR for this one looks dodgy, because it has an alloca passed to a
16678ec2e2eSOliver Stannard; musttail function, but it is passed as a byval argument, so will be copied
16778ec2e2eSOliver Stannard; into the stack space allocated by @large_caller_new_value's caller, so is
16878ec2e2eSOliver Stannard; valid.
16978ec2e2eSOliver Stannarddefine void @large_caller_new_value(%twenty_bytes* byval(%twenty_bytes) align 4 %a) {
17078ec2e2eSOliver Stannard; CHECK-LABEL: large_caller_new_value:
17178ec2e2eSOliver Stannard; CHECK:       @ %bb.0: @ %entry
172*376d7b27SOliver Stannard; CHECK-NEXT:    .pad #36
173*376d7b27SOliver Stannard; CHECK-NEXT:    sub sp, sp, #36
174*376d7b27SOliver Stannard; CHECK-NEXT:    add r12, sp, #20
17578ec2e2eSOliver Stannard; CHECK-NEXT:    stm r12, {r0, r1, r2, r3}
17678ec2e2eSOliver Stannard; CHECK-NEXT:    mov r0, #4
177*376d7b27SOliver Stannard; CHECK-NEXT:    add r1, sp, #36
178*376d7b27SOliver Stannard; CHECK-NEXT:    str r0, [sp, #16]
17978ec2e2eSOliver Stannard; CHECK-NEXT:    mov r0, #3
180*376d7b27SOliver Stannard; CHECK-NEXT:    str r0, [sp, #12]
18178ec2e2eSOliver Stannard; CHECK-NEXT:    mov r0, #2
182*376d7b27SOliver Stannard; CHECK-NEXT:    str r0, [sp, #8]
18378ec2e2eSOliver Stannard; CHECK-NEXT:    mov r0, #1
184*376d7b27SOliver Stannard; CHECK-NEXT:    str r0, [sp, #4]
18578ec2e2eSOliver Stannard; CHECK-NEXT:    mov r0, #0
186*376d7b27SOliver Stannard; CHECK-NEXT:    str r0, [sp]
187*376d7b27SOliver Stannard; CHECK-NEXT:    mov r0, sp
188*376d7b27SOliver Stannard; CHECK-NEXT:    add r0, r0, #16
189*376d7b27SOliver Stannard; CHECK-NEXT:    mov r3, #3
19078ec2e2eSOliver Stannard; CHECK-NEXT:    ldr r2, [r0], #4
19178ec2e2eSOliver Stannard; CHECK-NEXT:    str r2, [r1], #4
192*376d7b27SOliver Stannard; CHECK-NEXT:    mov r0, #0
193*376d7b27SOliver Stannard; CHECK-NEXT:    mov r1, #1
194*376d7b27SOliver Stannard; CHECK-NEXT:    mov r2, #2
195*376d7b27SOliver Stannard; CHECK-NEXT:    add sp, sp, #36
19678ec2e2eSOliver Stannard; CHECK-NEXT:    b large_callee
19778ec2e2eSOliver Stannardentry:
19878ec2e2eSOliver Stannard  %y = alloca %twenty_bytes, align 4
19978ec2e2eSOliver Stannard  store i32 0, ptr %y, align 4
20078ec2e2eSOliver Stannard  %0 = getelementptr inbounds i8, ptr %y, i32 4
20178ec2e2eSOliver Stannard  store i32 1, ptr %0, align 4
20278ec2e2eSOliver Stannard  %1 = getelementptr inbounds i8, ptr %y, i32 8
20378ec2e2eSOliver Stannard  store i32 2, ptr %1, align 4
20478ec2e2eSOliver Stannard  %2 = getelementptr inbounds i8, ptr %y, i32 12
20578ec2e2eSOliver Stannard  store i32 3, ptr %2, align 4
20678ec2e2eSOliver Stannard  %3 = getelementptr inbounds i8, ptr %y, i32 16
20778ec2e2eSOliver Stannard  store i32 4, ptr %3, align 4
20878ec2e2eSOliver Stannard  musttail call void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %y)
20978ec2e2eSOliver Stannard  ret void
21078ec2e2eSOliver Stannard}
211914a3990SOliver Stannard
212914a3990SOliver Stannarddeclare void @two_byvals_callee(%twenty_bytes* byval(%twenty_bytes) align 4, %twenty_bytes* byval(%twenty_bytes) align 4)
213914a3990SOliver Stannarddefine void @swap_byvals(%twenty_bytes* byval(%twenty_bytes) align 4 %a, %twenty_bytes* byval(%twenty_bytes) align 4 %b) {
214914a3990SOliver Stannard; CHECK-LABEL: swap_byvals:
215914a3990SOliver Stannard; CHECK:       @ %bb.0: @ %entry
216914a3990SOliver Stannard; CHECK-NEXT:    .pad #16
217914a3990SOliver Stannard; CHECK-NEXT:    sub sp, sp, #16
218914a3990SOliver Stannard; CHECK-NEXT:    .save {r4, r5, r11, lr}
219914a3990SOliver Stannard; CHECK-NEXT:    push {r4, r5, r11, lr}
220914a3990SOliver Stannard; CHECK-NEXT:    .pad #40
221914a3990SOliver Stannard; CHECK-NEXT:    sub sp, sp, #40
222914a3990SOliver Stannard; CHECK-NEXT:    add r12, sp, #56
223914a3990SOliver Stannard; CHECK-NEXT:    add lr, sp, #20
224914a3990SOliver Stannard; CHECK-NEXT:    stm r12, {r0, r1, r2, r3}
225914a3990SOliver Stannard; CHECK-NEXT:    add r0, sp, #56
226914a3990SOliver Stannard; CHECK-NEXT:    mov r12, sp
227914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
228914a3990SOliver Stannard; CHECK-NEXT:    mov r2, r12
229914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
230914a3990SOliver Stannard; CHECK-NEXT:    add r3, sp, #20
231914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
232914a3990SOliver Stannard; CHECK-NEXT:    add r4, sp, #76
233914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
234914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
235914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
236914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
237914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
238914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
239914a3990SOliver Stannard; CHECK-NEXT:    add r0, sp, #76
240914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
241914a3990SOliver Stannard; CHECK-NEXT:    mov r2, lr
242914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
243914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
244914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
245914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
246914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
247914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
248914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
249914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
250914a3990SOliver Stannard; CHECK-NEXT:    ldr r1, [r0], #4
251914a3990SOliver Stannard; CHECK-NEXT:    str r1, [r2], #4
252914a3990SOliver Stannard; CHECK-NEXT:    ldm r3, {r0, r1, r2, r3}
253914a3990SOliver Stannard; CHECK-NEXT:    ldr r5, [r12], #4
254914a3990SOliver Stannard; CHECK-NEXT:    str r5, [r4], #4
255914a3990SOliver Stannard; CHECK-NEXT:    ldr r5, [r12], #4
256914a3990SOliver Stannard; CHECK-NEXT:    str r5, [r4], #4
257914a3990SOliver Stannard; CHECK-NEXT:    ldr r5, [r12], #4
258914a3990SOliver Stannard; CHECK-NEXT:    str r5, [r4], #4
259914a3990SOliver Stannard; CHECK-NEXT:    ldr r5, [r12], #4
260914a3990SOliver Stannard; CHECK-NEXT:    str r5, [r4], #4
261914a3990SOliver Stannard; CHECK-NEXT:    ldr r5, [r12], #4
262914a3990SOliver Stannard; CHECK-NEXT:    str r5, [r4], #4
263914a3990SOliver Stannard; CHECK-NEXT:    add r5, lr, #16
264914a3990SOliver Stannard; CHECK-NEXT:    add r12, sp, #72
265914a3990SOliver Stannard; CHECK-NEXT:    ldr r4, [r5], #4
266914a3990SOliver Stannard; CHECK-NEXT:    str r4, [r12], #4
267914a3990SOliver Stannard; CHECK-NEXT:    add sp, sp, #40
268914a3990SOliver Stannard; CHECK-NEXT:    pop {r4, r5, r11, lr}
269914a3990SOliver Stannard; CHECK-NEXT:    add sp, sp, #16
270914a3990SOliver Stannard; CHECK-NEXT:    b two_byvals_callee
271914a3990SOliver Stannardentry:
272914a3990SOliver Stannard  musttail call void @two_byvals_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %b, %twenty_bytes* byval(%twenty_bytes) align 4 %a)
273914a3990SOliver Stannard  ret void
274914a3990SOliver Stannard}
275*376d7b27SOliver Stannard
276*376d7b27SOliver Stannard; A forwarded byval arg, but at a different offset on the stack, so it needs to
277*376d7b27SOliver Stannard; be copied to the local stack frame first. This can't be musttail because of
278*376d7b27SOliver Stannard; the different signatures, but is still tail-called as an optimisation.
279*376d7b27SOliver Stannarddeclare void @shift_byval_callee(%twenty_bytes* byval(%twenty_bytes) align 4)
280*376d7b27SOliver Stannarddefine void @shift_byval(i32 %a, %twenty_bytes* byval(%twenty_bytes) align 4 %b) {
281*376d7b27SOliver Stannard; CHECK-LABEL: shift_byval:
282*376d7b27SOliver Stannard; CHECK:       @ %bb.0: @ %entry
283*376d7b27SOliver Stannard; CHECK-NEXT:    .pad #12
284*376d7b27SOliver Stannard; CHECK-NEXT:    sub sp, sp, #12
285*376d7b27SOliver Stannard; CHECK-NEXT:    .save {r4, lr}
286*376d7b27SOliver Stannard; CHECK-NEXT:    push {r4, lr}
287*376d7b27SOliver Stannard; CHECK-NEXT:    .pad #20
288*376d7b27SOliver Stannard; CHECK-NEXT:    sub sp, sp, #20
289*376d7b27SOliver Stannard; CHECK-NEXT:    add r0, sp, #28
290*376d7b27SOliver Stannard; CHECK-NEXT:    add lr, sp, #40
291*376d7b27SOliver Stannard; CHECK-NEXT:    stm r0, {r1, r2, r3}
292*376d7b27SOliver Stannard; CHECK-NEXT:    add r0, sp, #28
293*376d7b27SOliver Stannard; CHECK-NEXT:    mov r1, sp
294*376d7b27SOliver Stannard; CHECK-NEXT:    ldr r2, [r0], #4
295*376d7b27SOliver Stannard; CHECK-NEXT:    add r12, r1, #16
296*376d7b27SOliver Stannard; CHECK-NEXT:    str r2, [r1], #4
297*376d7b27SOliver Stannard; CHECK-NEXT:    ldr r2, [r0], #4
298*376d7b27SOliver Stannard; CHECK-NEXT:    str r2, [r1], #4
299*376d7b27SOliver Stannard; CHECK-NEXT:    ldr r2, [r0], #4
300*376d7b27SOliver Stannard; CHECK-NEXT:    str r2, [r1], #4
301*376d7b27SOliver Stannard; CHECK-NEXT:    ldr r2, [r0], #4
302*376d7b27SOliver Stannard; CHECK-NEXT:    str r2, [r1], #4
303*376d7b27SOliver Stannard; CHECK-NEXT:    ldr r2, [r0], #4
304*376d7b27SOliver Stannard; CHECK-NEXT:    str r2, [r1], #4
305*376d7b27SOliver Stannard; CHECK-NEXT:    ldm sp, {r0, r1, r2, r3}
306*376d7b27SOliver Stannard; CHECK-NEXT:    ldr r4, [r12], #4
307*376d7b27SOliver Stannard; CHECK-NEXT:    str r4, [lr], #4
308*376d7b27SOliver Stannard; CHECK-NEXT:    add sp, sp, #20
309*376d7b27SOliver Stannard; CHECK-NEXT:    pop {r4, lr}
310*376d7b27SOliver Stannard; CHECK-NEXT:    add sp, sp, #12
311*376d7b27SOliver Stannard; CHECK-NEXT:    b shift_byval_callee
312*376d7b27SOliver Stannardentry:
313*376d7b27SOliver Stannard  tail call void @shift_byval_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %b)
314*376d7b27SOliver Stannard  ret void
315*376d7b27SOliver Stannard}
316*376d7b27SOliver Stannard
317*376d7b27SOliver Stannard; A global object passed to a byval argument, so it must be copied, but doesn't
318*376d7b27SOliver Stannard; need a stack temporary.
319*376d7b27SOliver Stannard@large_global = external global %twenty_bytes
320*376d7b27SOliver Stannarddefine void @large_caller_from_global(%twenty_bytes* byval(%twenty_bytes) align 4 %a) {
321*376d7b27SOliver Stannard; CHECK-LABEL: large_caller_from_global:
322*376d7b27SOliver Stannard; CHECK:       @ %bb.0: @ %entry
323*376d7b27SOliver Stannard; CHECK-NEXT:    .pad #16
324*376d7b27SOliver Stannard; CHECK-NEXT:    sub sp, sp, #16
325*376d7b27SOliver Stannard; CHECK-NEXT:    .save {r4, lr}
326*376d7b27SOliver Stannard; CHECK-NEXT:    push {r4, lr}
327*376d7b27SOliver Stannard; CHECK-NEXT:    add r12, sp, #8
328*376d7b27SOliver Stannard; CHECK-NEXT:    add lr, sp, #24
329*376d7b27SOliver Stannard; CHECK-NEXT:    stm r12, {r0, r1, r2, r3}
330*376d7b27SOliver Stannard; CHECK-NEXT:    movw r3, :lower16:large_global
331*376d7b27SOliver Stannard; CHECK-NEXT:    movt r3, :upper16:large_global
332*376d7b27SOliver Stannard; CHECK-NEXT:    add r12, r3, #16
333*376d7b27SOliver Stannard; CHECK-NEXT:    ldm r3, {r0, r1, r2, r3}
334*376d7b27SOliver Stannard; CHECK-NEXT:    ldr r4, [r12], #4
335*376d7b27SOliver Stannard; CHECK-NEXT:    str r4, [lr], #4
336*376d7b27SOliver Stannard; CHECK-NEXT:    pop {r4, lr}
337*376d7b27SOliver Stannard; CHECK-NEXT:    add sp, sp, #16
338*376d7b27SOliver Stannard; CHECK-NEXT:    b large_callee
339*376d7b27SOliver Stannardentry:
340*376d7b27SOliver Stannard  musttail call void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4 @large_global)
341*376d7b27SOliver Stannard  ret void
342*376d7b27SOliver Stannard}
343