; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mattr=+neon,+fullfp16,+fprcvt -verify-machineinstrs %s -o - | FileCheck %s
; RUN: llc -mattr=+neon -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK-NO-FPRCVT

target triple = "aarch64-unknown-linux-gnu"


; To demonstrate what we have implemented, we'll want a scalar integer value in a SIMD/FP register.
; A common case for this setup is when using the result of an integer reduction intrinsic.

; SCVTF

define half @scvtf_f16i32(<4 x i32> %x) {
; CHECK-LABEL: scvtf_f16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    scvtf h0, s0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f16i32:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, s0
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <4 x i32> %x, i64 0
 %conv = sitofp i32 %extract to half
 ret half %conv
}

define half @scvtf_f16i32_neg(<4 x i32> %x) {
; CHECK-LABEL: scvtf_f16i32_neg:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, v0.s[1]
; CHECK-NEXT:    scvtf h0, w8
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f16i32_neg:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    mov w8, v0.s[1]
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, w8
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <4 x i32> %x, i64 1
 %conv = sitofp i32 %extract to half
 ret half %conv
}

define <1 x half> @scvtf_f16i32_simple(<1 x i32> %x) {
; CHECK-LABEL: scvtf_f16i32_simple:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT:    scvtf h0, s0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f16i32_simple:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, s0
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %conv = sitofp <1 x i32> %x to <1 x half>
 ret <1 x half> %conv
}

define double @scvtf_f64i32(<4 x i32> %x) {
; CHECK-LABEL: scvtf_f64i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    scvtf d0, s0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f64i32:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    fmov w8, s0
; CHECK-NO-FPRCVT-NEXT:    scvtf d0, w8
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <4 x i32> %x, i64 0
 %conv = sitofp i32 %extract to double
 ret double %conv
}

define double @scvtf_f64i32_neg(<4 x i32> %x) {
; CHECK-LABEL: scvtf_f64i32_neg:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, v0.s[1]
; CHECK-NEXT:    scvtf d0, w8
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f64i32_neg:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    mov w8, v0.s[1]
; CHECK-NO-FPRCVT-NEXT:    scvtf d0, w8
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <4 x i32> %x, i64 1
 %conv = sitofp i32 %extract to double
 ret double %conv
}

define <1 x double> @scvtf_f64i32_simple(<1 x i32> %x) {
; CHECK-LABEL: scvtf_f64i32_simple:
; CHECK:       // %bb.0:
; CHECK-NEXT:    scvtf d0, s0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f64i32_simple:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    sshll v0.2d, v0.2s, #0
; CHECK-NO-FPRCVT-NEXT:    scvtf v0.2d, v0.2d
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 killed $q0
; CHECK-NO-FPRCVT-NEXT:    ret
 %conv = sitofp <1 x i32> %x to <1 x double>
 ret <1 x double> %conv
}

define half @scvtf_f16i64(<2 x i64> %x) {
; CHECK-LABEL: scvtf_f16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    scvtf h0, d0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f16i64:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    fmov x8, d0
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <2 x i64> %x, i64 0
 %conv = sitofp i64 %extract to half
 ret half %conv
}

define half @scvtf_f16i64_neg(<2 x i64> %x) {
; CHECK-LABEL: scvtf_f16i64_neg:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov x8, v0.d[1]
; CHECK-NEXT:    scvtf h0, x8
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f16i64_neg:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    mov x8, v0.d[1]
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <2 x i64> %x, i64 1
 %conv = sitofp i64 %extract to half
 ret half %conv
}

define <1 x half> @scvtf_f16i64_simple(<1 x i64> %x) {
; CHECK-LABEL: scvtf_f16i64_simple:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT:    scvtf h0, d0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f16i64_simple:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NO-FPRCVT-NEXT:    fmov x8, d0
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %conv = sitofp <1 x i64> %x to <1 x half>
 ret <1 x half> %conv
}

define float @scvtf_f32i64(<2 x i64> %x) {
; CHECK-LABEL: scvtf_f32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    scvtf s0, d0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f32i64:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    fmov x8, d0
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <2 x i64> %x, i64 0
 %conv = sitofp i64 %extract to float
 ret float %conv
}

