; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=arm-unknown-linux-gnueabihf -mattr=+vfp2 < %s | FileCheck -check-prefixes=AAPCS-HARD,GNU-AAPCS-HARD %s
; RUN: llc -mtriple=arm-unknown-linux-gnueabi -mattr=+vfp2 < %s | FileCheck -check-prefixes=AAPCS-SOFT,GNU-AAPCS-SOFT %s
; RUN: llc -mtriple=arm-unknown-linux-eabihf -mattr=+vfp2 < %s | FileCheck -check-prefixes=AAPCS-HARD,EABI-HARD %s
; RUN: llc -mtriple=arm-unknown-linux-eabi -mattr=+vfp2 < %s | FileCheck -check-prefixes=AAPCS-SOFT,EABI-SOFT %s
; RUN: llc -mtriple=armv7-unknown-linux -target-abi=apcs -float-abi=soft < %s | FileCheck -check-prefix=APCS %s
; RUN: llc -mtriple=armv7-unknown-linux -target-abi=apcs -float-abi=hard < %s | FileCheck -check-prefix=APCS %s
; RUN: llc -mtriple=armv7k-apple-watchos2.0 -mcpu=cortex-a7 < %s | FileCheck -check-prefix=WATCHABI-HARD %s
; RUN: llc -mtriple=armv7k-apple-watchos2.0 -mcpu=cortex-a7 -float-abi=soft < %s | FileCheck -check-prefix=WATCHABI-SOFT %s

define i1 @test(half %self) #0 {
; GNU-AAPCS-HARD-LABEL: test:
; GNU-AAPCS-HARD:       @ %bb.0:
; GNU-AAPCS-HARD-NEXT:    .save {r11, lr}
; GNU-AAPCS-HARD-NEXT:    push {r11, lr}
; GNU-AAPCS-HARD-NEXT:    vmov r0, s0
; GNU-AAPCS-HARD-NEXT:    bl __gnu_h2f_ieee
; GNU-AAPCS-HARD-NEXT:    vmov s0, r0
; GNU-AAPCS-HARD-NEXT:    mov r0, #0
; GNU-AAPCS-HARD-NEXT:    vcmp.f32 s0, s0
; GNU-AAPCS-HARD-NEXT:    vmrs APSR_nzcv, fpscr
; GNU-AAPCS-HARD-NEXT:    movvs r0, #1
; GNU-AAPCS-HARD-NEXT:    pop {r11, lr}
; GNU-AAPCS-HARD-NEXT:    mov pc, lr
;
; GNU-AAPCS-SOFT-LABEL: test:
; GNU-AAPCS-SOFT:       @ %bb.0:
; GNU-AAPCS-SOFT-NEXT:    .save {r11, lr}
; GNU-AAPCS-SOFT-NEXT:    push {r11, lr}
; GNU-AAPCS-SOFT-NEXT:    bl __gnu_h2f_ieee
; GNU-AAPCS-SOFT-NEXT:    vmov s0, r0
; GNU-AAPCS-SOFT-NEXT:    mov r0, #0
; GNU-AAPCS-SOFT-NEXT:    vcmp.f32 s0, s0
; GNU-AAPCS-SOFT-NEXT:    vmrs APSR_nzcv, fpscr
; GNU-AAPCS-SOFT-NEXT:    movvs r0, #1
; GNU-AAPCS-SOFT-NEXT:    pop {r11, lr}
; GNU-AAPCS-SOFT-NEXT:    mov pc, lr
;
; EABI-HARD-LABEL: test:
; EABI-HARD:       @ %bb.0:
; EABI-HARD-NEXT:    .save {r11, lr}
; EABI-HARD-NEXT:    push {r11, lr}
; EABI-HARD-NEXT:    vmov r0, s0
; EABI-HARD-NEXT:    bl __aeabi_h2f
; EABI-HARD-NEXT:    vmov s0, r0
; EABI-HARD-NEXT:    mov r0, #0
; EABI-HARD-NEXT:    vcmp.f32 s0, s0
; EABI-HARD-NEXT:    vmrs APSR_nzcv, fpscr
; EABI-HARD-NEXT:    movvs r0, #1
; EABI-HARD-NEXT:    pop {r11, lr}
; EABI-HARD-NEXT:    mov pc, lr
;
; EABI-SOFT-LABEL: test:
; EABI-SOFT:       @ %bb.0:
; EABI-SOFT-NEXT:    .save {r11, lr}
; EABI-SOFT-NEXT:    push {r11, lr}
; EABI-SOFT-NEXT:    bl __aeabi_h2f
; EABI-SOFT-NEXT:    vmov s0, r0
; EABI-SOFT-NEXT:    mov r0, #0
; EABI-SOFT-NEXT:    vcmp.f32 s0, s0
; EABI-SOFT-NEXT:    vmrs APSR_nzcv, fpscr
; EABI-SOFT-NEXT:    movvs r0, #1
; EABI-SOFT-NEXT:    pop {r11, lr}
; EABI-SOFT-NEXT:    mov pc, lr
;
; APCS-LABEL: test:
; APCS:       @ %bb.0:
; APCS-NEXT:    push {lr}
; APCS-NEXT:    bl __gnu_h2f_ieee
; APCS-NEXT:    vmov s0, r0
; APCS-NEXT:    mov r0, #0
; APCS-NEXT:    vcmp.f32 s0, s0
; APCS-NEXT:    vmrs APSR_nzcv, fpscr
; APCS-NEXT:    movwvs r0, #1
; APCS-NEXT:    pop {lr}
; APCS-NEXT:    bx lr
;
; WATCHABI-HARD-LABEL: test:
; WATCHABI-HARD:       @ %bb.0:
; WATCHABI-HARD-NEXT:    vcvtb.f32.f16 s0, s0
; WATCHABI-HARD-NEXT:    mov r0, #0
; WATCHABI-HARD-NEXT:    vcmp.f32 s0, s0
; WATCHABI-HARD-NEXT:    vmrs APSR_nzcv, fpscr
; WATCHABI-HARD-NEXT:    movwvs r0, #1
; WATCHABI-HARD-NEXT:    bx lr
;
; WATCHABI-SOFT-LABEL: test:
; WATCHABI-SOFT:       @ %bb.0:
; WATCHABI-SOFT-NEXT:    vmov s0, r0
; WATCHABI-SOFT-NEXT:    mov r1, #0
; WATCHABI-SOFT-NEXT:    vcvtb.f32.f16 s0, s0
; WATCHABI-SOFT-NEXT:    vcmp.f32 s0, s0
; WATCHABI-SOFT-NEXT:    vmrs APSR_nzcv, fpscr
; WATCHABI-SOFT-NEXT:    movwvs r1, #1
; WATCHABI-SOFT-NEXT:    mov r0, r1
; WATCHABI-SOFT-NEXT:    bx lr
  %_0 = fcmp une half %self, %self
  ret i1 %_0
}

