; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=x86_64-apple-macosx %s -o - | FileCheck %s --check-prefix=CHECK-SOFT
; RUN: llc -mtriple=x86_64-apple-macosx -mattr=+f16c %s -o - | FileCheck %s --check-prefix=CHECK-F16C
; RUN: llc -mtriple=x86_64-apple-macosx -mattr=+avx512fp16 %s -o - | FileCheck %s --check-prefix=CHECK-FP16

define void @truncsfhf(float %in, ptr %ptr) nounwind {
; CHECK-SOFT-LABEL: truncsfhf:
; CHECK-SOFT:       ## %bb.0:
; CHECK-SOFT-NEXT:    pushq %rbx
; CHECK-SOFT-NEXT:    movq %rdi, %rbx
; CHECK-SOFT-NEXT:    callq ___truncsfhf2
; CHECK-SOFT-NEXT:    movw %ax, (%rbx)
; CHECK-SOFT-NEXT:    popq %rbx
; CHECK-SOFT-NEXT:    retq
;
; CHECK-F16C-LABEL: truncsfhf:
; CHECK-F16C:       ## %bb.0:
; CHECK-F16C-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
; CHECK-F16C-NEXT:    vmovd %xmm0, %eax
; CHECK-F16C-NEXT:    movw %ax, (%rdi)
; CHECK-F16C-NEXT:    retq
;
; CHECK-FP16-LABEL: truncsfhf:
; CHECK-FP16:       ## %bb.0:
; CHECK-FP16-NEXT:    vcvtss2sh %xmm0, %xmm0, %xmm0
; CHECK-FP16-NEXT:    vmovsh %xmm0, (%rdi)
; CHECK-FP16-NEXT:    retq



  %half = fptrunc float %in to half
  store half %half, ptr %ptr
  ret void
}

define void @truncdfhf(double %in, ptr %ptr) nounwind {
; CHECK-SOFT-LABEL: truncdfhf:
; CHECK-SOFT:       ## %bb.0:
; CHECK-SOFT-NEXT:    pushq %rbx
; CHECK-SOFT-NEXT:    movq %rdi, %rbx
; CHECK-SOFT-NEXT:    callq ___truncdfhf2
; CHECK-SOFT-NEXT:    movw %ax, (%rbx)
; CHECK-SOFT-NEXT:    popq %rbx
; CHECK-SOFT-NEXT:    retq
;
; CHECK-F16C-LABEL: truncdfhf:
; CHECK-F16C:       ## %bb.0:
; CHECK-F16C-NEXT:    pushq %rbx
; CHECK-F16C-NEXT:    movq %rdi, %rbx
; CHECK-F16C-NEXT:    callq ___truncdfhf2
; CHECK-F16C-NEXT:    movw %ax, (%rbx)
; CHECK-F16C-NEXT:    popq %rbx
; CHECK-F16C-NEXT:    retq
;
; CHECK-FP16-LABEL: truncdfhf:
; CHECK-FP16:       ## %bb.0:
; CHECK-FP16-NEXT:    vcvtsd2sh %xmm0, %xmm0, %xmm0
; CHECK-FP16-NEXT:    vmovsh %xmm0, (%rdi)
; CHECK-FP16-NEXT:    retq



  %half = fptrunc double %in to half
  store half %half, ptr %ptr
  ret void
}

define float @extendhfsf(ptr %ptr) nounwind {
; CHECK-SOFT-LABEL: extendhfsf:
; CHECK-SOFT:       ## %bb.0:
; CHECK-SOFT-NEXT:    pushq %rax
; CHECK-SOFT-NEXT:    movzwl (%rdi), %edi
; CHECK-SOFT-NEXT:    callq ___extendhfsf2
; CHECK-SOFT-NEXT:    popq %rax
; CHECK-SOFT-NEXT:    retq
;
; CHECK-F16C-LABEL: extendhfsf:
; CHECK-F16C:       ## %bb.0:
; CHECK-F16C-NEXT:    movzwl (%rdi), %eax
; CHECK-F16C-NEXT:    vmovd %eax, %xmm0
; CHECK-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
; CHECK-F16C-NEXT:    retq
;
; CHECK-FP16-LABEL: extendhfsf:
; CHECK-FP16:       ## %bb.0:
; CHECK-FP16-NEXT:    vmovsh (%rdi), %xmm0
; CHECK-FP16-NEXT:    vcvtsh2ss %xmm0, %xmm0, %xmm0
; CHECK-FP16-NEXT:    retq



  %in = load half, ptr %ptr
  %float = fpext half %in to float
  ret float %float
}

