; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=armv8m.main-none-eabi   < %s -frame-pointer=none -mattr=+fp-armv8d16 | FileCheck %s --check-prefix=LE
; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 | FileCheck %s --check-prefix=BE
; RUN: llc -mtriple=armv8m.main-none-eabi   < %s -frame-pointer=none -mattr=+fp-armv8d16,+bf16 | FileCheck %s --check-prefix=LE-BF16
; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+bf16 | FileCheck %s --check-prefix=BE-BF16

;; Global ISel successfully generates code for some functions for little-endian
;; without +bf16, and falls back to SelectionDAG in all others.
; RUN: llc -mtriple=armv8m.main-none-eabi   < %s -frame-pointer=none -mattr=+fp-armv8d16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=LE-GISEL
; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=BE
; RUN: llc -mtriple=armv8m.main-none-eabi   < %s -frame-pointer=none -mattr=+fp-armv8d16,+bf16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=LE-BF16
; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+bf16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=BE-BF16

define arm_aapcscc bfloat @callee_soft_bfloat_in_reg(bfloat %f) {
; LE-LABEL: callee_soft_bfloat_in_reg:
; LE:       @ %bb.0: @ %entry
; LE-NEXT:    bx lr
;
; BE-LABEL: callee_soft_bfloat_in_reg:
; BE:       @ %bb.0: @ %entry
; BE-NEXT:    bx lr
;
; LE-BF16-LABEL: callee_soft_bfloat_in_reg:
; LE-BF16:       @ %bb.0: @ %entry
; LE-BF16-NEXT:    .pad #4
; LE-BF16-NEXT:    sub sp, #4
; LE-BF16-NEXT:    strh.w r0, [sp, #2]
; LE-BF16-NEXT:    ldrh.w r0, [sp, #2]
; LE-BF16-NEXT:    add sp, #4
; LE-BF16-NEXT:    bx lr
;
; BE-BF16-LABEL: callee_soft_bfloat_in_reg:
; BE-BF16:       @ %bb.0: @ %entry
; BE-BF16-NEXT:    .pad #4
; BE-BF16-NEXT:    sub sp, #4
; BE-BF16-NEXT:    strh.w r0, [sp, #2]
; BE-BF16-NEXT:    ldrh.w r0, [sp, #2]
; BE-BF16-NEXT:    add sp, #4
; BE-BF16-NEXT:    bx lr
;
; LE-GISEL-LABEL: callee_soft_bfloat_in_reg:
; LE-GISEL:       @ %bb.0: @ %entry
; LE-GISEL-NEXT:    bx lr
entry:
  ret bfloat %f
}

define void @caller_soft_bfloat_in_reg() {
; LE-LABEL: caller_soft_bfloat_in_reg:
; LE:       @ %bb.0: @ %entry
; LE-NEXT:    .save {r7, lr}
; LE-NEXT:    push {r7, lr}
; LE-NEXT:    mov.w r0, #16256
; LE-NEXT:    bl callee_soft_bfloat_in_reg
; LE-NEXT:    pop {r7, pc}
;
; BE-LABEL: caller_soft_bfloat_in_reg:
; BE:       @ %bb.0: @ %entry
; BE-NEXT:    .save {r7, lr}
; BE-NEXT:    push {r7, lr}
; BE-NEXT:    mov.w r0, #16256
; BE-NEXT:    bl callee_soft_bfloat_in_reg
; BE-NEXT:    pop {r7, pc}
;
; LE-BF16-LABEL: caller_soft_bfloat_in_reg:
; LE-BF16:       @ %bb.0: @ %entry
; LE-BF16-NEXT:    .save {r7, lr}
; LE-BF16-NEXT:    push {r7, lr}
; LE-BF16-NEXT:    mov.w r0, #16256
; LE-BF16-NEXT:    bl callee_soft_bfloat_in_reg
; LE-BF16-NEXT:    pop {r7, pc}
;
; BE-BF16-LABEL: caller_soft_bfloat_in_reg:
; BE-BF16:       @ %bb.0: @ %entry
; BE-BF16-NEXT:    .save {r7, lr}
; BE-BF16-NEXT:    push {r7, lr}
; BE-BF16-NEXT:    mov.w r0, #16256
; BE-BF16-NEXT:    bl callee_soft_bfloat_in_reg
; BE-BF16-NEXT:    pop {r7, pc}
;
; LE-GISEL-LABEL: caller_soft_bfloat_in_reg:
; LE-GISEL:       @ %bb.0: @ %entry
; LE-GISEL-NEXT:    .save {r7, lr}
; LE-GISEL-NEXT:    push {r7, lr}
; LE-GISEL-NEXT:    mov.w r0, #16256
; LE-GISEL-NEXT:    bl callee_soft_bfloat_in_reg
; LE-GISEL-NEXT:    pop {r7, pc}
entry:
  %ret = call arm_aapcscc bfloat @callee_soft_bfloat_in_reg(bfloat 1.0)
  ret void
}

define arm_aapcscc bfloat @callee_soft_bfloat_on_stack(float %r0, float %r1, float %r2, float %r3, bfloat %f) {
; LE-LABEL: callee_soft_bfloat_on_stack:
; LE:       @ %bb.0: @ %entry
; LE-NEXT:    ldr r0, [sp]
; LE-NEXT:    bx lr
;
; BE-LABEL: callee_soft_bfloat_on_stack:
; BE:       @ %bb.0: @ %entry
; BE-NEXT:    ldr r0, [sp]
; BE-NEXT:    bx lr
;
; LE-BF16-LABEL: callee_soft_bfloat_on_stack:
; LE-BF16:       @ %bb.0: @ %entry
; LE-BF16-NEXT:    ldrh.w r0, [sp]
; LE-BF16-NEXT:    bx lr
;
; BE-BF16-LABEL: callee_soft_bfloat_on_stack:
; BE-BF16:       @ %bb.0: @ %entry
; BE-BF16-NEXT:    ldrh.w r0, [sp, #2]
; BE-BF16-NEXT:    bx lr
;
; LE-GISEL-LABEL: callee_soft_bfloat_on_stack:
; LE-GISEL:       @ %bb.0: @ %entry
; LE-GISEL-NEXT:    mov r0, sp
; LE-GISEL-NEXT:    ldr r0, [r0]
; LE-GISEL-NEXT:    bx lr
entry:
  ret bfloat %f
}

define void @caller_soft_bfloat_on_stack() {
; LE-LABEL: caller_soft_bfloat_on_stack:
; LE:       @ %bb.0: @ %entry
; LE-NEXT:    .save {r7, lr}
; LE-NEXT:    push {r7, lr}
; LE-NEXT:    .pad #8
; LE-NEXT:    sub sp, #8
; LE-NEXT:    mov.w r0, #16256
; LE-NEXT:    str r0, [sp]
; LE-NEXT:    bl callee_soft_bfloat_on_stack
; LE-NEXT:    add sp, #8
; LE-NEXT:    pop {r7, pc}
;
; BE-LABEL: caller_soft_bfloat_on_stack:
; BE:       @ %bb.0: @ %entry
; BE-NEXT:    .save {r7, lr}
; BE-NEXT:    push {r7, lr}
; BE-NEXT:    .pad #8
; BE-NEXT:    sub sp, #8
; BE-NEXT:    mov.w r0, #16256
; BE-NEXT:    str r0, [sp]
; BE-NEXT:    bl callee_soft_bfloat_on_stack
; BE-NEXT:    add sp, #8
; BE-NEXT:    pop {r7, pc}
;
; LE-BF16-LABEL: caller_soft_bfloat_on_stack:
; LE-BF16:       @ %bb.0: @ %entry
; LE-BF16-NEXT:    .save {r7, lr}
; LE-BF16-NEXT:    push {r7, lr}
; LE-BF16-NEXT:    .pad #8
; LE-BF16-NEXT:    sub sp, #8
; LE-BF16-NEXT:    mov.w r0, #16256
; LE-BF16-NEXT:    str r0, [sp]
; LE-BF16-NEXT:    bl callee_soft_bfloat_on_stack
; LE-BF16-NEXT:    add sp, #8
; LE-BF16-NEXT:    pop {r7, pc}
;
; BE-BF16-LABEL: caller_soft_bfloat_on_stack:
; BE-BF16:       @ %bb.0: @ %entry
; BE-BF16-NEXT:    .save {r7, lr}
; BE-BF16-NEXT:    push {r7, lr}
; BE-BF16-NEXT:    .pad #8
; BE-BF16-NEXT:    sub sp, #8
; BE-BF16-NEXT:    mov.w r0, #16256
; BE-BF16-NEXT:    str r0, [sp]
; BE-BF16-NEXT:    bl callee_soft_bfloat_on_stack
; BE-BF16-NEXT:    add sp, #8
; BE-BF16-NEXT:    pop {r7, pc}
;
; LE-GISEL-LABEL: caller_soft_bfloat_on_stack:
; LE-GISEL:       @ %bb.0: @ %entry
; LE-GISEL-NEXT:    .save {r7, lr}
; LE-GISEL-NEXT:    push {r7, lr}
; LE-GISEL-NEXT:    .pad #8
; LE-GISEL-NEXT:    sub sp, #8
; LE-GISEL-NEXT:    mov.w r0, #16256
; LE-GISEL-NEXT:    str r0, [sp]
; LE-GISEL-NEXT:    bl callee_soft_bfloat_on_stack
; LE-GISEL-NEXT:    add sp, #8
; LE-GISEL-NEXT:    pop {r7, pc}
entry:
  %ret = call arm_aapcscc bfloat @callee_soft_bfloat_on_stack(float poison, float poison, float poison, float poison, bfloat 1.0)
  ret void
}

define arm_aapcs_vfpcc bfloat @callee_hard_bfloat_in_reg(bfloat %f) {
; LE-LABEL: callee_hard_bfloat_in_reg:
; LE:       @ %bb.0: @ %entry
; LE-NEXT:    bx lr
;
; BE-LABEL: callee_hard_bfloat_in_reg:
; BE:       @ %bb.0: @ %entry
; BE-NEXT:    bx lr
;
; LE-BF16-LABEL: callee_hard_bfloat_in_reg:
; LE-BF16:       @ %bb.0: @ %entry
; LE-BF16-NEXT:    .pad #4
; LE-BF16-NEXT:    sub sp, #4
; LE-BF16-NEXT:    vmov r0, s0
; LE-BF16-NEXT:    strh.w r0, [sp, #2]
; LE-BF16-NEXT:    ldrh.w r0, [sp, #2]
; LE-BF16-NEXT:    vmov s0, r0
; LE-BF16-NEXT:    add sp, #4
; LE-BF16-NEXT:    bx lr
;
; BE-BF16-LABEL: callee_hard_bfloat_in_reg:
; BE-BF16:       @ %bb.0: @ %entry
; BE-BF16-NEXT:    .pad #4
; BE-BF16-NEXT:    sub sp, #4
; BE-BF16-NEXT:    vmov r0, s0
; BE-BF16-NEXT:    strh.w r0, [sp, #2]
; BE-BF16-NEXT:    ldrh.w r0, [sp, #2]
; BE-BF16-NEXT:    vmov s0, r0
; BE-BF16-NEXT:    add sp, #4
; BE-BF16-NEXT:    bx lr
;
; LE-GISEL-LABEL: callee_hard_bfloat_in_reg:
; LE-GISEL:       @ %bb.0: @ %entry
; LE-GISEL-NEXT:    bx lr
entry:
  ret bfloat %f
}

define void @caller_hard_bfloat_in_reg() {
; LE-LABEL: caller_hard_bfloat_in_reg:
; LE:       @ %bb.0: @ %entry
; LE-NEXT:    .save {r7, lr}
; LE-NEXT:    push {r7, lr}
; LE-NEXT:    vldr s0, .LCPI5_0
; LE-NEXT:    bl callee_hard_bfloat_in_reg
; LE-NEXT:    pop {r7, pc}
; LE-NEXT:    .p2align 2
; LE-NEXT:  @ %bb.1:
; LE-NEXT:  .LCPI5_0:
; LE-NEXT:    .long 0x00003f80 @ float 2.27795078E-41
;
; BE-LABEL: caller_hard_bfloat_in_reg:
; BE:       @ %bb.0: @ %entry
; BE-NEXT:    .save {r7, lr}
; BE-NEXT:    push {r7, lr}
; BE-NEXT:    vldr s0, .LCPI5_0
; BE-NEXT:    bl callee_hard_bfloat_in_reg
; BE-NEXT:    pop {r7, pc}
; BE-NEXT:    .p2align 2
; BE-NEXT:  @ %bb.1:
; BE-NEXT:  .LCPI5_0:
; BE-NEXT:    .long 0x00003f80 @ float 2.27795078E-41
;
; LE-BF16-LABEL: caller_hard_bfloat_in_reg:
; LE-BF16:       @ %bb.0: @ %entry
; LE-BF16-NEXT:    .save {r7, lr}
; LE-BF16-NEXT:    push {r7, lr}
; LE-BF16-NEXT:    vldr s0, .LCPI5_0
; LE-BF16-NEXT:    bl callee_hard_bfloat_in_reg
; LE-BF16-NEXT:    pop {r7, pc}
; LE-BF16-NEXT:    .p2align 2
; LE-BF16-NEXT:  @ %bb.1:
; LE-BF16-NEXT:  .LCPI5_0:
; LE-BF16-NEXT:    .long 0x00003f80 @ float 2.27795078E-41
;
; BE-BF16-LABEL: caller_hard_bfloat_in_reg:
; BE-BF16:       @ %bb.0: @ %entry
; BE-BF16-NEXT:    .save {r7, lr}
; BE-BF16-NEXT:    push {r7, lr}
; BE-BF16-NEXT:    vldr s0, .LCPI5_0
; BE-BF16-NEXT:    bl callee_hard_bfloat_in_reg
; BE-BF16-NEXT:    pop {r7, pc}
; BE-BF16-NEXT:    .p2align 2
; BE-BF16-NEXT:  @ %bb.1:
; BE-BF16-NEXT:  .LCPI5_0:
; BE-BF16-NEXT:    .long 0x00003f80 @ float 2.27795078E-41
;
; LE-GISEL-LABEL: caller_hard_bfloat_in_reg:
; LE-GISEL:       @ %bb.0: @ %entry
; LE-GISEL-NEXT:    .save {r7, lr}
; LE-GISEL-NEXT:    push {r7, lr}
; LE-GISEL-NEXT:    vldr s0, .LCPI5_0
; LE-GISEL-NEXT:    bl callee_hard_bfloat_in_reg
; LE-GISEL-NEXT:    pop {r7, pc}
; LE-GISEL-NEXT:    .p2align 2
; LE-GISEL-NEXT:  @ %bb.1:
; LE-GISEL-NEXT:  .LCPI5_0:
; LE-GISEL-NEXT:    .long 0x00003f80 @ float 2.27795078E-41
entry:
  %ret = call arm_aapcs_vfpcc bfloat @callee_hard_bfloat_in_reg(bfloat 1.0)
  ret void
}

define arm_aapcs_vfpcc bfloat @callee_hard_bfloat_on_stack(float %s0, float %s1, float %s2, float %s3, float %s4, float %s5, float %s6, float %s7,float %s8, float %s9, float %s10, float %s11, float %s12, float %s13, float %s14, float %s15, bfloat %f) {
; LE-LABEL: callee_hard_bfloat_on_stack:
; LE:       @ %bb.0: @ %entry
; LE-NEXT:    vldr s0, [sp]
; LE-NEXT:    bx lr
;
; BE-LABEL: callee_hard_bfloat_on_stack:
; BE:       @ %bb.0: @ %entry
; BE-NEXT:    vldr s0, [sp]
; BE-NEXT:    bx lr
;
; LE-BF16-LABEL: callee_hard_bfloat_on_stack:
; LE-BF16:       @ %bb.0: @ %entry
; LE-BF16-NEXT:    ldrh.w r0, [sp]
; LE-BF16-NEXT:    vmov s0, r0
; LE-BF16-NEXT:    bx lr
;
; BE-BF16-LABEL: callee_hard_bfloat_on_stack:
; BE-BF16:       @ %bb.0: @ %entry
; BE-BF16-NEXT:    ldrh.w r0, [sp, #2]
; BE-BF16-NEXT:    vmov s0, r0
; BE-BF16-NEXT:    bx lr
;
; LE-GISEL-LABEL: callee_hard_bfloat_on_stack:
; LE-GISEL:       @ %bb.0: @ %entry
; LE-GISEL-NEXT:    mov r0, sp
; LE-GISEL-NEXT:    ldr r0, [r0]
; LE-GISEL-NEXT:    vmov s0, r0
; LE-GISEL-NEXT:    bx lr
entry:
  ret bfloat %f
}


define void @caller_hard_bfloat_on_stack() {
; LE-LABEL: caller_hard_bfloat_on_stack:
; LE:       @ %bb.0: @ %entry
; LE-NEXT:    .save {r7, lr}
; LE-NEXT:    push {r7, lr}
; LE-NEXT:    .pad #8
; LE-NEXT:    sub sp, #8
; LE-NEXT:    mov.w r0, #16256
; LE-NEXT:    str r0, [sp]
; LE-NEXT:    bl callee_hard_bfloat_on_stack
; LE-NEXT:    add sp, #8
; LE-NEXT:    pop {r7, pc}
;
; BE-LABEL: caller_hard_bfloat_on_stack:
; BE:       @ %bb.0: @ %entry
; BE-NEXT:    .save {r7, lr}
; BE-NEXT:    push {r7, lr}
; BE-NEXT:    .pad #8
; BE-NEXT:    sub sp, #8
; BE-NEXT:    mov.w r0, #16256
; BE-NEXT:    str r0, [sp]
; BE-NEXT:    bl callee_hard_bfloat_on_stack
; BE-NEXT:    add sp, #8
; BE-NEXT:    pop {r7, pc}
;
; LE-BF16-LABEL: caller_hard_bfloat_on_stack:
; LE-BF16:       @ %bb.0: @ %entry
; LE-BF16-NEXT:    .save {r7, lr}
; LE-BF16-NEXT:    push {r7, lr}
; LE-BF16-NEXT:    .pad #8
; LE-BF16-NEXT:    sub sp, #8
; LE-BF16-NEXT:    mov.w r0, #16256
; LE-BF16-NEXT:    str r0, [sp]
; LE-BF16-NEXT:    bl callee_hard_bfloat_on_stack
; LE-BF16-NEXT:    add sp, #8
; LE-BF16-NEXT:    pop {r7, pc}
;
; BE-BF16-LABEL: caller_hard_bfloat_on_stack:
; BE-BF16:       @ %bb.0: @ %entry
; BE-BF16-NEXT:    .save {r7, lr}
; BE-BF16-NEXT:    push {r7, lr}
; BE-BF16-NEXT:    .pad #8
; BE-BF16-NEXT:    sub sp, #8
; BE-BF16-NEXT:    mov.w r0, #16256
; BE-BF16-NEXT:    str r0, [sp]
; BE-BF16-NEXT:    bl callee_hard_bfloat_on_stack
; BE-BF16-NEXT:    add sp, #8
; BE-BF16-NEXT:    pop {r7, pc}
;
; LE-GISEL-LABEL: caller_hard_bfloat_on_stack:
; LE-GISEL:       @ %bb.0: @ %entry
; LE-GISEL-NEXT:    .save {r7, lr}
; LE-GISEL-NEXT:    push {r7, lr}
; LE-GISEL-NEXT:    .pad #8
; LE-GISEL-NEXT:    sub sp, #8
; LE-GISEL-NEXT:    mov.w r0, #16256
; LE-GISEL-NEXT:    str r0, [sp]
; LE-GISEL-NEXT:    bl callee_hard_bfloat_on_stack
; LE-GISEL-NEXT:    add sp, #8
; LE-GISEL-NEXT:    pop {r7, pc}
entry:
  %ret = call arm_aapcs_vfpcc bfloat @callee_hard_bfloat_on_stack(float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, bfloat 1.0)
  ret void
}
