; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --remove_checks
; RUN: llc < %s -march=colossus -colossus-coissue=false -mattr=+ipu1 | FileCheck %s  --check-prefixes=CHECK_SP,IPU1_2_SP
; RUN: llc < %s -march=colossus -colossus-coissue=false -mattr=+ipu2 | FileCheck %s  --check-prefixes=CHECK_SP,IPU1_2_SP
; RUN: llc < %s -march=colossus -colossus-coissue=false -mattr=+ipu1 -frame-pointer=all | FileCheck %s --check-prefixes=CHECK_FP,IPU1_2_FP
; RUN: llc < %s -march=colossus -colossus-coissue=false -mattr=+ipu2 -frame-pointer=all | FileCheck %s --check-prefixes=CHECK_FP,IPU1_2_FP

; Test basic calling with four arguments passed in [$m0, $m3]. The stack frame
; is one word to acommodate the spilt link register.
declare void @callee_regs(i32 %a1, i32 %a2, i32 %a3, i32 %a4)
define void @caller_regs() {
; CHECK_SP-LABEL: caller_regs:
; CHECK_SP:       # %bb.0:
; CHECK_SP-NEXT:    add $m11, $m11, -8
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 8
; CHECK_SP-NEXT:    .cfi_offset $m10, -4
; CHECK_SP-NEXT:    st32 $m10, $m11, $m15, 1 # 4-byte Folded Spill
; CHECK_SP-NEXT:    setzi $m0, 1
; CHECK_SP-NEXT:    setzi $m1, 2
; CHECK_SP-NEXT:    setzi $m2, 3
; CHECK_SP-NEXT:    setzi $m3, 4
; CHECK_SP-NEXT:    call $m10, callee_regs
; CHECK_SP-NEXT:    ld32 $m10, $m11, $m15, 1 # 4-byte Folded Reload
; CHECK_SP-NEXT:    add $m11, $m11, 8
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 0
; CHECK_SP-NEXT:    br $m10
;
; CHECK_FP-LABEL: caller_regs:
; CHECK_FP:       # %bb.0:
; CHECK_FP-NEXT:    add $m11, $m11, -8
; CHECK_FP-NEXT:    st32 $m9, $m11, $m15, 0 # 4-byte Folded Spill
; CHECK_FP-NEXT:    mov $m9, $m11
; CHECK_FP-NEXT:    .cfi_def_cfa $m9, 8
; CHECK_FP-NEXT:    .cfi_offset $m9, -8
; CHECK_FP-NEXT:    .cfi_offset $m10, -4
; CHECK_FP-NEXT:    st32 $m10, $m9, $m15, 1 # 4-byte Folded Spill
; CHECK_FP-NEXT:    setzi $m0, 1
; CHECK_FP-NEXT:    setzi $m1, 2
; CHECK_FP-NEXT:    setzi $m2, 3
; CHECK_FP-NEXT:    setzi $m3, 4
; CHECK_FP-NEXT:    call $m10, callee_regs
; CHECK_FP-NEXT:    ld32 $m10, $m9, $m15, 1 # 4-byte Folded Reload
; CHECK_FP-NEXT:    add $m11, $m9, 8
; CHECK_FP-NEXT:    ld32 $m9, $m9, $m15, 0 # 4-byte Folded Reload
; CHECK_FP-NEXT:    .cfi_def_cfa_register $m11
; CHECK_FP-NEXT:    br $m10
  call void @callee_regs(i32 1, i32 2, i32 3, i32 4)
  ret void
}

; Test basic calling with four arguments passed in [$m0, $m3] and two on the stack.
; The stack frame accomodates the spilt link register and two arguments.
declare void @callee_stack_mrf(i32 %a1, i32 %a2, i32 %a3, i32 %a4,
                               i32 %a5, i32 %a6)