define void @strict_truncsfhf(float %in, ptr %ptr) nounwind strictfp {
; CHECK-SOFT-LABEL: strict_truncsfhf:
; CHECK-SOFT:       ## %bb.0:
; CHECK-SOFT-NEXT:    pushq %rbx
; CHECK-SOFT-NEXT:    movq %rdi, %rbx
; CHECK-SOFT-NEXT:    callq ___truncsfhf2
; CHECK-SOFT-NEXT:    movw %ax, (%rbx)
; CHECK-SOFT-NEXT:    popq %rbx
; CHECK-SOFT-NEXT:    retq
;
; CHECK-F16C-LABEL: strict_truncsfhf:
; CHECK-F16C:       ## %bb.0:
; CHECK-F16C-NEXT:    vxorps %xmm1, %xmm1, %xmm1
; CHECK-F16C-NEXT:    vblendps {{.*#+}} xmm0 = xmm0[0],xmm1[1,2,3]
; CHECK-F16C-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
; CHECK-F16C-NEXT:    vmovd %xmm0, %eax
; CHECK-F16C-NEXT:    movw %ax, (%rdi)
; CHECK-F16C-NEXT:    retq
;
; CHECK-FP16-LABEL: strict_truncsfhf:
; CHECK-FP16:       ## %bb.0:
; CHECK-FP16-NEXT:    vcvtss2sh %xmm0, %xmm0, %xmm0
; CHECK-FP16-NEXT:    vmovsh %xmm0, (%rdi)
; CHECK-FP16-NEXT:    retq



  %half = call half @llvm.experimental.constrained.fptrunc.f16.f32(float %in, metadata  !"round.tonearest", metadata !"fpexcept.strict")
  store half %half, ptr %ptr
  ret void
}

define void @strict_truncdfhf(double %in, ptr %ptr) nounwind strictfp {
; CHECK-SOFT-LABEL: strict_truncdfhf:
; CHECK-SOFT:       ## %bb.0:
; CHECK-SOFT-NEXT:    pushq %rbx
; CHECK-SOFT-NEXT:    movq %rdi, %rbx
; CHECK-SOFT-NEXT:    callq ___truncdfhf2
; CHECK-SOFT-NEXT:    movw %ax, (%rbx)
; CHECK-SOFT-NEXT:    popq %rbx
; CHECK-SOFT-NEXT:    retq
;
; CHECK-F16C-LABEL: strict_truncdfhf:
; CHECK-F16C:       ## %bb.0:
; CHECK-F16C-NEXT:    pushq %rbx
; CHECK-F16C-NEXT:    movq %rdi, %rbx
; CHECK-F16C-NEXT:    callq ___truncdfhf2
; CHECK-F16C-NEXT:    movw %ax, (%rbx)
; CHECK-F16C-NEXT:    popq %rbx
; CHECK-F16C-NEXT:    retq
;
; CHECK-FP16-LABEL: strict_truncdfhf:
; CHECK-FP16:       ## %bb.0:
; CHECK-FP16-NEXT:    vcvtsd2sh %xmm0, %xmm0, %xmm0
; CHECK-FP16-NEXT:    vmovsh %xmm0, (%rdi)
; CHECK-FP16-NEXT:    retq


  %half = call half @llvm.experimental.constrained.fptrunc.f16.f64(double %in, metadata !"round.tonearest", metadata !"fpexcept.strict")
  store half %half, ptr %ptr
  ret void
}

define float @strict_extendhfsf(ptr %ptr) nounwind strictfp {
; CHECK-SOFT-LABEL: strict_extendhfsf:
; CHECK-SOFT:       ## %bb.0:
; CHECK-SOFT-NEXT:    pushq %rax
; CHECK-SOFT-NEXT:    movzwl (%rdi), %edi
; CHECK-SOFT-NEXT:    callq ___extendhfsf2
; CHECK-SOFT-NEXT:    popq %rax
; CHECK-SOFT-NEXT:    retq
;
; CHECK-F16C-LABEL: strict_extendhfsf:
; CHECK-F16C:       ## %bb.0:
; CHECK-F16C-NEXT:    movzwl (%rdi), %eax
; CHECK-F16C-NEXT:    vmovd %eax, %xmm0
; CHECK-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
; CHECK-F16C-NEXT:    retq
;
; CHECK-FP16-LABEL: strict_extendhfsf:
; CHECK-FP16:       ## %bb.0:
; CHECK-FP16-NEXT:    vmovsh (%rdi), %xmm0
; CHECK-FP16-NEXT:    vcvtsh2ss %xmm0, %xmm0, %xmm0
; CHECK-FP16-NEXT:    retq


  %in = load half, ptr %ptr
  %float = call float @llvm.experimental.constrained.fpext.f32.f16(half %in, metadata !"fpexcept.strict")
  ret float %float
}

declare half @llvm.experimental.constrained.fptrunc.f16.f32(float, metadata, metadata)
declare half @llvm.experimental.constrained.fptrunc.f16.f64(double, metadata, metadata)
declare float @llvm.experimental.constrained.fpext.f32.f16(half, metadata)
