From 7c1cc937cb597e12b1ebd90a8e5db4ee950f47b3 Mon Sep 17 00:00:00 2001 From: Kieran Bailey Date: Thu, 16 Jul 2026 15:15:56 +0000 Subject: [PATCH 1/5] [AArch64][SelectionDAG] Avoid cross-bank copies for NEON vcvtfp2fx results - Add SelectionDAG-only patterns for NEON vcvtfp2fx so integer result select GPR instead of FPR, avoiding the need for cross-bank copies. - Bitcast uses still select the FP/SIMD-register forms where available. - Add complexity used to prioritize the new patterns over the generic FP/SIMD patterns which GlobalIsel still uses - Add testing for GPR-resulting and FPR-resulting patterns - Add missing tests in fp16_intrinsic_scalar_2op.ll: test_vcvth_n_u64_f16_1 and test_vcvth_n_u64_f16_16 A follow-up patch will also include the fix for GlobalIsel --- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 43 ++++ .../AArch64/fp16_intrinsic_scalar_2op.ll | 215 ++++++++++++++---- .../CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll | 78 +++++++ 3 files changed, 292 insertions(+), 44 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index a660a3f11bdb2..e1b11420cb74f 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -9138,6 +9138,49 @@ defm FCVTZS : SIMDFPScalarRShift<0, 0b11111, "fcvtzs">; defm FCVTZU : SIMDFPScalarRShift<1, 0b11111, "fcvtzu">; defm SCVTF : SIMDFPScalarRShift<0, 0b11100, "scvtf">; defm UCVTF : SIMDFPScalarRShift<1, 0b11100, "ucvtf">; + +// Transformation for SIMD shift imm to fixed point imm for FPR-to-GPR result +def fixedpoint_scalar_xform : SDNodeXForm; + +multiclass FPToFixedScalarPats { +// Allow integer result to remain in GPR registers +// SelectionDAG-only as GIsel doesn't import fixedpoint_scalar_xform +// Give priority over generic FPR fallback +let AddedComplexity = 1 in { + def : Pat<(i32 (OpN FPR32:$Rn, vecshiftR32:$imm)), + (!cast(INST # "SWSri") FPR32:$Rn, (fixedpoint_scalar_xform vecshiftR32:$imm))>; + def : Pat<(i64 (OpN (f64 FPR64:$Rn), vecshiftR64:$imm)), + (!cast(INST # "SXDri") FPR64:$Rn, (fixedpoint_scalar_xform vecshiftR64:$imm))>; + + def : Pat<(i32 (OpN (f16 FPR16:$Rn), vecshiftR32:$imm)), + (!cast(INST # "SWHri") FPR16:$Rn, (fixedpoint_scalar_xform vecshiftR32:$imm))>; + def : Pat<(i64 (OpN (f16 FPR16:$Rn), vecshiftR64:$imm)), + (!cast(INST # "SXHri") FPR16:$Rn, (fixedpoint_scalar_xform vecshiftR64:$imm))>; + } + + // Bitcast results kept in FP/SIMD registers. + def : Pat<(f32 (bitconvert(i32 (OpN FPR32:$Rn, vecshiftR32:$imm)))), + (!cast(INST # "s") FPR32:$Rn, vecshiftR32:$imm)>; + def : Pat<(f64 (bitconvert(i64 (OpN (f64 FPR64:$Rn), vecshiftR64:$imm)))), + (!cast(INST # "d") FPR64:$Rn, vecshiftR64:$imm)>; + + def : Pat<(f32(bitconvert (i32 (OpN (f16 FPR16:$Rn), vecshiftR32:$imm)))), + (f32 (INSERT_SUBREG + (f32 (IMPLICIT_DEF)), + (!cast(INST # "h") FPR16:$Rn, vecshiftR32:$imm), + hsub))>; + def : Pat<(f64 (bitconvert (i64 (OpN (f16 FPR16:$Rn), vecshiftR64:$imm)))), + (f64 (INSERT_SUBREG + (f64 (IMPLICIT_DEF)), + (!cast(INST # "h") FPR16:$Rn, vecshiftR64:$imm), + hsub))>; +} +defm : FPToFixedScalarPats; +defm : FPToFixedScalarPats; + // Codegen patterns for the above. We don't put these directly on the // instructions because TableGen's type inference can't handle the truth. // Having the same base pattern for fp <--> int totally freaks it out. diff --git a/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll b/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll index da70599483a63..f44e1a6fa9970 100644 --- a/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll +++ b/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll @@ -185,6 +185,7 @@ declare i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half, i32) #1 declare i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half, i32) #1 declare half @llvm.aarch64.neon.vcvtfxu2fp.f16.i32(i32, i32) #1 declare i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half, i32) #1 +declare i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half, i32) #1 define dso_local half @test_vcvth_n_f16_s16_1(i16 %a) { ; CHECK-SD-LABEL: test_vcvth_n_f16_s16_1: @@ -247,11 +248,16 @@ entry: } define dso_local i16 @test_vcvth_n_s16_f16_1(half %a) { -; CHECK-LABEL: test_vcvth_n_s16_f16_1: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzs h0, h0, #1 -; CHECK-NEXT: fmov w0, s0 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: test_vcvth_n_s16_f16_1: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzs w0, h0, #1 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_s16_f16_1: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzs h0, h0, #1 +; CHECK-GI-NEXT: fmov w0, s0 +; CHECK-GI-NEXT: ret entry: %fcvth_n = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 1) %0 = trunc i32 %fcvth_n to i16 @@ -259,11 +265,16 @@ entry: } define dso_local i16 @test_vcvth_n_s16_f16_16(half %a) { -; CHECK-LABEL: test_vcvth_n_s16_f16_16: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzs h0, h0, #16 -; CHECK-NEXT: fmov w0, s0 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: test_vcvth_n_s16_f16_16: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzs w0, h0, #16 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_s16_f16_16: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzs h0, h0, #16 +; CHECK-GI-NEXT: fmov w0, s0 +; CHECK-GI-NEXT: ret entry: %fcvth_n = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 16) %0 = trunc i32 %fcvth_n to i16 @@ -271,47 +282,89 @@ entry: } define dso_local i32 @test_vcvth_n_s32_f16_1(half %a) { -; CHECK-LABEL: test_vcvth_n_s32_f16_1: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzs h0, h0, #1 -; CHECK-NEXT: fmov w0, s0 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: test_vcvth_n_s32_f16_1: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzs w0, h0, #1 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_s32_f16_1: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzs h0, h0, #1 +; CHECK-GI-NEXT: fmov w0, s0 +; CHECK-GI-NEXT: ret entry: %vcvth_n_s32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 1) ret i32 %vcvth_n_s32_f16 } define dso_local i32 @test_vcvth_n_s32_f16_16(half %a) { -; CHECK-LABEL: test_vcvth_n_s32_f16_16: +; CHECK-SD-LABEL: test_vcvth_n_s32_f16_16: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzs w0, h0, #16 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_s32_f16_16: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzs h0, h0, #16 +; CHECK-GI-NEXT: fmov w0, s0 +; CHECK-GI-NEXT: ret +entry: + %vcvth_n_s32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 16) + ret i32 %vcvth_n_s32_f16 +} + +define dso_local float @test_vcvth_n_s32_f16_fpr(half %a) { +; CHECK-LABEL: test_vcvth_n_s32_f16_fpr: ; CHECK: // %bb.0: // %entry ; CHECK-NEXT: fcvtzs h0, h0, #16 -; CHECK-NEXT: fmov w0, s0 ; CHECK-NEXT: ret entry: %vcvth_n_s32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 16) - ret i32 %vcvth_n_s32_f16 + %bc = bitcast i32 %vcvth_n_s32_f16 to float + ret float %bc } define dso_local i64 @test_vcvth_n_s64_f16_1(half %a) { -; CHECK-LABEL: test_vcvth_n_s64_f16_1: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzs h0, h0, #1 -; CHECK-NEXT: fmov x0, d0 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: test_vcvth_n_s64_f16_1: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzs x0, h0, #1 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_s64_f16_1: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzs h0, h0, #1 +; CHECK-GI-NEXT: fmov x0, d0 +; CHECK-GI-NEXT: ret entry: %vcvth_n_s64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half %a, i32 1) ret i64 %vcvth_n_s64_f16 } define dso_local i64 @test_vcvth_n_s64_f16_32(half %a) { -; CHECK-LABEL: test_vcvth_n_s64_f16_32: +; CHECK-SD-LABEL: test_vcvth_n_s64_f16_32: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzs x0, h0, #32 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_s64_f16_32: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzs h0, h0, #32 +; CHECK-GI-NEXT: fmov x0, d0 +; CHECK-GI-NEXT: ret +entry: + %vcvth_n_s64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half %a, i32 32) + ret i64 %vcvth_n_s64_f16 +} + +define dso_local double @test_vcvth_n_s64_f16_fpr(half %a) { +; CHECK-LABEL: test_vcvth_n_s64_f16_fpr: ; CHECK: // %bb.0: // %entry ; CHECK-NEXT: fcvtzs h0, h0, #32 -; CHECK-NEXT: fmov x0, d0 ; CHECK-NEXT: ret entry: %vcvth_n_s64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half %a, i32 32) - ret i64 %vcvth_n_s64_f16 + %bc = bitcast i64 %vcvth_n_s64_f16 to double + ret double %bc } define dso_local half @test_vcvth_n_f16_u16_1(i16 %a) { @@ -375,11 +428,16 @@ entry: } define dso_local i16 @test_vcvth_n_u16_f16_1(half %a) { -; CHECK-LABEL: test_vcvth_n_u16_f16_1: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzu h0, h0, #1 -; CHECK-NEXT: fmov w0, s0 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: test_vcvth_n_u16_f16_1: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzu w0, h0, #1 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_u16_f16_1: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzu h0, h0, #1 +; CHECK-GI-NEXT: fmov w0, s0 +; CHECK-GI-NEXT: ret entry: %fcvth_n = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 1) %0 = trunc i32 %fcvth_n to i16 @@ -387,11 +445,16 @@ entry: } define dso_local i16 @test_vcvth_n_u16_f16_16(half %a) { -; CHECK-LABEL: test_vcvth_n_u16_f16_16: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzu h0, h0, #16 -; CHECK-NEXT: fmov w0, s0 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: test_vcvth_n_u16_f16_16: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzu w0, h0, #16 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_u16_f16_16: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzu h0, h0, #16 +; CHECK-GI-NEXT: fmov w0, s0 +; CHECK-GI-NEXT: ret entry: %fcvth_n = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 16) %0 = trunc i32 %fcvth_n to i16 @@ -399,25 +462,89 @@ entry: } define dso_local i32 @test_vcvth_n_u32_f16_1(half %a) { -; CHECK-LABEL: test_vcvth_n_u32_f16_1: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzu h0, h0, #1 -; CHECK-NEXT: fmov w0, s0 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: test_vcvth_n_u32_f16_1: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzu w0, h0, #1 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_u32_f16_1: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzu h0, h0, #1 +; CHECK-GI-NEXT: fmov w0, s0 +; CHECK-GI-NEXT: ret entry: %vcvth_n_u32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 1) ret i32 %vcvth_n_u32_f16 } define dso_local i32 @test_vcvth_n_u32_f16_16(half %a) { -; CHECK-LABEL: test_vcvth_n_u32_f16_16: +; CHECK-SD-LABEL: test_vcvth_n_u32_f16_16: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzu w0, h0, #16 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_u32_f16_16: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzu h0, h0, #16 +; CHECK-GI-NEXT: fmov w0, s0 +; CHECK-GI-NEXT: ret +entry: + %vcvth_n_u32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 16) + ret i32 %vcvth_n_u32_f16 +} + +define dso_local float @test_vcvth_n_u32_f16_fpr(half %a) { +; CHECK-LABEL: test_vcvth_n_u32_f16_fpr: ; CHECK: // %bb.0: // %entry ; CHECK-NEXT: fcvtzu h0, h0, #16 -; CHECK-NEXT: fmov w0, s0 ; CHECK-NEXT: ret entry: %vcvth_n_u32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 16) - ret i32 %vcvth_n_u32_f16 + %bc = bitcast i32 %vcvth_n_u32_f16 to float + ret float %bc +} + +define dso_local i64 @test_vcvth_n_u64_f16_1(half %a) { +; CHECK-SD-LABEL: test_vcvth_n_u64_f16_1: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzu x0, h0, #1 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_u64_f16_1: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzu h0, h0, #1 +; CHECK-GI-NEXT: fmov x0, d0 +; CHECK-GI-NEXT: ret +entry: + %vcvth_n_u64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 1) + ret i64 %vcvth_n_u64_f16 +} + +define dso_local i64 @test_vcvth_n_u64_f16_16(half %a) { +; CHECK-SD-LABEL: test_vcvth_n_u64_f16_16: +; CHECK-SD: // %bb.0: // %entry +; CHECK-SD-NEXT: fcvtzu x0, h0, #16 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: test_vcvth_n_u64_f16_16: +; CHECK-GI: // %bb.0: // %entry +; CHECK-GI-NEXT: fcvtzu h0, h0, #16 +; CHECK-GI-NEXT: fmov x0, d0 +; CHECK-GI-NEXT: ret +entry: + %vcvth_n_u64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 16) + ret i64 %vcvth_n_u64_f16 +} + +define dso_local double @test_vcvth_n_u64_f16_fpr(half %a) { +; CHECK-LABEL: test_vcvth_n_u64_f16_fpr: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzu h0, h0, #16 +; CHECK-NEXT: ret +entry: + %vcvth_n_u64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 16) + %bc = bitcast i64 %vcvth_n_u64_f16 to double + ret double %bc } define dso_local i16 @vcageh_f16_test(half %a, half %b) { diff --git a/llvm/test/CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll b/llvm/test/CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll new file mode 100644 index 0000000000000..5ca1d8c44cf58 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll @@ -0,0 +1,78 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc -mtriple=aarch64 -global-isel=0 < %s | FileCheck %s + +define i32 @vcvtfp2fxs_f32_i32(float %a) { +; CHECK-LABEL: vcvtfp2fxs_f32_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs w0, s0, #16 +; CHECK-NEXT: ret + %r = call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f32(float %a, i32 16) + ret i32 %r +} + +define float @vcvtfp2fxs_f32_i32_bitcast(float %a) { +; CHECK-LABEL: vcvtfp2fxs_f32_i32_bitcast: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs s0, s0, #16 +; CHECK-NEXT: ret + %r = call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f32(float %a, i32 16) + %b = bitcast i32 %r to float + ret float %b +} + +define i32 @vcvtfp2fxu_f32_i32(float %a) { +; CHECK-LABEL: vcvtfp2fxu_f32_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzu w0, s0, #16 +; CHECK-NEXT: ret + %r = call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f32(float %a, i32 16) + ret i32 %r +} + +define float @vcvtfp2fxu_f32_i32_bitcast(float %a) { +; CHECK-LABEL: vcvtfp2fxu_f32_i32_bitcast: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzu s0, s0, #16 +; CHECK-NEXT: ret + %r = call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f32(float %a, i32 16) + %b = bitcast i32 %r to float + ret float %b +} + +define i64 @vcvtfp2fxs_f64_i64(double %a) { +; CHECK-LABEL: vcvtfp2fxs_f64_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs x0, d0, #16 +; CHECK-NEXT: ret + %r = call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f64(double %a, i32 16) + ret i64 %r +} + +define double @vcvtfp2fxs_f64_i64_bitcast(double %a) { +; CHECK-LABEL: vcvtfp2fxs_f64_i64_bitcast: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs d0, d0, #16 +; CHECK-NEXT: ret + %r = call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f64(double %a, i32 16) + %b = bitcast i64 %r to double + ret double %b +} + +define i64 @vcvtfp2fxu_f64_i64(double %a) { +; CHECK-LABEL: vcvtfp2fxu_f64_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzu x0, d0, #16 +; CHECK-NEXT: ret + %r = call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f64(double %a, i32 16) + ret i64 %r +} + +define double @vcvtfp2fxu_f64_i64_bitcast(double %a) { +; CHECK-LABEL: vcvtfp2fxu_f64_i64_bitcast: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzu d0, d0, #16 +; CHECK-NEXT: ret + %r = call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f64(double %a, i32 16) + %b = bitcast i64 %r to double + ret double %b +} From bf9501ee710f5a504eb9a595577a00cbdcb8476b Mon Sep 17 00:00:00 2001 From: Kieran Bailey Date: Mon, 20 Jul 2026 13:54:46 +0000 Subject: [PATCH 2/5] Addressing Review Comments - Moved the existing FPR fallbacks into the multiclass - Removed unnecessary AddedComplexity - Restructured comments based on review suggestions --- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 64 +++++++-------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index e1b11420cb74f..4f975385da8d4 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -9146,27 +9146,21 @@ def fixedpoint_scalar_xform : SDNodeXForm; multiclass FPToFixedScalarPats { -// Allow integer result to remain in GPR registers -// SelectionDAG-only as GIsel doesn't import fixedpoint_scalar_xform -// Give priority over generic FPR fallback -let AddedComplexity = 1 in { + // Allow integer result to remain in GPR register def : Pat<(i32 (OpN FPR32:$Rn, vecshiftR32:$imm)), (!cast(INST # "SWSri") FPR32:$Rn, (fixedpoint_scalar_xform vecshiftR32:$imm))>; def : Pat<(i64 (OpN (f64 FPR64:$Rn), vecshiftR64:$imm)), (!cast(INST # "SXDri") FPR64:$Rn, (fixedpoint_scalar_xform vecshiftR64:$imm))>; - def : Pat<(i32 (OpN (f16 FPR16:$Rn), vecshiftR32:$imm)), (!cast(INST # "SWHri") FPR16:$Rn, (fixedpoint_scalar_xform vecshiftR32:$imm))>; def : Pat<(i64 (OpN (f16 FPR16:$Rn), vecshiftR64:$imm)), (!cast(INST # "SXHri") FPR16:$Rn, (fixedpoint_scalar_xform vecshiftR64:$imm))>; - } - // Bitcast results kept in FP/SIMD registers. + // Explicit Bitcast results kept in FP/SIMD registers. def : Pat<(f32 (bitconvert(i32 (OpN FPR32:$Rn, vecshiftR32:$imm)))), (!cast(INST # "s") FPR32:$Rn, vecshiftR32:$imm)>; def : Pat<(f64 (bitconvert(i64 (OpN (f64 FPR64:$Rn), vecshiftR64:$imm)))), (!cast(INST # "d") FPR64:$Rn, vecshiftR64:$imm)>; - def : Pat<(f32(bitconvert (i32 (OpN (f16 FPR16:$Rn), vecshiftR32:$imm)))), (f32 (INSERT_SUBREG (f32 (IMPLICIT_DEF)), @@ -9177,27 +9171,31 @@ let AddedComplexity = 1 in { (f64 (IMPLICIT_DEF)), (!cast(INST # "h") FPR16:$Rn, vecshiftR64:$imm), hsub))>; + + // FPR fallback patterns + def : Pat<(i32 (OpN FPR32:$Rn, vecshiftR32:$imm)), + (!cast(INST # "s") FPR32:$Rn, vecshiftR32:$imm)>; + def : Pat<(i64 (OpN (f64 FPR64:$Rn), vecshiftR64:$imm)), + (!cast(INST # "d") FPR64:$Rn, vecshiftR64:$imm)>; + def : Pat<(v1i64 (OpN (v1f64 FPR64:$Rn), vecshiftR64:$imm)), + (!cast(INST # "d") FPR64:$Rn, vecshiftR64:$imm)>; + def : Pat<(i32 (OpN (f16 FPR16:$Rn), vecshiftR32:$imm)), + (i32 (INSERT_SUBREG + (i32 (IMPLICIT_DEF)), + (!cast(INST # "h") FPR16:$Rn, vecshiftR32:$imm), + hsub))>; + def : Pat<(i64 (OpN (f16 FPR16:$Rn), vecshiftR64:$imm)), + (i64 (INSERT_SUBREG + (i64 (IMPLICIT_DEF)), + (!cast(INST # "h") FPR16:$Rn, vecshiftR64:$imm), + hsub))>; } defm : FPToFixedScalarPats; defm : FPToFixedScalarPats; -// Codegen patterns for the above. We don't put these directly on the +// Codegen patterns for SCVTF and UCVTF. We don't put these directly on the // instructions because TableGen's type inference can't handle the truth. // Having the same base pattern for fp <--> int totally freaks it out. -def : Pat<(int_aarch64_neon_vcvtfp2fxs FPR32:$Rn, vecshiftR32:$imm), - (FCVTZSs FPR32:$Rn, vecshiftR32:$imm)>; -def : Pat<(int_aarch64_neon_vcvtfp2fxu FPR32:$Rn, vecshiftR32:$imm), - (FCVTZUs FPR32:$Rn, vecshiftR32:$imm)>; -def : Pat<(i64 (int_aarch64_neon_vcvtfp2fxs (f64 FPR64:$Rn), vecshiftR64:$imm)), - (FCVTZSd FPR64:$Rn, vecshiftR64:$imm)>; -def : Pat<(i64 (int_aarch64_neon_vcvtfp2fxu (f64 FPR64:$Rn), vecshiftR64:$imm)), - (FCVTZUd FPR64:$Rn, vecshiftR64:$imm)>; -def : Pat<(v1i64 (int_aarch64_neon_vcvtfp2fxs (v1f64 FPR64:$Rn), - vecshiftR64:$imm)), - (FCVTZSd FPR64:$Rn, vecshiftR64:$imm)>; -def : Pat<(v1i64 (int_aarch64_neon_vcvtfp2fxu (v1f64 FPR64:$Rn), - vecshiftR64:$imm)), - (FCVTZUd FPR64:$Rn, vecshiftR64:$imm)>; def : Pat<(int_aarch64_neon_vcvtfxu2fp FPR32:$Rn, vecshiftR32:$imm), (UCVTFs FPR32:$Rn, vecshiftR32:$imm)>; def : Pat<(f64 (int_aarch64_neon_vcvtfxu2fp (i64 FPR64:$Rn), vecshiftR64:$imm)), @@ -9229,26 +9227,6 @@ def : Pat<(f16 (int_aarch64_neon_vcvtfxu2fp FPR32:$Rn, vecshiftR16:$imm)), (UCVTFh (f16 (EXTRACT_SUBREG FPR32:$Rn, hsub)), vecshiftR16:$imm)>; def : Pat<(f16 (int_aarch64_neon_vcvtfxu2fp (i64 FPR64:$Rn), vecshiftR16:$imm)), (UCVTFh (f16 (EXTRACT_SUBREG FPR64:$Rn, hsub)), vecshiftR16:$imm)>; -def : Pat<(i32 (int_aarch64_neon_vcvtfp2fxs (f16 FPR16:$Rn), vecshiftR32:$imm)), - (i32 (INSERT_SUBREG - (i32 (IMPLICIT_DEF)), - (FCVTZSh FPR16:$Rn, vecshiftR32:$imm), - hsub))>; -def : Pat<(i64 (int_aarch64_neon_vcvtfp2fxs (f16 FPR16:$Rn), vecshiftR64:$imm)), - (i64 (INSERT_SUBREG - (i64 (IMPLICIT_DEF)), - (FCVTZSh FPR16:$Rn, vecshiftR64:$imm), - hsub))>; -def : Pat<(i32 (int_aarch64_neon_vcvtfp2fxu (f16 FPR16:$Rn), vecshiftR32:$imm)), - (i32 (INSERT_SUBREG - (i32 (IMPLICIT_DEF)), - (FCVTZUh FPR16:$Rn, vecshiftR32:$imm), - hsub))>; -def : Pat<(i64 (int_aarch64_neon_vcvtfp2fxu (f16 FPR16:$Rn), vecshiftR64:$imm)), - (i64 (INSERT_SUBREG - (i64 (IMPLICIT_DEF)), - (FCVTZUh FPR16:$Rn, vecshiftR64:$imm), - hsub))>; def : Pat<(i32 (int_aarch64_neon_facge (f16 FPR16:$Rn), (f16 FPR16:$Rm))), (i32 (INSERT_SUBREG (i32 (IMPLICIT_DEF)), From e36b3814086742b5e5c16023c9a3a9b6733f26f4 Mon Sep 17 00:00:00 2001 From: Kieran Bailey Date: Mon, 27 Jul 2026 13:52:56 +0000 Subject: [PATCH 3/5] Remove f16 GPR result conversions. - Acle requires f16 conversions to lower to Hd register - Remove f16 GPR conversion patterns for vcvth_n - Remove the bitconvert test cases for f16 --- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 20 +- .../AArch64/fp16_intrinsic_scalar_2op.ll | 208 +++++------------- 2 files changed, 55 insertions(+), 173 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 4f975385da8d4..2f36cf2ad5494 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -9139,40 +9139,26 @@ defm FCVTZU : SIMDFPScalarRShift<1, 0b11111, "fcvtzu">; defm SCVTF : SIMDFPScalarRShift<0, 0b11100, "scvtf">; defm UCVTF : SIMDFPScalarRShift<1, 0b11100, "ucvtf">; -// Transformation for SIMD shift imm to fixed point imm for FPR-to-GPR result +// Transformation for SIMD shift imm to fixed point imm for FPR-to-GPR result. def fixedpoint_scalar_xform : SDNodeXForm; multiclass FPToFixedScalarPats { - // Allow integer result to remain in GPR register + // Allow integer result to remain in GPR register. def : Pat<(i32 (OpN FPR32:$Rn, vecshiftR32:$imm)), (!cast(INST # "SWSri") FPR32:$Rn, (fixedpoint_scalar_xform vecshiftR32:$imm))>; def : Pat<(i64 (OpN (f64 FPR64:$Rn), vecshiftR64:$imm)), (!cast(INST # "SXDri") FPR64:$Rn, (fixedpoint_scalar_xform vecshiftR64:$imm))>; - def : Pat<(i32 (OpN (f16 FPR16:$Rn), vecshiftR32:$imm)), - (!cast(INST # "SWHri") FPR16:$Rn, (fixedpoint_scalar_xform vecshiftR32:$imm))>; - def : Pat<(i64 (OpN (f16 FPR16:$Rn), vecshiftR64:$imm)), - (!cast(INST # "SXHri") FPR16:$Rn, (fixedpoint_scalar_xform vecshiftR64:$imm))>; // Explicit Bitcast results kept in FP/SIMD registers. def : Pat<(f32 (bitconvert(i32 (OpN FPR32:$Rn, vecshiftR32:$imm)))), (!cast(INST # "s") FPR32:$Rn, vecshiftR32:$imm)>; def : Pat<(f64 (bitconvert(i64 (OpN (f64 FPR64:$Rn), vecshiftR64:$imm)))), (!cast(INST # "d") FPR64:$Rn, vecshiftR64:$imm)>; - def : Pat<(f32(bitconvert (i32 (OpN (f16 FPR16:$Rn), vecshiftR32:$imm)))), - (f32 (INSERT_SUBREG - (f32 (IMPLICIT_DEF)), - (!cast(INST # "h") FPR16:$Rn, vecshiftR32:$imm), - hsub))>; - def : Pat<(f64 (bitconvert (i64 (OpN (f16 FPR16:$Rn), vecshiftR64:$imm)))), - (f64 (INSERT_SUBREG - (f64 (IMPLICIT_DEF)), - (!cast(INST # "h") FPR16:$Rn, vecshiftR64:$imm), - hsub))>; - // FPR fallback patterns + // FPR fallback patterns. def : Pat<(i32 (OpN FPR32:$Rn, vecshiftR32:$imm)), (!cast(INST # "s") FPR32:$Rn, vecshiftR32:$imm)>; def : Pat<(i64 (OpN (f64 FPR64:$Rn), vecshiftR64:$imm)), diff --git a/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll b/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll index f44e1a6fa9970..af898c5f1d312 100644 --- a/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll +++ b/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll @@ -248,16 +248,11 @@ entry: } define dso_local i16 @test_vcvth_n_s16_f16_1(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_s16_f16_1: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzs w0, h0, #1 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_s16_f16_1: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzs h0, h0, #1 -; CHECK-GI-NEXT: fmov w0, s0 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: test_vcvth_n_s16_f16_1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzs h0, h0, #1 +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: ret entry: %fcvth_n = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 1) %0 = trunc i32 %fcvth_n to i16 @@ -265,16 +260,11 @@ entry: } define dso_local i16 @test_vcvth_n_s16_f16_16(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_s16_f16_16: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzs w0, h0, #16 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_s16_f16_16: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzs h0, h0, #16 -; CHECK-GI-NEXT: fmov w0, s0 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: test_vcvth_n_s16_f16_16: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzs h0, h0, #16 +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: ret entry: %fcvth_n = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 16) %0 = trunc i32 %fcvth_n to i16 @@ -282,89 +272,47 @@ entry: } define dso_local i32 @test_vcvth_n_s32_f16_1(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_s32_f16_1: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzs w0, h0, #1 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_s32_f16_1: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzs h0, h0, #1 -; CHECK-GI-NEXT: fmov w0, s0 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: test_vcvth_n_s32_f16_1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzs h0, h0, #1 +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: ret entry: %vcvth_n_s32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 1) ret i32 %vcvth_n_s32_f16 } define dso_local i32 @test_vcvth_n_s32_f16_16(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_s32_f16_16: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzs w0, h0, #16 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_s32_f16_16: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzs h0, h0, #16 -; CHECK-GI-NEXT: fmov w0, s0 -; CHECK-GI-NEXT: ret -entry: - %vcvth_n_s32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 16) - ret i32 %vcvth_n_s32_f16 -} - -define dso_local float @test_vcvth_n_s32_f16_fpr(half %a) { -; CHECK-LABEL: test_vcvth_n_s32_f16_fpr: +; CHECK-LABEL: test_vcvth_n_s32_f16_16: ; CHECK: // %bb.0: // %entry ; CHECK-NEXT: fcvtzs h0, h0, #16 +; CHECK-NEXT: fmov w0, s0 ; CHECK-NEXT: ret entry: %vcvth_n_s32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half %a, i32 16) - %bc = bitcast i32 %vcvth_n_s32_f16 to float - ret float %bc + ret i32 %vcvth_n_s32_f16 } define dso_local i64 @test_vcvth_n_s64_f16_1(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_s64_f16_1: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzs x0, h0, #1 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_s64_f16_1: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzs h0, h0, #1 -; CHECK-GI-NEXT: fmov x0, d0 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: test_vcvth_n_s64_f16_1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzs h0, h0, #1 +; CHECK-NEXT: fmov x0, d0 +; CHECK-NEXT: ret entry: %vcvth_n_s64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half %a, i32 1) ret i64 %vcvth_n_s64_f16 } define dso_local i64 @test_vcvth_n_s64_f16_32(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_s64_f16_32: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzs x0, h0, #32 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_s64_f16_32: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzs h0, h0, #32 -; CHECK-GI-NEXT: fmov x0, d0 -; CHECK-GI-NEXT: ret -entry: - %vcvth_n_s64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half %a, i32 32) - ret i64 %vcvth_n_s64_f16 -} - -define dso_local double @test_vcvth_n_s64_f16_fpr(half %a) { -; CHECK-LABEL: test_vcvth_n_s64_f16_fpr: +; CHECK-LABEL: test_vcvth_n_s64_f16_32: ; CHECK: // %bb.0: // %entry ; CHECK-NEXT: fcvtzs h0, h0, #32 +; CHECK-NEXT: fmov x0, d0 ; CHECK-NEXT: ret entry: %vcvth_n_s64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half %a, i32 32) - %bc = bitcast i64 %vcvth_n_s64_f16 to double - ret double %bc + ret i64 %vcvth_n_s64_f16 } define dso_local half @test_vcvth_n_f16_u16_1(i16 %a) { @@ -428,16 +376,11 @@ entry: } define dso_local i16 @test_vcvth_n_u16_f16_1(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_u16_f16_1: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzu w0, h0, #1 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_u16_f16_1: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzu h0, h0, #1 -; CHECK-GI-NEXT: fmov w0, s0 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: test_vcvth_n_u16_f16_1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzu h0, h0, #1 +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: ret entry: %fcvth_n = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 1) %0 = trunc i32 %fcvth_n to i16 @@ -445,16 +388,11 @@ entry: } define dso_local i16 @test_vcvth_n_u16_f16_16(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_u16_f16_16: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzu w0, h0, #16 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_u16_f16_16: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzu h0, h0, #16 -; CHECK-GI-NEXT: fmov w0, s0 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: test_vcvth_n_u16_f16_16: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzu h0, h0, #16 +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: ret entry: %fcvth_n = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 16) %0 = trunc i32 %fcvth_n to i16 @@ -462,89 +400,47 @@ entry: } define dso_local i32 @test_vcvth_n_u32_f16_1(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_u32_f16_1: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzu w0, h0, #1 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_u32_f16_1: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzu h0, h0, #1 -; CHECK-GI-NEXT: fmov w0, s0 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: test_vcvth_n_u32_f16_1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzu h0, h0, #1 +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: ret entry: %vcvth_n_u32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 1) ret i32 %vcvth_n_u32_f16 } define dso_local i32 @test_vcvth_n_u32_f16_16(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_u32_f16_16: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzu w0, h0, #16 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_u32_f16_16: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzu h0, h0, #16 -; CHECK-GI-NEXT: fmov w0, s0 -; CHECK-GI-NEXT: ret -entry: - %vcvth_n_u32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 16) - ret i32 %vcvth_n_u32_f16 -} - -define dso_local float @test_vcvth_n_u32_f16_fpr(half %a) { -; CHECK-LABEL: test_vcvth_n_u32_f16_fpr: +; CHECK-LABEL: test_vcvth_n_u32_f16_16: ; CHECK: // %bb.0: // %entry ; CHECK-NEXT: fcvtzu h0, h0, #16 +; CHECK-NEXT: fmov w0, s0 ; CHECK-NEXT: ret entry: %vcvth_n_u32_f16 = tail call i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half %a, i32 16) - %bc = bitcast i32 %vcvth_n_u32_f16 to float - ret float %bc + ret i32 %vcvth_n_u32_f16 } define dso_local i64 @test_vcvth_n_u64_f16_1(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_u64_f16_1: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzu x0, h0, #1 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_u64_f16_1: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzu h0, h0, #1 -; CHECK-GI-NEXT: fmov x0, d0 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: test_vcvth_n_u64_f16_1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: fcvtzu h0, h0, #1 +; CHECK-NEXT: fmov x0, d0 +; CHECK-NEXT: ret entry: %vcvth_n_u64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 1) ret i64 %vcvth_n_u64_f16 } define dso_local i64 @test_vcvth_n_u64_f16_16(half %a) { -; CHECK-SD-LABEL: test_vcvth_n_u64_f16_16: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: fcvtzu x0, h0, #16 -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: test_vcvth_n_u64_f16_16: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: fcvtzu h0, h0, #16 -; CHECK-GI-NEXT: fmov x0, d0 -; CHECK-GI-NEXT: ret -entry: - %vcvth_n_u64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 16) - ret i64 %vcvth_n_u64_f16 -} - -define dso_local double @test_vcvth_n_u64_f16_fpr(half %a) { -; CHECK-LABEL: test_vcvth_n_u64_f16_fpr: +; CHECK-LABEL: test_vcvth_n_u64_f16_16: ; CHECK: // %bb.0: // %entry ; CHECK-NEXT: fcvtzu h0, h0, #16 +; CHECK-NEXT: fmov x0, d0 ; CHECK-NEXT: ret entry: %vcvth_n_u64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 16) - %bc = bitcast i64 %vcvth_n_u64_f16 to double - ret double %bc + ret i64 %vcvth_n_u64_f16 } define dso_local i16 @vcageh_f16_test(half %a, half %b) { From 2437f37c2745254f12df5b8dc52be0b621d34e67 Mon Sep 17 00:00:00 2001 From: Kieran Bailey Date: Tue, 28 Jul 2026 15:31:26 +0000 Subject: [PATCH 4/5] Removed fp16 missing unsigned test case I will remove the missing test cases for u64_f16 as they will be added when the f16 patterns are fixed and are unrelated to my patch. --- .../AArch64/fp16_intrinsic_scalar_2op.ll | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll b/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll index af898c5f1d312..da70599483a63 100644 --- a/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll +++ b/llvm/test/CodeGen/AArch64/fp16_intrinsic_scalar_2op.ll @@ -185,7 +185,6 @@ declare i32 @llvm.aarch64.neon.vcvtfp2fxs.i32.f16(half, i32) #1 declare i64 @llvm.aarch64.neon.vcvtfp2fxs.i64.f16(half, i32) #1 declare half @llvm.aarch64.neon.vcvtfxu2fp.f16.i32(i32, i32) #1 declare i32 @llvm.aarch64.neon.vcvtfp2fxu.i32.f16(half, i32) #1 -declare i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half, i32) #1 define dso_local half @test_vcvth_n_f16_s16_1(i16 %a) { ; CHECK-SD-LABEL: test_vcvth_n_f16_s16_1: @@ -421,28 +420,6 @@ entry: ret i32 %vcvth_n_u32_f16 } -define dso_local i64 @test_vcvth_n_u64_f16_1(half %a) { -; CHECK-LABEL: test_vcvth_n_u64_f16_1: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzu h0, h0, #1 -; CHECK-NEXT: fmov x0, d0 -; CHECK-NEXT: ret -entry: - %vcvth_n_u64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 1) - ret i64 %vcvth_n_u64_f16 -} - -define dso_local i64 @test_vcvth_n_u64_f16_16(half %a) { -; CHECK-LABEL: test_vcvth_n_u64_f16_16: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: fcvtzu h0, h0, #16 -; CHECK-NEXT: fmov x0, d0 -; CHECK-NEXT: ret -entry: - %vcvth_n_u64_f16 = tail call i64 @llvm.aarch64.neon.vcvtfp2fxu.i64.f16(half %a, i32 16) - ret i64 %vcvth_n_u64_f16 -} - define dso_local i16 @vcageh_f16_test(half %a, half %b) { ; CHECK-LABEL: vcageh_f16_test: ; CHECK: // %bb.0: // %entry From 254741717f07707b6fddc031b668aef49584395e Mon Sep 17 00:00:00 2001 From: Kieran Bailey Date: Wed, 29 Jul 2026 14:23:13 +0000 Subject: [PATCH 5/5] [AArch64][SelectionDAG] Avoid cross-bank copies for NEON vcvtfp2fx results Updated the types in test names to be correct order for llvm standard --- .../CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/llvm/test/CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll b/llvm/test/CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll index 5ca1d8c44cf58..219a2950aa35d 100644 --- a/llvm/test/CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll +++ b/llvm/test/CodeGen/AArch64/neon-scalar-vcvtfp2fx.ll @@ -1,8 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 ; RUN: llc -mtriple=aarch64 -global-isel=0 < %s | FileCheck %s -define i32 @vcvtfp2fxs_f32_i32(float %a) { -; CHECK-LABEL: vcvtfp2fxs_f32_i32: +define i32 @vcvtfp2fxs_i32_f32(float %a) { +; CHECK-LABEL: vcvtfp2fxs_i32_f32: ; CHECK: // %bb.0: ; CHECK-NEXT: fcvtzs w0, s0, #16 ; CHECK-NEXT: ret @@ -10,8 +10,8 @@ define i32 @vcvtfp2fxs_f32_i32(float %a) { ret i32 %r } -define float @vcvtfp2fxs_f32_i32_bitcast(float %a) { -; CHECK-LABEL: vcvtfp2fxs_f32_i32_bitcast: +define float @vcvtfp2fxs_i32_f32_bitcast(float %a) { +; CHECK-LABEL: vcvtfp2fxs_i32_f32_bitcast: ; CHECK: // %bb.0: ; CHECK-NEXT: fcvtzs s0, s0, #16 ; CHECK-NEXT: ret @@ -20,8 +20,8 @@ define float @vcvtfp2fxs_f32_i32_bitcast(float %a) { ret float %b } -define i32 @vcvtfp2fxu_f32_i32(float %a) { -; CHECK-LABEL: vcvtfp2fxu_f32_i32: +define i32 @vcvtfp2fxu_i32_f32(float %a) { +; CHECK-LABEL: vcvtfp2fxu_i32_f32: ; CHECK: // %bb.0: ; CHECK-NEXT: fcvtzu w0, s0, #16 ; CHECK-NEXT: ret @@ -29,8 +29,8 @@ define i32 @vcvtfp2fxu_f32_i32(float %a) { ret i32 %r } -define float @vcvtfp2fxu_f32_i32_bitcast(float %a) { -; CHECK-LABEL: vcvtfp2fxu_f32_i32_bitcast: +define float @vcvtfp2fxu_i32_f32_bitcast(float %a) { +; CHECK-LABEL: vcvtfp2fxu_i32_f32_bitcast: ; CHECK: // %bb.0: ; CHECK-NEXT: fcvtzu s0, s0, #16 ; CHECK-NEXT: ret @@ -39,8 +39,8 @@ define float @vcvtfp2fxu_f32_i32_bitcast(float %a) { ret float %b } -define i64 @vcvtfp2fxs_f64_i64(double %a) { -; CHECK-LABEL: vcvtfp2fxs_f64_i64: +define i64 @vcvtfp2fxs_i64_f64(double %a) { +; CHECK-LABEL: vcvtfp2fxs_i64_f64: ; CHECK: // %bb.0: ; CHECK-NEXT: fcvtzs x0, d0, #16 ; CHECK-NEXT: ret @@ -48,8 +48,8 @@ define i64 @vcvtfp2fxs_f64_i64(double %a) { ret i64 %r } -define double @vcvtfp2fxs_f64_i64_bitcast(double %a) { -; CHECK-LABEL: vcvtfp2fxs_f64_i64_bitcast: +define double @vcvtfp2fxs_i64_f64_bitcast(double %a) { +; CHECK-LABEL: vcvtfp2fxs_i64_f64_bitcast: ; CHECK: // %bb.0: ; CHECK-NEXT: fcvtzs d0, d0, #16 ; CHECK-NEXT: ret @@ -58,8 +58,8 @@ define double @vcvtfp2fxs_f64_i64_bitcast(double %a) { ret double %b } -define i64 @vcvtfp2fxu_f64_i64(double %a) { -; CHECK-LABEL: vcvtfp2fxu_f64_i64: +define i64 @vcvtfp2fxu_i64_f64(double %a) { +; CHECK-LABEL: vcvtfp2fxu_i64_f64: ; CHECK: // %bb.0: ; CHECK-NEXT: fcvtzu x0, d0, #16 ; CHECK-NEXT: ret @@ -67,8 +67,8 @@ define i64 @vcvtfp2fxu_f64_i64(double %a) { ret i64 %r } -define double @vcvtfp2fxu_f64_i64_bitcast(double %a) { -; CHECK-LABEL: vcvtfp2fxu_f64_i64_bitcast: +define double @vcvtfp2fxu_i64_f64_bitcast(double %a) { +; CHECK-LABEL: vcvtfp2fxu_i64_f64_bitcast: ; CHECK: // %bb.0: ; CHECK-NEXT: fcvtzu d0, d0, #16 ; CHECK-NEXT: ret