define void @caller_stack_mrf() {
; CHECK_SP-LABEL: caller_stack_mrf:
; CHECK_SP:       # %bb.0:
; CHECK_SP-NEXT:    add $m11, $m11, -16
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 16
; CHECK_SP-NEXT:    .cfi_offset $m10, -4
; CHECK_SP-NEXT:    st32 $m10, $m11, $m15, 3 # 4-byte Folded Spill
; CHECK_SP-NEXT:    setzi $a0, 6
; CHECK_SP-NEXT:    st32 $a0, $m11, $m15, 1
; CHECK_SP-NEXT:    setzi $a0, 5
; CHECK_SP-NEXT:    st32 $a0, $m11, $m15, 0
; CHECK_SP-NEXT:    setzi $m0, 1
; CHECK_SP-NEXT:    setzi $m1, 2
; CHECK_SP-NEXT:    setzi $m2, 3
; CHECK_SP-NEXT:    setzi $m3, 4
; CHECK_SP-NEXT:    call $m10, callee_stack_mrf
; CHECK_SP-NEXT:    ld32 $m10, $m11, $m15, 3 # 4-byte Folded Reload
; CHECK_SP-NEXT:    add $m11, $m11, 16
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 0
; CHECK_SP-NEXT:    br $m10
;
; CHECK_FP-LABEL: caller_stack_mrf:
; CHECK_FP:       # %bb.0:
; CHECK_FP-NEXT:    add $m11, $m11, -16
; CHECK_FP-NEXT:    st32 $m9, $m11, $m15, 2 # 4-byte Folded Spill
; CHECK_FP-NEXT:    mov $m9, $m11
; CHECK_FP-NEXT:    .cfi_def_cfa $m9, 16
; CHECK_FP-NEXT:    .cfi_offset $m9, -8
; CHECK_FP-NEXT:    .cfi_offset $m10, -4
; CHECK_FP-NEXT:    st32 $m10, $m9, $m15, 3 # 4-byte Folded Spill
; CHECK_FP-NEXT:    setzi $a0, 6
; CHECK_FP-NEXT:    st32 $a0, $m11, $m15, 1
; CHECK_FP-NEXT:    setzi $a0, 5
; CHECK_FP-NEXT:    st32 $a0, $m11, $m15, 0
; CHECK_FP-NEXT:    setzi $m0, 1
; CHECK_FP-NEXT:    setzi $m1, 2
; CHECK_FP-NEXT:    setzi $m2, 3
; CHECK_FP-NEXT:    setzi $m3, 4
; CHECK_FP-NEXT:    call $m10, callee_stack_mrf
; CHECK_FP-NEXT:    ld32 $m10, $m9, $m15, 3 # 4-byte Folded Reload
; CHECK_FP-NEXT:    add $m11, $m9, 16
; CHECK_FP-NEXT:    ld32 $m9, $m9, $m15, 2 # 4-byte Folded Reload
; CHECK_FP-NEXT:    .cfi_def_cfa_register $m11
; CHECK_FP-NEXT:    br $m10
  call void @callee_stack_mrf(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)
  ret void
}

; Test basic calling with six arguments passed in [$a0, $a5] and two on the stack.
; The stack frame accomodates the spilt link register and two arguments.
declare void @callee_stack_arf(float %a1, float %a2, float %a3, float %a4,
                               float %a5, float %a6, float %a7, float %a8)
define void @caller_stack_arf(float %s0, float %s1) {
; CHECK_SP-LABEL: caller_stack_arf:
; CHECK_SP:       # %bb.0:
; CHECK_SP-NEXT:    add $m11, $m11, -16
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 16
; CHECK_SP-NEXT:    .cfi_offset $m10, -4
; CHECK_SP-NEXT:    st32 $m10, $m11, $m15, 3 # 4-byte Folded Spill
; CHECK_SP-NEXT:    st32 $a1, $m11, $m15, 1
; CHECK_SP-NEXT:    st32 $a0, $m11, $m15, 0
; CHECK_SP-NEXT:    setzi $a0, 1
; CHECK_SP-NEXT:    setzi $a1, 2
; CHECK_SP-NEXT:    setzi $a2, 3
; CHECK_SP-NEXT:    setzi $a3, 4
; CHECK_SP-NEXT:    setzi $a4, 5
; CHECK_SP-NEXT:    setzi $a5, 6
; CHECK_SP-NEXT:    call $m10, callee_stack_arf
; CHECK_SP-NEXT:    ld32 $m10, $m11, $m15, 3 # 4-byte Folded Reload
; CHECK_SP-NEXT:    add $m11, $m11, 16
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 0
; CHECK_SP-NEXT:    br $m10
;
; CHECK_FP-LABEL: caller_stack_arf:
; CHECK_FP:       # %bb.0:
; CHECK_FP-NEXT:    add $m11, $m11, -16
; CHECK_FP-NEXT:    st32 $m9, $m11, $m15, 2 # 4-byte Folded Spill
; CHECK_FP-NEXT:    mov $m9, $m11
; CHECK_FP-NEXT:    .cfi_def_cfa $m9, 16
; CHECK_FP-NEXT:    .cfi_offset $m9, -8
; CHECK_FP-NEXT:    .cfi_offset $m10, -4
; CHECK_FP-NEXT:    st32 $m10, $m9, $m15, 3 # 4-byte Folded Spill
; CHECK_FP-NEXT:    st32 $a1, $m11, $m15, 1
; CHECK_FP-NEXT:    st32 $a0, $m11, $m15, 0
; CHECK_FP-NEXT:    setzi $a0, 1
; CHECK_FP-NEXT:    setzi $a1, 2
; CHECK_FP-NEXT:    setzi $a2, 3
; CHECK_FP-NEXT:    setzi $a3, 4
; CHECK_FP-NEXT:    setzi $a4, 5
; CHECK_FP-NEXT:    setzi $a5, 6
; CHECK_FP-NEXT:    call $m10, callee_stack_arf
; CHECK_FP-NEXT:    ld32 $m10, $m9, $m15, 3 # 4-byte Folded Reload
; CHECK_FP-NEXT:    add $m11, $m9, 16
; CHECK_FP-NEXT:    ld32 $m9, $m9, $m15, 2 # 4-byte Folded Reload
; CHECK_FP-NEXT:    .cfi_def_cfa_register $m11
; CHECK_FP-NEXT:    br $m10
  %x1 = bitcast i32 1 to float
  %x2 = bitcast i32 2 to float
  %x3 = bitcast i32 3 to float
  %x4 = bitcast i32 4 to float
  %x5 = bitcast i32 5 to float
  %x6 = bitcast i32 6 to float
  call void @callee_stack_arf(float %x1, float %x2, float %x3, float %x4, float %x5, float %x6, float %s0, float %s1)
  ret void
}