define float @f16_to_f32(ptr %p) #0 {
; GNU-AAPCS-HARD-LABEL: f16_to_f32:
; GNU-AAPCS-HARD:       @ %bb.0:
; GNU-AAPCS-HARD-NEXT:    .save {r11, lr}
; GNU-AAPCS-HARD-NEXT:    push {r11, lr}
; GNU-AAPCS-HARD-NEXT:    ldrh r0, [r0]
; GNU-AAPCS-HARD-NEXT:    bl __gnu_h2f_ieee
; GNU-AAPCS-HARD-NEXT:    vmov s0, r0
; GNU-AAPCS-HARD-NEXT:    pop {r11, lr}
; GNU-AAPCS-HARD-NEXT:    mov pc, lr
;
; GNU-AAPCS-SOFT-LABEL: f16_to_f32:
; GNU-AAPCS-SOFT:       @ %bb.0:
; GNU-AAPCS-SOFT-NEXT:    ldrh r0, [r0]
; GNU-AAPCS-SOFT-NEXT:    b __gnu_h2f_ieee
;
; EABI-HARD-LABEL: f16_to_f32:
; EABI-HARD:       @ %bb.0:
; EABI-HARD-NEXT:    .save {r11, lr}
; EABI-HARD-NEXT:    push {r11, lr}
; EABI-HARD-NEXT:    ldrh r0, [r0]
; EABI-HARD-NEXT:    bl __aeabi_h2f
; EABI-HARD-NEXT:    vmov s0, r0
; EABI-HARD-NEXT:    pop {r11, lr}
; EABI-HARD-NEXT:    mov pc, lr
;
; EABI-SOFT-LABEL: f16_to_f32:
; EABI-SOFT:       @ %bb.0:
; EABI-SOFT-NEXT:    ldrh r0, [r0]
; EABI-SOFT-NEXT:    b __aeabi_h2f
;
; APCS-LABEL: f16_to_f32:
; APCS:       @ %bb.0:
; APCS-NEXT:    ldrh r0, [r0]
; APCS-NEXT:    b __gnu_h2f_ieee
;
; WATCHABI-HARD-LABEL: f16_to_f32:
; WATCHABI-HARD:       @ %bb.0:
; WATCHABI-HARD-NEXT:    ldrh r0, [r0]
; WATCHABI-HARD-NEXT:    vmov s0, r0
; WATCHABI-HARD-NEXT:    vcvtb.f32.f16 s0, s0
; WATCHABI-HARD-NEXT:    bx lr
;
; WATCHABI-SOFT-LABEL: f16_to_f32:
; WATCHABI-SOFT:       @ %bb.0:
; WATCHABI-SOFT-NEXT:    ldrh r0, [r0]
; WATCHABI-SOFT-NEXT:    vmov s0, r0
; WATCHABI-SOFT-NEXT:    vcvtb.f32.f16 s0, s0
; WATCHABI-SOFT-NEXT:    vmov r0, s0
; WATCHABI-SOFT-NEXT:    bx lr
  %load = load half, ptr %p
  %cvt = fpext half %load to float
  ret float %cvt
}

