llvm/llvm/test/CodeGen/X86/preserve_nonecc_call.ll

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
; RUN: llc -mtriple=x86_64-unknown-unknown -mcpu=corei7 < %s | FileCheck %s

; This test checks various function call behaviors between preserve_none and
; normal calling conventions.

declare preserve_nonecc void @callee(ptr)

; Normal caller calls preserve_none callee. Will not generated tail call because
; of incompatible calling convention. Callee saved registers are saved/restored
; around the call.
define void @caller1(ptr %a) {
; CHECK-LABEL: caller1:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pushq %r15
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    pushq %r14
; CHECK-NEXT:    .cfi_def_cfa_offset 24
; CHECK-NEXT:    pushq %r13
; CHECK-NEXT:    .cfi_def_cfa_offset 32
; CHECK-NEXT:    pushq %r12
; CHECK-NEXT:    .cfi_def_cfa_offset 40
; CHECK-NEXT:    pushq %rbx
; CHECK-NEXT:    .cfi_def_cfa_offset 48
; CHECK-NEXT:    .cfi_offset %rbx, -48
; CHECK-NEXT:    .cfi_offset %r12, -40
; CHECK-NEXT:    .cfi_offset %r13, -32
; CHECK-NEXT:    .cfi_offset %r14, -24
; CHECK-NEXT:    .cfi_offset %r15, -16
; CHECK-NEXT:    movq %rdi, %r12
; CHECK-NEXT:    callq callee@PLT
; CHECK-NEXT:    popq %rbx
; CHECK-NEXT:    .cfi_def_cfa_offset 40
; CHECK-NEXT:    popq %r12
; CHECK-NEXT:    .cfi_def_cfa_offset 32
; CHECK-NEXT:    popq %r13
; CHECK-NEXT:    .cfi_def_cfa_offset 24
; CHECK-NEXT:    popq %r14
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    popq %r15
; CHECK-NEXT:    .cfi_def_cfa_offset 8
; CHECK-NEXT:    retq
  tail call preserve_nonecc void @callee(ptr %a)
  ret void
}

; Preserve_none caller calls preserve_none callee. Same function body.
; The tail call is preserved. No registers are saved/restored around the call.
; Actually a simple jmp instruction is generated.
define preserve_nonecc void @caller2(ptr %a) {
; CHECK-LABEL: caller2:
; CHECK:       # %bb.0:
; CHECK-NEXT:    jmp callee@PLT # TAILCALL
  tail call preserve_nonecc void @callee(ptr %a)
  ret void
}

; Preserve_none function can use more registers to pass parameters.
declare preserve_nonecc i64 @callee_with_many_param2(i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11)
define preserve_nonecc i64 @callee_with_many_param(i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12) {
; CHECK-LABEL: callee_with_many_param:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pushq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    movq %r13, %r12
; CHECK-NEXT:    movq %r14, %r13
; CHECK-NEXT:    movq %r15, %r14
; CHECK-NEXT:    movq %rdi, %r15
; CHECK-NEXT:    movq %rsi, %rdi
; CHECK-NEXT:    movq %rdx, %rsi
; CHECK-NEXT:    movq %rcx, %rdx
; CHECK-NEXT:    movq %r8, %rcx
; CHECK-NEXT:    movq %r9, %r8
; CHECK-NEXT:    movq %r11, %r9
; CHECK-NEXT:    movq %rax, %r11
; CHECK-NEXT:    callq callee_with_many_param2@PLT
; CHECK-NEXT:    popq %rcx
; CHECK-NEXT:    .cfi_def_cfa_offset 8
; CHECK-NEXT:    retq
  %ret = call preserve_nonecc i64 @callee_with_many_param2(i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12)
  ret i64 %ret
}

define i64 @caller3() {
; CHECK-LABEL: caller3:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pushq %r15
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    pushq %r14
; CHECK-NEXT:    .cfi_def_cfa_offset 24
; CHECK-NEXT:    pushq %r13
; CHECK-NEXT:    .cfi_def_cfa_offset 32
; CHECK-NEXT:    pushq %r12
; CHECK-NEXT:    .cfi_def_cfa_offset 40
; CHECK-NEXT:    pushq %rbx
; CHECK-NEXT:    .cfi_def_cfa_offset 48
; CHECK-NEXT:    .cfi_offset %rbx, -48
; CHECK-NEXT:    .cfi_offset %r12, -40
; CHECK-NEXT:    .cfi_offset %r13, -32
; CHECK-NEXT:    .cfi_offset %r14, -24
; CHECK-NEXT:    .cfi_offset %r15, -16
; CHECK-NEXT:    movl $1, %r12d
; CHECK-NEXT:    movl $2, %r13d
; CHECK-NEXT:    movl $3, %r14d
; CHECK-NEXT:    movl $4, %r15d
; CHECK-NEXT:    movl $5, %edi
; CHECK-NEXT:    movl $6, %esi
; CHECK-NEXT:    movl $7, %edx
; CHECK-NEXT:    movl $8, %ecx
; CHECK-NEXT:    movl $9, %r8d
; CHECK-NEXT:    movl $10, %r9d
; CHECK-NEXT:    movl $11, %r11d
; CHECK-NEXT:    movl $12, %eax
; CHECK-NEXT:    callq callee_with_many_param@PLT
; CHECK-NEXT:    popq %rbx
; CHECK-NEXT:    .cfi_def_cfa_offset 40
; CHECK-NEXT:    popq %r12
; CHECK-NEXT:    .cfi_def_cfa_offset 32
; CHECK-NEXT:    popq %r13
; CHECK-NEXT:    .cfi_def_cfa_offset 24
; CHECK-NEXT:    popq %r14
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    popq %r15
; CHECK-NEXT:    .cfi_def_cfa_offset 8
; CHECK-NEXT:    retq
  %ret = call preserve_nonecc i64 @callee_with_many_param(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12)
  ret i64 %ret
}

; Non-volatile registers are used to pass the first few parameters.
declare void @boring()
declare preserve_nonecc void @continuation(ptr, ptr, ptr, ptr)
define preserve_nonecc void @entry(ptr %r12, ptr %r13, ptr %r14, ptr %r15) {
; CHECK-LABEL: entry:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pushq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    callq boring@PLT
; CHECK-NEXT:    popq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 8
; CHECK-NEXT:    jmp continuation@PLT # TAILCALL
  call void @boring()
  musttail call preserve_nonecc void @continuation(ptr %r12, ptr %r13, ptr %r14, ptr %r15)
  ret void
}