blob: df64b704a361f8f510a924cd5fb0e845075683f4 [file] [edit]
; 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
}