define void @f32_to_f16(ptr %p, float %arg) #0 {
; GNU-AAPCS-HARD-LABEL: f32_to_f16:
; GNU-AAPCS-HARD:       @ %bb.0:
; GNU-AAPCS-HARD-NEXT:    .save {r4, lr}
; GNU-AAPCS-HARD-NEXT:    push {r4, lr}
; GNU-AAPCS-HARD-NEXT:    mov r4, r0
; GNU-AAPCS-HARD-NEXT:    vmov r0, s0
; GNU-AAPCS-HARD-NEXT:    bl __gnu_f2h_ieee
; GNU-AAPCS-HARD-NEXT:    strh r0, [r4]
; GNU-AAPCS-HARD-NEXT:    pop {r4, lr}
; GNU-AAPCS-HARD-NEXT:    mov pc, lr
;
; GNU-AAPCS-SOFT-LABEL: f32_to_f16:
; GNU-AAPCS-SOFT:       @ %bb.0:
; GNU-AAPCS-SOFT-NEXT:    .save {r4, lr}
; GNU-AAPCS-SOFT-NEXT:    push {r4, lr}
; GNU-AAPCS-SOFT-NEXT:    mov r4, r0
; GNU-AAPCS-SOFT-NEXT:    mov r0, r1
; GNU-AAPCS-SOFT-NEXT:    bl __gnu_f2h_ieee
; GNU-AAPCS-SOFT-NEXT:    strh r0, [r4]
; GNU-AAPCS-SOFT-NEXT:    pop {r4, lr}
; GNU-AAPCS-SOFT-NEXT:    mov pc, lr
;
; EABI-HARD-LABEL: f32_to_f16:
; EABI-HARD:       @ %bb.0:
; EABI-HARD-NEXT:    .save {r4, lr}
; EABI-HARD-NEXT:    push {r4, lr}
; EABI-HARD-NEXT:    mov r4, r0
; EABI-HARD-NEXT:    vmov r0, s0
; EABI-HARD-NEXT:    bl __aeabi_f2h
; EABI-HARD-NEXT:    strh r0, [r4]
; EABI-HARD-NEXT:    pop {r4, lr}
; EABI-HARD-NEXT:    mov pc, lr
;
; EABI-SOFT-LABEL: f32_to_f16:
; EABI-SOFT:       @ %bb.0:
; EABI-SOFT-NEXT:    .save {r4, lr}
; EABI-SOFT-NEXT:    push {r4, lr}
; EABI-SOFT-NEXT:    mov r4, r0
; EABI-SOFT-NEXT:    mov r0, r1
; EABI-SOFT-NEXT:    bl __aeabi_f2h
; EABI-SOFT-NEXT:    strh r0, [r4]
; EABI-SOFT-NEXT:    pop {r4, lr}
; EABI-SOFT-NEXT:    mov pc, lr
;
; APCS-LABEL: f32_to_f16:
; APCS:       @ %bb.0:
; APCS-NEXT:    push {r4, lr}
; APCS-NEXT:    mov r4, r0
; APCS-NEXT:    mov r0, r1
; APCS-NEXT:    bl __gnu_f2h_ieee
; APCS-NEXT:    strh r0, [r4]
; APCS-NEXT:    pop {r4, pc}
;
; WATCHABI-HARD-LABEL: f32_to_f16:
; WATCHABI-HARD:       @ %bb.0:
; WATCHABI-HARD-NEXT:    vcvtb.f16.f32 s0, s0
; WATCHABI-HARD-NEXT:    vmov r1, s0
; WATCHABI-HARD-NEXT:    strh r1, [r0]
; WATCHABI-HARD-NEXT:    bx lr
;
; WATCHABI-SOFT-LABEL: f32_to_f16:
; WATCHABI-SOFT:       @ %bb.0:
; WATCHABI-SOFT-NEXT:    vmov s0, r1
; WATCHABI-SOFT-NEXT:    vcvtb.f16.f32 s0, s0
; WATCHABI-SOFT-NEXT:    vmov r1, s0
; WATCHABI-SOFT-NEXT:    strh r1, [r0]
; WATCHABI-SOFT-NEXT:    bx lr
  %cvt = fptrunc float %arg to half
  store half %cvt, ptr %p
  ret void
}