; Test calling with mixed use of float/int MRF and ARF registers.
declare void @callee_mixed(i32 %a1, float %a2, i32 %a3, float %a4,
                           i32 %a5, float %a6, i32 %a7, float %a8,
                           i32 %a9, float %a10, float %a11, float %a12)

define void @caller_mixed() {
; IPU1_2_sp-LABEL: caller_mixed:
; IPU1_2_sp:       # %bb.0:
; IPU1_2_sp-NEXT:    add $m11, $m11, -16
; IPU1_2_sp-NEXT:    .cfi_def_cfa_offset 16
; IPU1_2_sp-NEXT:    .cfi_offset $m10, -4
; IPU1_2_sp-NEXT:    .cfi_offset $a6, -8
; IPU1_2_sp-NEXT:    st32 $m10, $m11, $m15, 3 # 4-byte Folded Spill
; IPU1_2_sp-NEXT:    st32 $a6, $m11, $m15, 2 # 4-byte Folded Spill
; IPU1_2_sp-NEXT:    mov $a0, $a15
; IPU1_2_sp-NEXT:    mov $a1, $a15
; IPU1_2_sp-NEXT:    mov $a2, $a15
; IPU1_2_sp-NEXT:    mov $a3, $a15
; IPU1_2_sp-NEXT:    mov $a4, $a15
; IPU1_2_sp-NEXT:    mov $a5, $a15
; IPU1_2_sp-NEXT:    st32 $a15, $m11, $m15, 1
; IPU1_2_sp-NEXT:    setzi $m0, 1
; IPU1_2_sp-NEXT:    setzi $m1, 3
; IPU1_2_sp-NEXT:    setzi $m2, 5
; IPU1_2_sp-NEXT:    setzi $m3, 7
; IPU1_2_sp-NEXT:    setzi $a6, 9
; IPU1_2_sp-NEXT:    st32 $a6, $m11, $m15, 0
; IPU1_2_sp-NEXT:    call $m10, callee_mixed
; IPU1_2_sp-NEXT:    ld32 $a6, $m11, $m15, 2 # 4-byte Folded Reload
; IPU1_2_sp-NEXT:    ld32 $m10, $m11, $m15, 3 # 4-byte Folded Reload
; IPU1_2_sp-NEXT:    add $m11, $m11, 16
; IPU1_2_sp-NEXT:    .cfi_def_cfa_offset 0
; IPU1_2_sp-NEXT:    br $m10
;
; IPU1_2_SP-LABEL: caller_mixed:
; IPU1_2_SP:       # %bb.0:
; IPU1_2_SP-NEXT:    add $m11, $m11, -16
; IPU1_2_SP-NEXT:    .cfi_def_cfa_offset 16
; IPU1_2_SP-NEXT:    .cfi_offset $m10, -4
; IPU1_2_SP-NEXT:    .cfi_offset $a6, -8
; IPU1_2_SP-NEXT:    st32 $m10, $m11, $m15, 3 # 4-byte Folded Spill
; IPU1_2_SP-NEXT:    st32 $a6, $m11, $m15, 2 # 4-byte Folded Spill
; IPU1_2_SP-NEXT:    mov $a0, $a15
; IPU1_2_SP-NEXT:    mov $a1, $a15
; IPU1_2_SP-NEXT:    mov $a2, $a15
; IPU1_2_SP-NEXT:    mov $a3, $a15
; IPU1_2_SP-NEXT:    mov $a4, $a15
; IPU1_2_SP-NEXT:    mov $a5, $a15
; IPU1_2_SP-NEXT:    st32 $a15, $m11, $m15, 1
; IPU1_2_SP-NEXT:    setzi $m0, 1
; IPU1_2_SP-NEXT:    setzi $m1, 3
; IPU1_2_SP-NEXT:    setzi $m2, 5
; IPU1_2_SP-NEXT:    setzi $m3, 7
; IPU1_2_SP-NEXT:    setzi $a6, 9
; IPU1_2_SP-NEXT:    st32 $a6, $m11, $m15, 0
; IPU1_2_SP-NEXT:    call $m10, callee_mixed
; IPU1_2_SP-NEXT:    ld32 $a6, $m11, $m15, 2 # 4-byte Folded Reload
; IPU1_2_SP-NEXT:    ld32 $m10, $m11, $m15, 3 # 4-byte Folded Reload
; IPU1_2_SP-NEXT:    add $m11, $m11, 16
; IPU1_2_SP-NEXT:    .cfi_def_cfa_offset 0
; IPU1_2_SP-NEXT:    br $m10
;
; IPU1_2_FP-LABEL: caller_mixed:
; IPU1_2_FP:       # %bb.0:
; IPU1_2_FP-NEXT:    add $m11, $m11, -24
; IPU1_2_FP-NEXT:    st32 $m9, $m11, $m15, 3 # 4-byte Folded Spill
; IPU1_2_FP-NEXT:    mov $m9, $m11
; IPU1_2_FP-NEXT:    .cfi_def_cfa $m9, 24
; IPU1_2_FP-NEXT:    .cfi_offset $m9, -12
; IPU1_2_FP-NEXT:    .cfi_offset $m10, -4
; IPU1_2_FP-NEXT:    .cfi_offset $a6, -8
; IPU1_2_FP-NEXT:    st32 $m10, $m9, $m15, 5 # 4-byte Folded Spill
; IPU1_2_FP-NEXT:    st32 $a6, $m9, $m15, 4 # 4-byte Folded Spill
; IPU1_2_FP-NEXT:    mov $a0, $a15
; IPU1_2_FP-NEXT:    mov $a1, $a15
; IPU1_2_FP-NEXT:    mov $a2, $a15
; IPU1_2_FP-NEXT:    mov $a3, $a15
; IPU1_2_FP-NEXT:    mov $a4, $a15
; IPU1_2_FP-NEXT:    mov $a5, $a15
; IPU1_2_FP-NEXT:    st32 $a15, $m11, $m15, 1
; IPU1_2_FP-NEXT:    setzi $m0, 1
; IPU1_2_FP-NEXT:    setzi $m1, 3
; IPU1_2_FP-NEXT:    setzi $m2, 5
; IPU1_2_FP-NEXT:    setzi $m3, 7
; IPU1_2_FP-NEXT:    setzi $a6, 9
; IPU1_2_FP-NEXT:    st32 $a6, $m11, $m15, 0
; IPU1_2_FP-NEXT:    call $m10, callee_mixed
; IPU1_2_FP-NEXT:    ld32 $a6, $m9, $m15, 4 # 4-byte Folded Reload
; IPU1_2_FP-NEXT:    ld32 $m10, $m9, $m15, 5 # 4-byte Folded Reload
; IPU1_2_FP-NEXT:    add $m11, $m9, 24
; IPU1_2_FP-NEXT:    ld32 $m9, $m9, $m15, 3 # 4-byte Folded Reload
; IPU1_2_FP-NEXT:    .cfi_def_cfa_register $m11
; IPU1_2_FP-NEXT:    br $m10
  call void @callee_mixed(i32 1, float 0.0, i32 3, float 0.0,
                          i32 5, float 0.0, i32 7, float 0.0,
                          i32 9, float 0.0, float 0.0, float 0.0)
  ret void
}

