[llvm] [AArch64][llvm] Pre-commit tests for new fpcvt codegen (PR #173272)
Jonathan Thackray via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 22 07:31:55 PST 2025
https://github.com/jthackray created https://github.com/llvm/llvm-project/pull/173272
[AArch64][llvm] Pre-commit tests for new fpcvt codegen
[AArch64][llvm] Add codegen for simd fpcvt intrinsics
Add tablegen patterns to provide codegen for SCVTF and UCVTF
operating purely on SIMD & FP registers, using explicit bitcasts.
>From b380116c0167bd002bab99a9aa5a9726ab17c6d5 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 22 Dec 2025 14:17:52 +0000
Subject: [PATCH 1/2] [AArch64][llvm] Pre-commit tests for new fpcvt codegen
---
.../AArch64/arm64-cvtf-simd-intrinsics.ll | 90 +++++++++++++++++++
1 file changed, 90 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/arm64-cvtf-simd-intrinsics.ll
diff --git a/llvm/test/CodeGen/AArch64/arm64-cvtf-simd-intrinsics.ll b/llvm/test/CodeGen/AArch64/arm64-cvtf-simd-intrinsics.ll
new file mode 100644
index 0000000000000..f4dc91cb962ed
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/arm64-cvtf-simd-intrinsics.ll
@@ -0,0 +1,90 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=aarch64-unknown-unknown -mattr=+neon,+fullfp16,+fprcvt | FileCheck %s --check-prefixes=CHECK
+
+define double @scvtf_bitcast_f32_to_f64(float %f) nounwind {
+; CHECK-LABEL: scvtf_bitcast_f32_to_f64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov w8, s0
+; CHECK-NEXT: scvtf d0, w8
+; CHECK-NEXT: ret
+ %i = bitcast float %f to i32
+ %r = sitofp i32 %i to double
+ ret double %r
+}
+
+define double @ucvtf_bitcast_f32_to_f64(float %f) nounwind {
+; CHECK-LABEL: ucvtf_bitcast_f32_to_f64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov w8, s0
+; CHECK-NEXT: ucvtf d0, w8
+; CHECK-NEXT: ret
+ %i = bitcast float %f to i32
+ %r = uitofp i32 %i to double
+ ret double %r
+}
+
+define half @scvtf_bitcast_f32_to_f16(float %f) nounwind {
+; CHECK-LABEL: scvtf_bitcast_f32_to_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov w8, s0
+; CHECK-NEXT: scvtf h0, w8
+; CHECK-NEXT: ret
+ %i = bitcast float %f to i32
+ %r = sitofp i32 %i to half
+ ret half %r
+}
+
+define half @ucvtf_bitcast_f32_to_f16(float %f) nounwind {
+; CHECK-LABEL: ucvtf_bitcast_f32_to_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov w8, s0
+; CHECK-NEXT: ucvtf h0, w8
+; CHECK-NEXT: ret
+ %i = bitcast float %f to i32
+ %r = uitofp i32 %i to half
+ ret half %r
+}
+
+define float @scvtf_bitcast_f64_to_f32(double %d) nounwind {
+; CHECK-LABEL: scvtf_bitcast_f64_to_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov x8, d0
+; CHECK-NEXT: scvtf s0, x8
+; CHECK-NEXT: ret
+ %i = bitcast double %d to i64
+ %r = sitofp i64 %i to float
+ ret float %r
+}
+
+define float @ucvtf_bitcast_f64_to_f32(double %d) nounwind {
+; CHECK-LABEL: ucvtf_bitcast_f64_to_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov x8, d0
+; CHECK-NEXT: ucvtf s0, x8
+; CHECK-NEXT: ret
+ %i = bitcast double %d to i64
+ %r = uitofp i64 %i to float
+ ret float %r
+}
+
+define half @scvtf_bitcast_f64_to_f16(double %d) nounwind {
+; CHECK-LABEL: scvtf_bitcast_f64_to_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov x8, d0
+; CHECK-NEXT: scvtf h0, x8
+; CHECK-NEXT: ret
+ %i = bitcast double %d to i64
+ %r = sitofp i64 %i to half
+ ret half %r
+}
+
+define half @ucvtf_bitcast_f64_to_f16(double %d) nounwind {
+; CHECK-LABEL: ucvtf_bitcast_f64_to_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov x8, d0
+; CHECK-NEXT: ucvtf h0, x8
+; CHECK-NEXT: ret
+ %i = bitcast double %d to i64
+ %r = uitofp i64 %i to half
+ ret half %r
+}
>From 80bc071af380f13e4a9140de1918a1befeb95a74 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Thu, 18 Dec 2025 14:28:38 +0000
Subject: [PATCH 2/2] [AArch64][llvm] Add codegen for simd fpcvt intrinsics
Add tablegen patterns to provide codegen for SCVTF and UCVTF
operating purely on SIMD & FP registers, using explicit bitcasts.
---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 30 +++++++++++++++++++
.../AArch64/arm64-cvtf-simd-intrinsics.ll | 27 +++++++----------
2 files changed, 40 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index f3cd613a6bd99..8b0ec69adb737 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -6557,6 +6557,36 @@ defm UQXTN : SIMDTwoScalarMixedBHS<1, 0b10100, "uqxtn", int_aarch64_neon_scalar
defm USQADD : SIMDTwoScalarBHSDTied< 1, 0b00011, "usqadd",
int_aarch64_neon_usqadd>;
+// Floating-point conversion patterns.
+multiclass IntegerToFPSIMDScalarPatterns<SDPatternOperator OpN, string INST> {
+ let Predicates = [HasFPRCVT] in {
+ def : Pat<(f64 (OpN (i32 (bitconvert (f32 FPR32:$Rn))))),
+ (!cast<Instruction>(INST # DSr) FPR32:$Rn)>;
+ def : Pat<(f16 (OpN (i32 (bitconvert (f32 FPR32:$Rn))))),
+ (!cast<Instruction>(INST # HSr) FPR32:$Rn)>;
+ def : Pat<(f16 (OpN (i64 (bitconvert (f64 FPR64:$Rn))))),
+ (!cast<Instruction>(INST # HDr) FPR64:$Rn)>;
+ def : Pat<(f32 (OpN (i64 (bitconvert (f64 FPR64:$Rn))))),
+ (!cast<Instruction>(INST # SDr) FPR64:$Rn)>;
+ }
+ def : Pat<(f32 (OpN (i32 (bitconvert (f32 FPR32:$Rn))))),
+ (!cast<Instruction>(INST # v1i32) FPR32:$Rn)>;
+ def : Pat<(f64 (OpN (i64 (bitconvert (f64 FPR64:$Rn))))),
+ (!cast<Instruction>(INST # v1i64) FPR64:$Rn)>;
+
+ def : Pat<(f16 (OpN (i16 (vector_extract (v8i16 FPR128:$Rn), (i64 0))))),
+ (!cast<Instruction>(INST # v1i16)
+ (EXTRACT_SUBREG (v8i16 FPR128:$Rn), hsub))>;
+ def : Pat<(f32 (OpN (i32 (vector_extract (v4i32 FPR128:$Rn), (i64 0))))),
+ (!cast<Instruction>(INST # v1i32)
+ (EXTRACT_SUBREG (v4i32 FPR128:$Rn), ssub))>;
+ def : Pat<(f64 (OpN (i64 (vector_extract (v2i64 FPR128:$Rn), (i64 0))))),
+ (!cast<Instruction>(INST # v1i64)
+ (EXTRACT_SUBREG (v2i64 FPR128:$Rn), dsub))>;
+}
+defm : IntegerToFPSIMDScalarPatterns<sint_to_fp, "SCVTF">;
+defm : IntegerToFPSIMDScalarPatterns<uint_to_fp, "UCVTF">;
+
// Floating-point conversion patterns.
multiclass FPToIntegerSIMDScalarPatterns<SDPatternOperator OpN, string INST> {
let Predicates = [HasFPRCVT] in {
diff --git a/llvm/test/CodeGen/AArch64/arm64-cvtf-simd-intrinsics.ll b/llvm/test/CodeGen/AArch64/arm64-cvtf-simd-intrinsics.ll
index f4dc91cb962ed..29102d9ca9587 100644
--- a/llvm/test/CodeGen/AArch64/arm64-cvtf-simd-intrinsics.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-cvtf-simd-intrinsics.ll
@@ -1,11 +1,11 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+
; RUN: llc < %s -mtriple=aarch64-unknown-unknown -mattr=+neon,+fullfp16,+fprcvt | FileCheck %s --check-prefixes=CHECK
define double @scvtf_bitcast_f32_to_f64(float %f) nounwind {
; CHECK-LABEL: scvtf_bitcast_f32_to_f64:
; CHECK: // %bb.0:
-; CHECK-NEXT: fmov w8, s0
-; CHECK-NEXT: scvtf d0, w8
+; CHECK-NEXT: scvtf d0, s0
; CHECK-NEXT: ret
%i = bitcast float %f to i32
%r = sitofp i32 %i to double
@@ -15,8 +15,7 @@ define double @scvtf_bitcast_f32_to_f64(float %f) nounwind {
define double @ucvtf_bitcast_f32_to_f64(float %f) nounwind {
; CHECK-LABEL: ucvtf_bitcast_f32_to_f64:
; CHECK: // %bb.0:
-; CHECK-NEXT: fmov w8, s0
-; CHECK-NEXT: ucvtf d0, w8
+; CHECK-NEXT: ucvtf d0, s0
; CHECK-NEXT: ret
%i = bitcast float %f to i32
%r = uitofp i32 %i to double
@@ -26,8 +25,7 @@ define double @ucvtf_bitcast_f32_to_f64(float %f) nounwind {
define half @scvtf_bitcast_f32_to_f16(float %f) nounwind {
; CHECK-LABEL: scvtf_bitcast_f32_to_f16:
; CHECK: // %bb.0:
-; CHECK-NEXT: fmov w8, s0
-; CHECK-NEXT: scvtf h0, w8
+; CHECK-NEXT: scvtf h0, s0
; CHECK-NEXT: ret
%i = bitcast float %f to i32
%r = sitofp i32 %i to half
@@ -37,8 +35,7 @@ define half @scvtf_bitcast_f32_to_f16(float %f) nounwind {
define half @ucvtf_bitcast_f32_to_f16(float %f) nounwind {
; CHECK-LABEL: ucvtf_bitcast_f32_to_f16:
; CHECK: // %bb.0:
-; CHECK-NEXT: fmov w8, s0
-; CHECK-NEXT: ucvtf h0, w8
+; CHECK-NEXT: ucvtf h0, s0
; CHECK-NEXT: ret
%i = bitcast float %f to i32
%r = uitofp i32 %i to half
@@ -48,8 +45,7 @@ define half @ucvtf_bitcast_f32_to_f16(float %f) nounwind {
define float @scvtf_bitcast_f64_to_f32(double %d) nounwind {
; CHECK-LABEL: scvtf_bitcast_f64_to_f32:
; CHECK: // %bb.0:
-; CHECK-NEXT: fmov x8, d0
-; CHECK-NEXT: scvtf s0, x8
+; CHECK-NEXT: scvtf s0, d0
; CHECK-NEXT: ret
%i = bitcast double %d to i64
%r = sitofp i64 %i to float
@@ -59,8 +55,7 @@ define float @scvtf_bitcast_f64_to_f32(double %d) nounwind {
define float @ucvtf_bitcast_f64_to_f32(double %d) nounwind {
; CHECK-LABEL: ucvtf_bitcast_f64_to_f32:
; CHECK: // %bb.0:
-; CHECK-NEXT: fmov x8, d0
-; CHECK-NEXT: ucvtf s0, x8
+; CHECK-NEXT: ucvtf s0, d0
; CHECK-NEXT: ret
%i = bitcast double %d to i64
%r = uitofp i64 %i to float
@@ -70,8 +65,7 @@ define float @ucvtf_bitcast_f64_to_f32(double %d) nounwind {
define half @scvtf_bitcast_f64_to_f16(double %d) nounwind {
; CHECK-LABEL: scvtf_bitcast_f64_to_f16:
; CHECK: // %bb.0:
-; CHECK-NEXT: fmov x8, d0
-; CHECK-NEXT: scvtf h0, x8
+; CHECK-NEXT: scvtf h0, d0
; CHECK-NEXT: ret
%i = bitcast double %d to i64
%r = sitofp i64 %i to half
@@ -81,8 +75,7 @@ define half @scvtf_bitcast_f64_to_f16(double %d) nounwind {
define half @ucvtf_bitcast_f64_to_f16(double %d) nounwind {
; CHECK-LABEL: ucvtf_bitcast_f64_to_f16:
; CHECK: // %bb.0:
-; CHECK-NEXT: fmov x8, d0
-; CHECK-NEXT: ucvtf h0, x8
+; CHECK-NEXT: ucvtf h0, d0
; CHECK-NEXT: ret
%i = bitcast double %d to i64
%r = uitofp i64 %i to half
More information about the llvm-commits
mailing list