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