; Test the i32 return value is passed in $m0.
declare i32 @callee_ret_i32()
define void @caller_ret_i32() {
; CHECK_SP-LABEL: caller_ret_i32:
; CHECK_SP:       # %bb.0:
; CHECK_SP-NEXT:    add $m11, $m11, -8
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 8
; CHECK_SP-NEXT:    .cfi_offset $m10, -4
; CHECK_SP-NEXT:    st32 $m10, $m11, $m15, 1 # 4-byte Folded Spill
; CHECK_SP-NEXT:    call $m10, callee_ret_i32
; CHECK_SP-NEXT:    #APP
; CHECK_SP-NEXT:    exitneg $m0
; CHECK_SP-NEXT:    #NO_APP
; CHECK_SP-NEXT:    ld32 $m10, $m11, $m15, 1 # 4-byte Folded Reload
; CHECK_SP-NEXT:    add $m11, $m11, 8
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 0
; CHECK_SP-NEXT:    br $m10
;
; CHECK_FP-LABEL: caller_ret_i32:
; CHECK_FP:       # %bb.0:
; CHECK_FP-NEXT:    add $m11, $m11, -8
; CHECK_FP-NEXT:    st32 $m9, $m11, $m15, 0 # 4-byte Folded Spill
; CHECK_FP-NEXT:    mov $m9, $m11
; CHECK_FP-NEXT:    .cfi_def_cfa $m9, 8
; CHECK_FP-NEXT:    .cfi_offset $m9, -8
; CHECK_FP-NEXT:    .cfi_offset $m10, -4
; CHECK_FP-NEXT:    st32 $m10, $m9, $m15, 1 # 4-byte Folded Spill
; CHECK_FP-NEXT:    call $m10, callee_ret_i32
; CHECK_FP-NEXT:    #APP
; CHECK_FP-NEXT:    exitneg $m0
; CHECK_FP-NEXT:    #NO_APP
; CHECK_FP-NEXT:    ld32 $m10, $m9, $m15, 1 # 4-byte Folded Reload
; CHECK_FP-NEXT:    add $m11, $m9, 8
; CHECK_FP-NEXT:    ld32 $m9, $m9, $m15, 0 # 4-byte Folded Reload
; CHECK_FP-NEXT:    .cfi_def_cfa_register $m11
; CHECK_FP-NEXT:    br $m10
  %1 = call i32 @callee_ret_i32()
  call void asm sideeffect "exitneg $0", "r"(i32 %1)
  ret void
}

