| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no_x86_scrub_sp --version 6 | |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -no-x86-call-frame-opt | FileCheck %s | |
| ; PR105223: a tailcc callee pops its stack arguments. When one of them needs a | |
| ; 16-byte aligned slot, the caller must expect the amount the callee pops, | |
| ; around a normal call and when it moves the return address for a musttail | |
| ; call. | |
| ; %x takes the 16-byte aligned slot at offset 0 and %p the one at offset 16, | |
| ; so the callee pops 24 bytes. | |
| define internal tailcc void @callee_i128(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i128 %x, ptr %p) noinline { | |
| ; CHECK-LABEL: callee_i128: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: retq $24 | |
| ret void | |
| } | |
| define void @call_i128() nounwind { | |
| ; CHECK-LABEL: call_i128: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: subq $24, %rsp | |
| ; CHECK-NEXT: movq $0, 16(%rsp) | |
| ; CHECK-NEXT: movq $0, 8(%rsp) | |
| ; CHECK-NEXT: movq $6, (%rsp) | |
| ; CHECK-NEXT: movl $1, %esi | |
| ; CHECK-NEXT: movl $2, %edx | |
| ; CHECK-NEXT: movl $3, %ecx | |
| ; CHECK-NEXT: movl $4, %r8d | |
| ; CHECK-NEXT: movl $5, %r9d | |
| ; CHECK-NEXT: xorl %edi, %edi | |
| ; CHECK-NEXT: callq callee_i128 | |
| ; CHECK-NEXT: retq | |
| call tailcc void @callee_i128(i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i128 6, ptr null) | |
| ret void | |
| } | |
| ; The ninth vector argument takes a 16-byte aligned stack slot in the same way. | |
| define internal tailcc void @callee_v4f32(<4 x float> %v0, <4 x float> %v1, <4 x float> %v2, <4 x float> %v3, <4 x float> %v4, <4 x float> %v5, <4 x float> %v6, <4 x float> %v7, <4 x float> %v8, i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, ptr %p) noinline { | |
| ; CHECK-LABEL: callee_v4f32: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: retq $24 | |
| ret void | |
| } | |
| define void @call_v4f32() nounwind { | |
| ; CHECK-LABEL: call_v4f32: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: subq $24, %rsp | |
| ; CHECK-NEXT: xorps %xmm0, %xmm0 | |
| ; CHECK-NEXT: movaps %xmm0, (%rsp) | |
| ; CHECK-NEXT: movq $0, 16(%rsp) | |
| ; CHECK-NEXT: xorps %xmm1, %xmm1 | |
| ; CHECK-NEXT: xorps %xmm2, %xmm2 | |
| ; CHECK-NEXT: xorps %xmm3, %xmm3 | |
| ; CHECK-NEXT: xorps %xmm4, %xmm4 | |
| ; CHECK-NEXT: xorps %xmm5, %xmm5 | |
| ; CHECK-NEXT: xorps %xmm6, %xmm6 | |
| ; CHECK-NEXT: xorps %xmm7, %xmm7 | |
| ; CHECK-NEXT: movl $1, %esi | |
| ; CHECK-NEXT: movl $2, %edx | |
| ; CHECK-NEXT: movl $3, %ecx | |
| ; CHECK-NEXT: movl $4, %r8d | |
| ; CHECK-NEXT: movl $5, %r9d | |
| ; CHECK-NEXT: xorl %edi, %edi | |
| ; CHECK-NEXT: callq callee_v4f32 | |
| ; CHECK-NEXT: retq | |
| call tailcc void @callee_v4f32(<4 x float> zeroinitializer, <4 x float> zeroinitializer, <4 x float> zeroinitializer, <4 x float> zeroinitializer, <4 x float> zeroinitializer, <4 x float> zeroinitializer, <4 x float> zeroinitializer, <4 x float> zeroinitializer, <4 x float> zeroinitializer, i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, ptr null) | |
| ret void | |
| } | |
| ; @musttail_i128 pops 8 bytes and its callee 24, so the return address moves | |
| ; down by 16 bytes. | |
| declare tailcc ptr @callee_i128_ptr(ptr, ptr, ptr, ptr, ptr, ptr, i128, ptr) | |
| define tailcc ptr @musttail_i128(ptr %p) nounwind { | |
| ; CHECK-LABEL: musttail_i128: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: subq $16, %rsp | |
| ; CHECK-NEXT: movq %rdi, 24(%rsp) | |
| ; CHECK-NEXT: movq 16(%rsp), %rax | |
| ; CHECK-NEXT: xorps %xmm0, %xmm0 | |
| ; CHECK-NEXT: movaps %xmm0, 8(%rsp) | |
| ; CHECK-NEXT: movq %rax, (%rsp) | |
| ; CHECK-NEXT: movq %rdi, %rsi | |
| ; CHECK-NEXT: movq %rdi, %rdx | |
| ; CHECK-NEXT: movq %rdi, %rcx | |
| ; CHECK-NEXT: movq %rdi, %r8 | |
| ; CHECK-NEXT: movq %rdi, %r9 | |
| ; CHECK-NEXT: jmp callee_i128_ptr@PLT # TAILCALL | |
| %r = musttail call tailcc ptr @callee_i128_ptr(ptr %p, ptr %p, ptr %p, ptr %p, ptr %p, ptr %p, i128 0, ptr %p) | |
| ret ptr %r | |
| } | |
| ; Based on the original report. The i256 parts take 8-byte slots. | |
| declare tailcc ptr @callee_i256(ptr, ptr, ptr, ptr, i256, i256, ptr) | |
| define tailcc ptr @musttail_i256(ptr %p) nounwind { | |
| ; CHECK-LABEL: musttail_i256: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: subq $48, %rsp | |
| ; CHECK-NEXT: xorps %xmm0, %xmm0 | |
| ; CHECK-NEXT: movaps %xmm0, 8(%rsp) | |
| ; CHECK-NEXT: movaps %xmm0, 24(%rsp) | |
| ; CHECK-NEXT: movq %rdi, 56(%rsp) | |
| ; CHECK-NEXT: movq 48(%rsp), %rax | |
| ; CHECK-NEXT: movaps %xmm0, 40(%rsp) | |
| ; CHECK-NEXT: movq %rax, (%rsp) | |
| ; CHECK-NEXT: movq %rdi, %rsi | |
| ; CHECK-NEXT: movq %rdi, %rdx | |
| ; CHECK-NEXT: movq %rdi, %rcx | |
| ; CHECK-NEXT: xorl %r8d, %r8d | |
| ; CHECK-NEXT: xorl %r9d, %r9d | |
| ; CHECK-NEXT: jmp callee_i256@PLT # TAILCALL | |
| %r = musttail call tailcc ptr @callee_i256(ptr %p, ptr %p, ptr %p, ptr %p, i256 0, i256 0, ptr %p) | |
| ret ptr %r | |
| } | |
| ; The same calls from functions whose own stack is realigned. With a dynamic | |
| ; alloca the call frame is not reserved in the prologue, so the adjustment | |
| ; around the call shows the size the caller expects the callee to pop. | |
| declare void @use(ptr) | |
| define void @call_i128_realigned_dynalloca(i64 %n) nounwind { | |
| ; CHECK-LABEL: call_i128_realigned_dynalloca: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: pushq %rbp | |
| ; CHECK-NEXT: movq %rsp, %rbp | |
| ; CHECK-NEXT: pushq %r14 | |
| ; CHECK-NEXT: pushq %rbx | |
| ; CHECK-NEXT: andq $-64, %rsp | |
| ; CHECK-NEXT: subq $64, %rsp | |
| ; CHECK-NEXT: movq %rsp, %rbx | |
| ; CHECK-NEXT: movq %rsp, %r14 | |
| ; CHECK-NEXT: addq $15, %rdi | |
| ; CHECK-NEXT: andq $-16, %rdi | |
| ; CHECK-NEXT: subq %rdi, %r14 | |
| ; CHECK-NEXT: movq %r14, %rsp | |
| ; CHECK-NEXT: movq %rbx, %rdi | |
| ; CHECK-NEXT: callq use@PLT | |
| ; CHECK-NEXT: movq %r14, %rdi | |
| ; CHECK-NEXT: callq use@PLT | |
| ; CHECK-NEXT: subq $32, %rsp | |
| ; CHECK-NEXT: movq $0, 16(%rsp) | |
| ; CHECK-NEXT: movq $0, 8(%rsp) | |
| ; CHECK-NEXT: movq $6, (%rsp) | |
| ; CHECK-NEXT: movl $1, %esi | |
| ; CHECK-NEXT: movl $2, %edx | |
| ; CHECK-NEXT: movl $3, %ecx | |
| ; CHECK-NEXT: movl $4, %r8d | |
| ; CHECK-NEXT: movl $5, %r9d | |
| ; CHECK-NEXT: xorl %edi, %edi | |
| ; CHECK-NEXT: callq callee_i128 | |
| ; CHECK-NEXT: leaq -16(%rbp), %rsp | |
| ; CHECK-NEXT: popq %rbx | |
| ; CHECK-NEXT: popq %r14 | |
| ; CHECK-NEXT: popq %rbp | |
| ; CHECK-NEXT: retq | |
| %a = alloca i32, align 64 | |
| %d = alloca i8, i64 %n | |
| call void @use(ptr %a) | |
| call void @use(ptr %d) | |
| call tailcc void @callee_i128(i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i128 6, ptr null) | |
| ret void | |
| } | |
| define tailcc ptr @musttail_i128_realigned(ptr %p) nounwind { | |
| ; CHECK-LABEL: musttail_i128_realigned: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: subq $16, %rsp | |
| ; CHECK-NEXT: pushq %rbp | |
| ; CHECK-NEXT: movq %rsp, %rbp | |
| ; CHECK-NEXT: pushq %rbx | |
| ; CHECK-NEXT: andq $-64, %rsp | |
| ; CHECK-NEXT: subq $64, %rsp | |
| ; CHECK-NEXT: movq %rdi, %rbx | |
| ; CHECK-NEXT: movq %rsp, %rdi | |
| ; CHECK-NEXT: callq use@PLT | |
| ; CHECK-NEXT: movq %rbx, 32(%rbp) | |
| ; CHECK-NEXT: movq 24(%rbp), %rax | |
| ; CHECK-NEXT: xorps %xmm0, %xmm0 | |
| ; CHECK-NEXT: movaps %xmm0, 16(%rbp) | |
| ; CHECK-NEXT: movq %rax, 8(%rbp) | |
| ; CHECK-NEXT: movq %rbx, %rdi | |
| ; CHECK-NEXT: movq %rbx, %rsi | |
| ; CHECK-NEXT: movq %rbx, %rdx | |
| ; CHECK-NEXT: movq %rbx, %rcx | |
| ; CHECK-NEXT: movq %rbx, %r8 | |
| ; CHECK-NEXT: movq %rbx, %r9 | |
| ; CHECK-NEXT: leaq -8(%rbp), %rsp | |
| ; CHECK-NEXT: popq %rbx | |
| ; CHECK-NEXT: popq %rbp | |
| ; CHECK-NEXT: jmp callee_i128_ptr@PLT # TAILCALL | |
| %a = alloca i32, align 64 | |
| call void @use(ptr %a) | |
| %r = musttail call tailcc ptr @callee_i128_ptr(ptr %p, ptr %p, ptr %p, ptr %p, ptr %p, ptr %p, i128 0, ptr %p) | |
| ret ptr %r | |
| } |