| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: llc < %s -mtriple=arm64-apple-ios -o - | FileCheck %s | |
| declare swiftcc ptr @swift_task_alloc(i64) | |
| ; A musttail call modelling a swiftasync context reallocation thunk, whose 10 | |
| ; ordinary arguments overflow the 8 GPR argument registers, leaving 9 bytes of | |
| ; stack arg area: | |
| ; * Formal arguments %1-%8 are forwarded in registers x0-x7 | |
| ; * swiftasync and swiftself don't count agaginst the usual 8 GPR argument | |
| ; list, and are are passed in dedicated registers (x22/x20) | |
| ; * ptr %9 (8 bytes) and i1 %10 (1 byte) are passed on the stack, packed in 9 | |
| ; contiguous bytes | |
| ; We round up that stack arg area to keep the FPDiff (and therefore the stack) | |
| ; 16-byte aligned going into the callee. | |
| define swifttailcc void @thunk(ptr %1, ptr swiftasync %sa, i64 %2, i64 %3, i64 %4, ptr %5, i64 %6, ptr %7, ptr %8, ptr %9, i1 %10, ptr swiftself %self) #0 { | |
| ; CHECK-LABEL: thunk: | |
| ; CHECK: ; %bb.0: ; %entry | |
| ; CHECK-NEXT: orr x29, x29, #0x1000000000000000 | |
| ; CHECK-NEXT: sub sp, sp, #96 | |
| ; CHECK-NEXT: stp x28, x27, [sp, #8] ; 16-byte Folded Spill | |
| ; CHECK-NEXT: mov x27, x1 | |
| ; CHECK-NEXT: mov x28, x0 | |
| ; CHECK-NEXT: stp x26, x25, [sp, #24] ; 16-byte Folded Spill | |
| ; CHECK-NEXT: mov w0, #64 ; =0x40 | |
| ; CHECK-NEXT: mov x25, x3 | |
| ; CHECK-NEXT: stp x24, x23, [sp, #40] ; 16-byte Folded Spill | |
| ; CHECK-NEXT: mov x23, x5 | |
| ; CHECK-NEXT: mov x24, x4 | |
| ; CHECK-NEXT: stp x21, x19, [sp, #56] ; 16-byte Folded Spill | |
| ; CHECK-NEXT: mov x19, x7 | |
| ; CHECK-NEXT: mov x21, x6 | |
| ; CHECK-NEXT: stp x29, x30, [sp, #80] ; 16-byte Folded Spill | |
| ; CHECK-NEXT: add x29, sp, #80 | |
| ; CHECK-NEXT: mov x26, x2 | |
| ; CHECK-NEXT: str x22, [sp, #72] | |
| ; CHECK-NEXT: ldr x1, [x20] | |
| ; CHECK-NEXT: str x1, [sp] ; 8-byte Spill | |
| ; CHECK-NEXT: bl _swift_task_alloc | |
| ; CHECK-NEXT: ldp x29, x30, [sp, #80] ; 16-byte Folded Reload | |
| ; CHECK-NEXT: mov x8, x0 | |
| ; CHECK-NEXT: str x0, [x22, #16] | |
| ; CHECK-NEXT: mov x0, x28 | |
| ; CHECK-NEXT: mov x1, x27 | |
| ; CHECK-NEXT: mov x2, x26 | |
| ; CHECK-NEXT: mov x3, x25 | |
| ; CHECK-NEXT: mov x4, x24 | |
| ; CHECK-NEXT: mov x5, x23 | |
| ; CHECK-NEXT: mov x6, x21 | |
| ; CHECK-NEXT: mov x7, x19 | |
| ; CHECK-NEXT: ldp x21, x19, [sp, #56] ; 16-byte Folded Reload | |
| ; CHECK-NEXT: mov x22, x8 | |
| ; CHECK-NEXT: ldp x24, x23, [sp, #40] ; 16-byte Folded Reload | |
| ; CHECK-NEXT: ldr x8, [sp] ; 8-byte Reload | |
| ; CHECK-NEXT: ldp x26, x25, [sp, #24] ; 16-byte Folded Reload | |
| ; CHECK-NEXT: and x29, x29, #0xefffffffffffffff | |
| ; CHECK-NEXT: ldp x28, x27, [sp, #8] ; 16-byte Folded Reload | |
| ; CHECK-NEXT: add sp, sp, #96 | |
| ; CHECK-NEXT: br x8 | |
| entry: | |
| %oldCtx = getelementptr inbounds i8, ptr %sa, i64 16 | |
| %fn = load ptr, ptr %self, align 8 | |
| %newCtx = call swiftcc ptr @swift_task_alloc(i64 64) | |
| store ptr %newCtx, ptr %oldCtx, align 8 | |
| musttail call swifttailcc void %fn(ptr %1, ptr swiftasync %newCtx, i64 %2, i64 %3, i64 %4, ptr %5, i64 %6, ptr %7, ptr %8, ptr %9, i1 %10, ptr swiftself %self) | |
| ret void | |
| } | |
| ; A musttail call from a function with no arguments (and therefore no reusable | |
| ; stack arg area) to a function with 11 i32 arguments that overflow the 8 GPR | |
| ; argument registers, leaving 4 bytes of stack arg area: | |
| ; * The first 8 i32 arguments land in registers w0-w7 | |
| ; * The arg is passed on the stack, consuming 4 bytes | |
| ; We round up that stack arg area to keep the FPDiff (and therefore the stack) | |
| ; 16-byte aligned going into the callee. | |
| define swifttailcc void @caller_no_args() { | |
| ; CHECK-LABEL: caller_no_args: | |
| ; CHECK: ; %bb.0: ; %entry | |
| ; CHECK-NEXT: mov w8, #8 ; =0x8 | |
| ; CHECK-NEXT: str w8, [sp, #-16]! | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 | |
| ; CHECK-NEXT: mov w0, wzr | |
| ; CHECK-NEXT: mov w1, #1 ; =0x1 | |
| ; CHECK-NEXT: mov w2, #2 ; =0x2 | |
| ; CHECK-NEXT: mov w3, #3 ; =0x3 | |
| ; CHECK-NEXT: mov w4, #4 ; =0x4 | |
| ; CHECK-NEXT: mov w5, #5 ; =0x5 | |
| ; CHECK-NEXT: mov w6, #6 ; =0x6 | |
| ; CHECK-NEXT: mov w7, #7 ; =0x7 | |
| ; CHECK-NEXT: b _callee_11_args | |
| entry: | |
| musttail call swifttailcc void @callee_11_args(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8) | |
| ret void | |
| } | |
| ; The corresponding callee pops swifttail callee, with 11 i32 arguments that | |
| ; overflow the 8 GPR argument registers, leaving 4 bytes of stack arg area, | |
| ; which is rounded up to keep the stack 16-byte aligned. The amount popped here | |
| ; must match what was pushed in @caller_no_args. | |
| define swifttailcc void @callee_11_args(i32, i32, i32, i32, i32, i32, i32, i32, i32) "noinline" { | |
| ; CHECK-LABEL: callee_11_args: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: add sp, sp, #16 | |
| ; CHECK-NEXT: ret | |
| ret void | |
| } | |
| attributes #0 = { nounwind "frame-pointer"="non-leaf-no-reserve" } |