; Test the float return value is passed in $a0.
declare float @callee_ret_float()
define void @caller_ret_float() {
; CHECK_SP-LABEL: caller_ret_float:
; CHECK_SP:       # %bb.0:
; CHECK_SP-NEXT:    add $m11, $m11, -8
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 8
; CHECK_SP-NEXT:    .cfi_offset $m10, -4
; CHECK_SP-NEXT:    st32 $m10, $m11, $m15, 1 # 4-byte Folded Spill
; CHECK_SP-NEXT:    call $m10, callee_ret_float
; CHECK_SP-NEXT:    #APP
; CHECK_SP-NEXT:    get $a0, 0
; CHECK_SP-NEXT:    #NO_APP
; CHECK_SP-NEXT:    ld32 $m10, $m11, $m15, 1 # 4-byte Folded Reload
; CHECK_SP-NEXT:    add $m11, $m11, 8
; CHECK_SP-NEXT:    .cfi_def_cfa_offset 0
; CHECK_SP-NEXT:    br $m10
;
; CHECK_FP-LABEL: caller_ret_float:
; CHECK_FP:       # %bb.0:
; CHECK_FP-NEXT:    add $m11, $m11, -8
; CHECK_FP-NEXT:    st32 $m9, $m11, $m15, 0 # 4-byte Folded Spill
; CHECK_FP-NEXT:    mov $m9, $m11
; CHECK_FP-NEXT:    .cfi_def_cfa $m9, 8
; CHECK_FP-NEXT:    .cfi_offset $m9, -8
; CHECK_FP-NEXT:    .cfi_offset $m10, -4
; CHECK_FP-NEXT:    st32 $m10, $m9, $m15, 1 # 4-byte Folded Spill
; CHECK_FP-NEXT:    call $m10, callee_ret_float
; CHECK_FP-NEXT:    #APP
; CHECK_FP-NEXT:    get $a0, 0
; CHECK_FP-NEXT:    #NO_APP
; CHECK_FP-NEXT:    ld32 $m10, $m9, $m15, 1 # 4-byte Folded Reload
; CHECK_FP-NEXT:    add $m11, $m9, 8
; CHECK_FP-NEXT:    ld32 $m9, $m9, $m15, 0 # 4-byte Folded Reload
; CHECK_FP-NEXT:    .cfi_def_cfa_register $m11
; CHECK_FP-NEXT:    br $m10
  %1 = call float @callee_ret_float()
  call void asm sideeffect "uget $0, 0", "r"(float %1)
  ret void
}
