[llvm] [AArch64] Codegen for new SCVTF/UCVTF variants (FEAT_FPRCVT) (PR #123767)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 31 08:01:46 PST 2025


================
@@ -0,0 +1,283 @@
+; 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 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 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 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
+}
+
+; 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 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 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 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
+}
----------------
CarolineConcatto wrote:


Can we also add tests without the extract.  Like this one:
```
define <1 x half> @scvtf_f16i32_1(<1 x i32> %x) {
 %conv = sitofp <1 x i32> %x to <1 x half>
 ret <1 x half> %conv
}
```
I think this will force the compiler to use the FPR register and then it can test 
 [(set (dvt dstType:$Rd), (node srcType:$Rn))]>, from line 5387 that  now could also triggered when using any_sint_to_fp.

Just in case:
I did create these tests locally and noticed that convert between 32bits and 64bits does not used the new SCVTF  as expect. But I don't think you need to fix that in this patch.
Like for instance:
```
define <1 x float> @scvtf_f32i64(<1 x i64> %x) {
 %conv = sitofp <1 x i64> %x to <1 x float>
 ret <1 x float> %conv
}
```
Is using:
```
 scvtf v0.2d, v0.2d
fcvtn v0.2s, v0.2d
```
but it should be :
` scvtf s0, d0.`



https://github.com/llvm/llvm-project/pull/123767


More information about the llvm-commits mailing list