define float @scvtf_f32i64_neg(<2 x i64> %x) {
; CHECK-LABEL: scvtf_f32i64_neg:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov x8, v0.d[1]
; CHECK-NEXT:    scvtf s0, x8
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f32i64_neg:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    mov x8, v0.d[1]
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <2 x i64> %x, i64 1
 %conv = sitofp i64 %extract to float
 ret float %conv
}

; This test does not give the indended result of scvtf s0, d0
; This is due to the input being loaded as a 2 item vector and
; therefore using vector inputs that do not match the pattern
; This test will be fixed in a future revision
define <1 x float> @scvtf_f32i64_simple(<1 x i64> %x) {
; CHECK-LABEL: scvtf_f32i64_simple:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT:    movi d1, #0000000000000000
; CHECK-NEXT:    scvtf s0, d0
; CHECK-NEXT:    mov v1.s[0], v0.s[0]
; CHECK-NEXT:    fmov d0, d1
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: scvtf_f32i64_simple:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NO-FPRCVT-NEXT:    fmov x8, d0
; CHECK-NO-FPRCVT-NEXT:    movi d1, #0000000000000000
; CHECK-NO-FPRCVT-NEXT:    scvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    mov v1.s[0], v0.s[0]
; CHECK-NO-FPRCVT-NEXT:    fmov d0, d1
; CHECK-NO-FPRCVT-NEXT:    ret
 %conv = sitofp <1 x i64> %x to <1 x float>
 ret <1 x float> %conv
}

; UCVTF

define half @ucvtf_f16i32(<4 x i32> %x) {
; CHECK-LABEL: ucvtf_f16i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ucvtf h0, s0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f16i32:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, s0
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <4 x i32> %x, i64 0
 %conv = uitofp i32 %extract to half
 ret half %conv
}

define half @ucvtf_f16i32_neg(<4 x i32> %x) {
; CHECK-LABEL: ucvtf_f16i32_neg:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, v0.s[1]
; CHECK-NEXT:    ucvtf h0, w8
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f16i32_neg:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    mov w8, v0.s[1]
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, w8
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <4 x i32> %x, i64 1
 %conv = uitofp i32 %extract to half
 ret half %conv
}

define <1 x half> @ucvtf_f16i32_simple(<1 x i32> %x) {
; CHECK-LABEL: ucvtf_f16i32_simple:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT:    ucvtf h0, s0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f16i32_simple:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, s0
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %conv = uitofp <1 x i32> %x to <1 x half>
 ret <1 x half> %conv
}

define double @ucvtf_f64i32(<4 x i32> %x) {
; CHECK-LABEL: ucvtf_f64i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ucvtf d0, s0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f64i32:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    fmov w8, s0
; CHECK-NO-FPRCVT-NEXT:    ucvtf d0, w8
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <4 x i32> %x, i64 0
 %conv = uitofp i32 %extract to double
 ret double %conv
}

define double @ucvtf_f64i32_neg(<4 x i32> %x) {
; CHECK-LABEL: ucvtf_f64i32_neg:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, v0.s[1]
; CHECK-NEXT:    ucvtf d0, w8
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f64i32_neg:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    mov w8, v0.s[1]
; CHECK-NO-FPRCVT-NEXT:    ucvtf d0, w8
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <4 x i32> %x, i64 1
 %conv = uitofp i32 %extract to double
 ret double %conv
}

define <1 x double> @ucvtf_f64i32_simple(<1 x i32> %x) {
; CHECK-LABEL: ucvtf_f64i32_simple:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ucvtf d0, s0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f64i32_simple:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    ushll v0.2d, v0.2s, #0
; CHECK-NO-FPRCVT-NEXT:    ucvtf v0.2d, v0.2d
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 killed $q0
; CHECK-NO-FPRCVT-NEXT:    ret
 %conv = uitofp <1 x i32> %x to <1 x double>
 ret <1 x double> %conv
}

define half @ucvtf_f16i64(<2 x i64> %x) {
; CHECK-LABEL: ucvtf_f16i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ucvtf h0, d0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f16i64:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    fmov x8, d0
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <2 x i64> %x, i64 0
 %conv = uitofp i64 %extract to half
 ret half %conv
}