define double @f16_to_f64(ptr %p) #0 {
; GNU-AAPCS-HARD-LABEL: f16_to_f64:
; GNU-AAPCS-HARD:       @ %bb.0:
; GNU-AAPCS-HARD-NEXT:    .save {r11, lr}
; GNU-AAPCS-HARD-NEXT:    push {r11, lr}
; GNU-AAPCS-HARD-NEXT:    ldrh r0, [r0]
; GNU-AAPCS-HARD-NEXT:    bl __gnu_h2f_ieee
; GNU-AAPCS-HARD-NEXT:    vmov s0, r0
; GNU-AAPCS-HARD-NEXT:    vcvt.f64.f32 d0, s0
; GNU-AAPCS-HARD-NEXT:    pop {r11, lr}
; GNU-AAPCS-HARD-NEXT:    mov pc, lr
;
; GNU-AAPCS-SOFT-LABEL: f16_to_f64:
; GNU-AAPCS-SOFT:       @ %bb.0:
; GNU-AAPCS-SOFT-NEXT:    .save {r11, lr}
; GNU-AAPCS-SOFT-NEXT:    push {r11, lr}
; GNU-AAPCS-SOFT-NEXT:    ldrh r0, [r0]
; GNU-AAPCS-SOFT-NEXT:    bl __gnu_h2f_ieee
; GNU-AAPCS-SOFT-NEXT:    vmov s0, r0
; GNU-AAPCS-SOFT-NEXT:    vcvt.f64.f32 d0, s0
; GNU-AAPCS-SOFT-NEXT:    vmov r0, r1, d0
; GNU-AAPCS-SOFT-NEXT:    pop {r11, lr}
; GNU-AAPCS-SOFT-NEXT:    mov pc, lr
;
; EABI-HARD-LABEL: f16_to_f64:
; EABI-HARD:       @ %bb.0:
; EABI-HARD-NEXT:    .save {r11, lr}
; EABI-HARD-NEXT:    push {r11, lr}
; EABI-HARD-NEXT:    ldrh r0, [r0]
; EABI-HARD-NEXT:    bl __aeabi_h2f
; EABI-HARD-NEXT:    vmov s0, r0
; EABI-HARD-NEXT:    vcvt.f64.f32 d0, s0
; EABI-HARD-NEXT:    pop {r11, lr}
; EABI-HARD-NEXT:    mov pc, lr
;
; EABI-SOFT-LABEL: f16_to_f64:
; EABI-SOFT:       @ %bb.0:
; EABI-SOFT-NEXT:    .save {r11, lr}
; EABI-SOFT-NEXT:    push {r11, lr}
; EABI-SOFT-NEXT:    ldrh r0, [r0]
; EABI-SOFT-NEXT:    bl __aeabi_h2f
; EABI-SOFT-NEXT:    vmov s0, r0
; EABI-SOFT-NEXT:    vcvt.f64.f32 d0, s0
; EABI-SOFT-NEXT:    vmov r0, r1, d0
; EABI-SOFT-NEXT:    pop {r11, lr}
; EABI-SOFT-NEXT:    mov pc, lr
;
; APCS-LABEL: f16_to_f64:
; APCS:       @ %bb.0:
; APCS-NEXT:    push {lr}
; APCS-NEXT:    ldrh r0, [r0]
; APCS-NEXT:    bl __gnu_h2f_ieee
; APCS-NEXT:    vmov s0, r0
; APCS-NEXT:    vcvt.f64.f32 d16, s0
; APCS-NEXT:    vmov r0, r1, d16
; APCS-NEXT:    pop {lr}
; APCS-NEXT:    bx lr
;
; WATCHABI-HARD-LABEL: f16_to_f64:
; WATCHABI-HARD:       @ %bb.0:
; WATCHABI-HARD-NEXT:    ldrh r0, [r0]
; WATCHABI-HARD-NEXT:    vmov s0, r0
; WATCHABI-HARD-NEXT:    vcvtb.f32.f16 s0, s0
; WATCHABI-HARD-NEXT:    vcvt.f64.f32 d0, s0
; WATCHABI-HARD-NEXT:    bx lr
;
; WATCHABI-SOFT-LABEL: f16_to_f64:
; WATCHABI-SOFT:       @ %bb.0:
; WATCHABI-SOFT-NEXT:    ldrh r0, [r0]
; WATCHABI-SOFT-NEXT:    vmov s0, r0
; WATCHABI-SOFT-NEXT:    vcvtb.f32.f16 s0, s0
; WATCHABI-SOFT-NEXT:    vcvt.f64.f32 d16, s0
; WATCHABI-SOFT-NEXT:    vmov r0, r1, d16
; WATCHABI-SOFT-NEXT:    bx lr
  %load = load half, ptr %p
  %cvt = fpext half %load to double
  ret double %cvt
}

