[llvm] [AArch64] Codegen for new SCVTF/UCVTF variants (FEAT_FPRCVT) (PR #123767)
Virginia Cangelosi via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 24 03:01:27 PST 2025
https://github.com/virginia-cangelosi updated https://github.com/llvm/llvm-project/pull/123767
>From 5812fcdc7275e4a39ee143dbb81edaa7689866b8 Mon Sep 17 00:00:00 2001
From: Virginia Cangelosi <virginia.cangelosi at arm.com>
Date: Tue, 21 Jan 2025 11:02:13 +0000
Subject: [PATCH] [AArch64] Codegen for new SCVTF/UCVTF variants (FEAT_FPRCVT)
---
.../lib/Target/AArch64/AArch64InstrFormats.td | 15 +-
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 4 +-
llvm/test/CodeGen/AArch64/fprcvt-cvtf.ll | 283 ++++++++++++++++++
3 files changed, 298 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/fprcvt-cvtf.ll
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 6a3a9492e031c6..3a2a79167e163b 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -5487,7 +5487,7 @@ multiclass IntegerToFP<bits<2> rmode, bits<3> opcode, string asm, SDPatternOpera
}
}
-multiclass IntegerToFPSIMDScalar<bits<2> rmode, bits<3> opcode, string asm, SDPatternOperator node = null_frag> {
+multiclass IntegerToFPSIMDScalar<bits<2> rmode, bits<3> opcode, string asm, SDPatternOperator op, SDPatternOperator node = null_frag> {
// 32-bit to half-precision
def HSr: BaseIntegerToFPUnscaled<rmode, opcode, FPR32, FPR16, f16, asm, node> {
let Inst{31} = 0; // 32-bit FPR flag
@@ -5511,6 +5511,18 @@ multiclass IntegerToFPSIMDScalar<bits<2> rmode, bits<3> opcode, string asm, SDPa
let Inst{31} = 1; // 64-bit FPR flag
let Inst{23-22} = 0b00; // 32-bit FPR flag
}
+
+ def : Pat<(f16 (op (i32 FPR32:$Rn))),
+ (!cast<Instruction>(NAME # HSr) $Rn)>;
+
+ def : Pat<(f16 (op (i32 (extractelt (v4i32 V128:$Rn), (i64 0))))),
+ (!cast<Instruction>(NAME # HSr) (EXTRACT_SUBREG $Rn, ssub))>;
+ def : Pat<(f64 (op (i32 (extractelt (v4i32 V128:$Rn), (i64 0))))),
+ (!cast<Instruction>(NAME # DSr) (EXTRACT_SUBREG $Rn, ssub))>;
+ def : Pat<(f16 (op (i64 (extractelt (v2i64 V128:$Rn), (i64 0))))),
+ (!cast<Instruction>(NAME # HDr) (EXTRACT_SUBREG $Rn, dsub))>;
+ def : Pat<(f32 (op (i64 (extractelt (v2i64 V128:$Rn), (i64 0))))),
+ (!cast<Instruction>(NAME # SDr) (EXTRACT_SUBREG $Rn, dsub))>;
}
//---
@@ -13270,4 +13282,3 @@ multiclass SIMDThreeSameVectorFP8MatrixMul<string asm>{
let Predicates = [HasNEON, HasF8F32MM];
}
}
-
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index fa6385409f30c7..183fa5ffbe75f8 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -5068,8 +5068,8 @@ defm SCVTF : IntegerToFP<0b00, 0b010, "scvtf", any_sint_to_fp>;
defm UCVTF : IntegerToFP<0b00, 0b011, "ucvtf", any_uint_to_fp>;
let Predicates = [HasNEON, HasFPRCVT] in {
- defm SCVTF : IntegerToFPSIMDScalar<0b11, 0b100, "scvtf">;
- defm UCVTF : IntegerToFPSIMDScalar<0b11, 0b101, "ucvtf">;
+ defm SCVTF : IntegerToFPSIMDScalar<0b11, 0b100, "scvtf", any_sint_to_fp>;
+ defm UCVTF : IntegerToFPSIMDScalar<0b11, 0b101, "ucvtf", any_uint_to_fp>;
}
def : Pat<(f16 (fdiv (f16 (any_sint_to_fp (i32 GPR32:$Rn))), fixedpoint_f16_i32:$scale)),
diff --git a/llvm/test/CodeGen/AArch64/fprcvt-cvtf.ll b/llvm/test/CodeGen/AArch64/fprcvt-cvtf.ll
new file mode 100644
index 00000000000000..742e811be75f5f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/fprcvt-cvtf.ll
@@ -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
+}
More information about the llvm-commits
mailing list