define half @ucvtf_f16i64_neg(<2 x i64> %x) {
; CHECK-LABEL: ucvtf_f16i64_neg:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov x8, v0.d[1]
; CHECK-NEXT:    ucvtf h0, x8
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f16i64_neg:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    mov x8, v0.d[1]
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <2 x i64> %x, i64 1
 %conv = uitofp i64 %extract to half
 ret half %conv
}

define <1 x half> @ucvtf_f16i64_simple(<1 x i64> %x) {
; CHECK-LABEL: ucvtf_f16i64_simple:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT:    ucvtf h0, d0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f16i64_simple:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NO-FPRCVT-NEXT:    fmov x8, d0
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    fcvt h0, s0
; CHECK-NO-FPRCVT-NEXT:    ret
 %conv = uitofp <1 x i64> %x to <1 x half>
 ret <1 x half> %conv
}

define float @ucvtf_f32i64(<2 x i64> %x) {
; CHECK-LABEL: ucvtf_f32i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ucvtf s0, d0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f32i64:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    fmov x8, d0
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <2 x i64> %x, i64 0
 %conv = uitofp i64 %extract to float
 ret float %conv
}

define float @ucvtf_f32i64_neg(<2 x i64> %x) {
; CHECK-LABEL: ucvtf_f32i64_neg:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov x8, v0.d[1]
; CHECK-NEXT:    ucvtf s0, x8
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f32i64_neg:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    mov x8, v0.d[1]
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    ret
 %extract = extractelement <2 x i64> %x, i64 1
 %conv = uitofp i64 %extract to float
 ret float %conv
}

; This test does not give the indended result of ucvtf s0, d0
; This is due to the input being loaded as a 2 item vector and
; therefore using vector inputs that do not match the pattern
; This test will be fixed in a future revision
define <1 x float> @ucvtf_f32i64_simple(<1 x i64> %x) {
; CHECK-LABEL: ucvtf_f32i64_simple:
; CHECK:       // %bb.0:
; CHECK-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NEXT:    movi d1, #0000000000000000
; CHECK-NEXT:    ucvtf s0, d0
; CHECK-NEXT:    mov v1.s[0], v0.s[0]
; CHECK-NEXT:    fmov d0, d1
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: ucvtf_f32i64_simple:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 def $q0
; CHECK-NO-FPRCVT-NEXT:    fmov x8, d0
; CHECK-NO-FPRCVT-NEXT:    movi d1, #0000000000000000
; CHECK-NO-FPRCVT-NEXT:    ucvtf s0, x8
; CHECK-NO-FPRCVT-NEXT:    mov v1.s[0], v0.s[0]
; CHECK-NO-FPRCVT-NEXT:    fmov d0, d1
; CHECK-NO-FPRCVT-NEXT:    ret
 %conv = uitofp <1 x i64> %x to <1 x float>
 ret <1 x float> %conv
}

define <1 x double> @uitofp_sext_v2i32_extract_lane0(<2 x i32> %x) {
; CHECK-LABEL: uitofp_sext_v2i32_extract_lane0:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sshll v0.2d, v0.2s, #0
; CHECK-NEXT:    ucvtf v0.2d, v0.2d
; CHECK-NEXT:    // kill: def $d0 killed $d0 killed $q0
; CHECK-NEXT:    ret
;
; CHECK-NO-FPRCVT-LABEL: uitofp_sext_v2i32_extract_lane0:
; CHECK-NO-FPRCVT:       // %bb.0:
; CHECK-NO-FPRCVT-NEXT:    sshll v0.2d, v0.2s, #0
; CHECK-NO-FPRCVT-NEXT:    ucvtf v0.2d, v0.2d
; CHECK-NO-FPRCVT-NEXT:    // kill: def $d0 killed $d0 killed $q0
; CHECK-NO-FPRCVT-NEXT:    ret
  %wide  = sext <2 x i32> %x to <2 x i64>
  %fpv2  = uitofp <2 x i64> %wide to <2 x double>
  %lane0 = shufflevector <2 x double> %fpv2, <2 x double> poison, <1 x i32> zeroinitializer
  ret <1 x double> %lane0
}