define void @f64_to_f16(ptr %p, double %arg) #0 {
; AAPCS-HARD-LABEL: f64_to_f16:
; AAPCS-HARD:       @ %bb.0:
; AAPCS-HARD-NEXT:    .save {r4, lr}
; AAPCS-HARD-NEXT:    push {r4, lr}
; AAPCS-HARD-NEXT:    mov r4, r0
; AAPCS-HARD-NEXT:    vmov r0, r1, d0
; AAPCS-HARD-NEXT:    bl __aeabi_d2h
; AAPCS-HARD-NEXT:    strh r0, [r4]
; AAPCS-HARD-NEXT:    pop {r4, lr}
; AAPCS-HARD-NEXT:    mov pc, lr
;
; AAPCS-SOFT-LABEL: f64_to_f16:
; AAPCS-SOFT:       @ %bb.0:
; AAPCS-SOFT-NEXT:    .save {r4, lr}
; AAPCS-SOFT-NEXT:    push {r4, lr}
; AAPCS-SOFT-NEXT:    mov r4, r0
; AAPCS-SOFT-NEXT:    mov r1, r3
; AAPCS-SOFT-NEXT:    mov r0, r2
; AAPCS-SOFT-NEXT:    bl __aeabi_d2h
; AAPCS-SOFT-NEXT:    strh r0, [r4]
; AAPCS-SOFT-NEXT:    pop {r4, lr}
; AAPCS-SOFT-NEXT:    mov pc, lr
;
; APCS-LABEL: f64_to_f16:
; APCS:       @ %bb.0:
; APCS-NEXT:    push {r4, lr}
; APCS-NEXT:    mov r4, r0
; APCS-NEXT:    mov r0, r1
; APCS-NEXT:    mov r1, r2
; APCS-NEXT:    bl __truncdfhf2
; APCS-NEXT:    strh r0, [r4]
; APCS-NEXT:    pop {r4, pc}
;
; WATCHABI-HARD-LABEL: f64_to_f16:
; WATCHABI-HARD:       @ %bb.0:
; WATCHABI-HARD-NEXT:    push {r4, lr}
; WATCHABI-HARD-NEXT:    sub sp, sp, #8
; WATCHABI-HARD-NEXT:    mov r4, r0
; WATCHABI-HARD-NEXT:    bl ___truncdfhf2
; WATCHABI-HARD-NEXT:    strh r0, [r4]
; WATCHABI-HARD-NEXT:    add sp, sp, #8
; WATCHABI-HARD-NEXT:    pop {r4, pc}
;
; WATCHABI-SOFT-LABEL: f64_to_f16:
; WATCHABI-SOFT:       @ %bb.0:
; WATCHABI-SOFT-NEXT:    push {r4, lr}
; WATCHABI-SOFT-NEXT:    sub sp, sp, #8
; WATCHABI-SOFT-NEXT:    mov r4, r0
; WATCHABI-SOFT-NEXT:    mov r1, r3
; WATCHABI-SOFT-NEXT:    mov r0, r2
; WATCHABI-SOFT-NEXT:    bl ___truncdfhf2
; WATCHABI-SOFT-NEXT:    strh r0, [r4]
; WATCHABI-SOFT-NEXT:    add sp, sp, #8
; WATCHABI-SOFT-NEXT:    pop {r4, pc}
  %cvt = fptrunc double %arg to half
  store half %cvt, ptr %p
  ret void
}

attributes #0 = { nounwind }
