[llvm] [AArch64][SelectionDAG] Fold fp_to_int(fmul) for FPR results (PR #210987)

Kieran B via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 28 07:08:46 PDT 2026


https://github.com/kieroxide updated https://github.com/llvm/llvm-project/pull/210987

>From 1df87cf8f3d1cb29f9c1d705e92a5064e09912d0 Mon Sep 17 00:00:00 2001
From: Kieran Bailey <kieran.bailey at arm.com>
Date: Tue, 21 Jul 2026 12:58:58 +0000
Subject: [PATCH 1/3] [AArch64][SelectionDAG] Fold fp_to_int(fmul) for FPR
 results

- Add FmulToFPToIntFPRPats FCVTZ fmul folds (F32 and F64) for any_fp_to_int, fp_to_int_sat, neon_fcvtz.
- Add FPR-result test coverage for fp_to_int and fp_to_int_sat to existing fcvt-fixed.ll
- Create new test file neon-fcvt-fixed.ll for neon.fcvtz testing

A follow up patch will include the fix for GlobalIsel
---
 llvm/lib/Target/AArch64/AArch64InstrInfo.td  |  31 ++-
 llvm/test/CodeGen/AArch64/fcvt-fixed.ll      | 244 +++++++++++++++----
 llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll | 148 +++++++++++
 3 files changed, 374 insertions(+), 49 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll

diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 51fb2e1d1f9f0..43cd4e6466524 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -9251,7 +9251,9 @@ class fixedpoint_vec_f32<ValueType FloatVT>
     : ComplexPattern<FloatVT, 1, "SelectCVTFixedPointVec<32>">;
 class fixedpoint_vec_f16<ValueType FloatVT>
     : ComplexPattern<FloatVT, 1, "SelectCVTFixedPointVec<16>">;
-// This thing just allows us to change the type of the node produced. The imm
+    
+// Shared by scalar and vector fixed-point FCVT patterns. 
+// Allows transformation of fixedpoint -> vecshift. The imm
 // value we want is already in V from SelectCVTFixedPointVec.
 def fixedpoint_vec_xform : SDNodeXForm<timm, [{
   (void)N;
@@ -9293,6 +9295,33 @@ def : Pat<(v8f16 (sint_to_fp (v8i16 (AArch64vashr_exact v8i16:$Vn, i32:$shift)))
           (SCVTFv8i16_shift $Vn, vecshiftR16:$shift)>;
 }
 
+// Fmul fold + FP_to_int conversions bitcast kept in SIMD/FP register
+multiclass FmulToFPToIntFPRPats<SDPatternOperator OpN, string INST> {
+  def : Pat<(f32 (bitconvert (i32 (OpN (fmul FPR32:$Rn, fixedpoint_f32_i32:$scale))))),
+      (!cast<Instruction>(INST # "s") FPR32:$Rn, (fixedpoint_vec_xform fixedpoint_f32_i32:$scale))>;
+  def : Pat<(f64 (bitconvert (i64 (OpN (fmul FPR64:$Rn, fixedpoint_f64_i64:$scale))))),
+      (!cast<Instruction>(INST # "d") FPR64:$Rn, (fixedpoint_vec_xform fixedpoint_f64_i64:$scale))>;
+}
+
+let Predicates = [HasNEON] in {
+  defm : FmulToFPToIntFPRPats<any_fp_to_sint, "FCVTZS">;
+  defm : FmulToFPToIntFPRPats<any_fp_to_uint, "FCVTZU">;
+  defm : FmulToFPToIntFPRPats<int_aarch64_neon_fcvtzs, "FCVTZS">;
+  defm : FmulToFPToIntFPRPats<int_aarch64_neon_fcvtzu, "FCVTZU">;
+}
+
+multiclass FmulToFPToIntSatFPRPats<SDPatternOperator OpN, string INST> {
+  def : Pat<(f32 (bitconvert (i32 (OpN (fmul FPR32:$Rn, fixedpoint_f32_i32:$scale), i32)))),
+      (!cast<Instruction>(INST # "s") FPR32:$Rn, (fixedpoint_vec_xform fixedpoint_f32_i32:$scale))>;
+  def : Pat<(f64 (bitconvert (i64 (OpN (fmul FPR64:$Rn, fixedpoint_f64_i64:$scale), i64)))),
+      (!cast<Instruction>(INST # "d") FPR64:$Rn, (fixedpoint_vec_xform fixedpoint_f64_i64:$scale))>;
+}
+
+let Predicates = [HasNEON] in {
+  defm : FmulToFPToIntSatFPRPats<fp_to_sint_sat, "FCVTZS">;
+  defm : FmulToFPToIntSatFPRPats<fp_to_uint_sat, "FCVTZU">;
+}
+
 multiclass FCVTPat<ValueType FVT, ValueType IVT, ValueType ScalarVT, RegisterOperand RC, ComplexPattern fixedpoint> {
   // fptosi(fadd(x, x)) -> FCVTZS_shift x, 1
   def : Pat<(IVT (fp_to_sint (FVT (fadd RC:$Vn, RC:$Vn)))),
diff --git a/llvm/test/CodeGen/AArch64/fcvt-fixed.ll b/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
index 743d1604388de..4ff1e1cbcda6a 100644
--- a/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
+++ b/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
@@ -41,6 +41,24 @@ define i32 @fcvtzs_f32_i32_32(float %flt) {
   ret i32 %cvt
 }
 
+define float @fcvtzs_f32_i32_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzs_f32_i32_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs s0, s0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzs_f32_i32_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs s0, s0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul float %flt, 128.0
+  %cvt = fptosi float %fix to i32
+  %bc = bitcast i32 %cvt to float
+  ret float %bc
+}
+
 define i64 @fcvtzs_f32_i64_7(float %flt) {
 ; CHECK-SD-LABEL: fcvtzs_f32_i64_7:
 ; CHECK-SD:       // %bb.0:
@@ -148,6 +166,25 @@ define i64 @fcvtzs_f64_i64_64(double %dbl) {
   ret i64 %cvt
 }
 
+define double @fcvtzs_f64_i64_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzs_f64_i64_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs d0, d0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzs_f64_i64_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov x8, #4638707616191610880 // =0x4060000000000000
+; CHECK-GI-NEXT:    fmov d1, x8
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzs d0, d0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul double %dbl, 128.0
+  %cvt = fptosi double %fix to i64
+  %bc = bitcast i64 %cvt to double
+  ret double %bc
+}
+
 define i32 @fcvtzs_f16_i32_7(half %flt) {
 ; CHECK-NO16-LABEL: fcvtzs_f16_i32_7:
 ; CHECK-NO16:       // %bb.0:
@@ -166,8 +203,8 @@ define i32 @fcvtzs_f16_i32_7(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI8_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI8_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI10_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI10_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -194,8 +231,8 @@ define i32 @fcvtzs_f16_i32_15(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI9_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI9_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI11_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI11_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -222,8 +259,8 @@ define i64 @fcvtzs_f16_i64_7(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI10_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI10_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI12_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI12_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -250,8 +287,8 @@ define i64 @fcvtzs_f16_i64_15(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI11_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI11_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI13_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI13_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -279,6 +316,24 @@ define i32 @fcvtzu_f32_i32_7(float %flt) {
   ret i32 %cvt
 }
 
+define float @fcvtzu_f32_i32_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzu_f32_i32_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu s0, s0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzu_f32_i32_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu s0, s0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul float %flt, 128.0
+  %cvt = fptoui float %fix to i32
+  %bc = bitcast i32 %cvt to float
+  ret float %bc
+}
+
 define i32 @fcvtzu_f32_i32_32(float %flt) {
 ; CHECK-SD-LABEL: fcvtzu_f32_i32_32:
 ; CHECK-SD:       // %bb.0:
@@ -404,6 +459,25 @@ define i64 @fcvtzu_f64_i64_64(double %dbl) {
   ret i64 %cvt
 }
 
+define double @fcvtzu_f64_i64_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzu_f64_i64_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu d0, d0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzu_f64_i64_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov x8, #4638707616191610880 // =0x4060000000000000
+; CHECK-GI-NEXT:    fmov d1, x8
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzu d0, d0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul double %dbl, 128.0
+  %cvt = fptoui double %fix to i64
+  %bc = bitcast i64 %cvt to double
+  ret double %bc
+}
+
 define i32 @fcvtzu_f16_i32_7(half %flt) {
 ; CHECK-NO16-LABEL: fcvtzu_f16_i32_7:
 ; CHECK-NO16:       // %bb.0:
@@ -422,8 +496,8 @@ define i32 @fcvtzu_f16_i32_7(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI20_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI20_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI24_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI24_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -450,8 +524,8 @@ define i32 @fcvtzu_f16_i32_15(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI21_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI21_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI25_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI25_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -478,8 +552,8 @@ define i64 @fcvtzu_f16_i64_7(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI22_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI22_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI26_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI26_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -506,8 +580,8 @@ define i64 @fcvtzu_f16_i64_15(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI23_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI23_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI27_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI27_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -689,8 +763,8 @@ define half @scvtf_f16_i32_7(i32 %int) {
 ; CHECK-GI-FP16-LABEL: scvtf_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    scvtf h0, w0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI32_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI32_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI36_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI36_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = sitofp i32 %int to half
@@ -727,8 +801,8 @@ define half @scvtf_f16_i32_15(i32 %int) {
 ; CHECK-GI-FP16-LABEL: scvtf_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    scvtf h0, w0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI33_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI33_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI37_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI37_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = sitofp i32 %int to half
@@ -765,8 +839,8 @@ define half @scvtf_f16_i64_7(i64 %long) {
 ; CHECK-GI-FP16-LABEL: scvtf_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    scvtf h0, x0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI34_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI34_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI38_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI38_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = sitofp i64 %long to half
@@ -803,8 +877,8 @@ define half @scvtf_f16_i64_15(i64 %long) {
 ; CHECK-GI-FP16-LABEL: scvtf_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    scvtf h0, x0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI35_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI35_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI39_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI39_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = sitofp i64 %long to half
@@ -985,8 +1059,8 @@ define half @ucvtf_f16_i32_7(i32 %int) {
 ; CHECK-GI-FP16-LABEL: ucvtf_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    ucvtf h0, w0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI44_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI44_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI48_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI48_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = uitofp i32 %int to half
@@ -1023,8 +1097,8 @@ define half @ucvtf_f16_i32_15(i32 %int) {
 ; CHECK-GI-FP16-LABEL: ucvtf_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    ucvtf h0, w0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI45_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI45_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI49_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI49_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = uitofp i32 %int to half
@@ -1061,8 +1135,8 @@ define half @ucvtf_f16_i64_7(i64 %long) {
 ; CHECK-GI-FP16-LABEL: ucvtf_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    ucvtf h0, x0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI46_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI46_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI50_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI50_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = uitofp i64 %long to half
@@ -1099,8 +1173,8 @@ define half @ucvtf_f16_i64_15(i64 %long) {
 ; CHECK-GI-FP16-LABEL: ucvtf_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    ucvtf h0, x0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI47_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI47_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI51_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI51_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = uitofp i64 %long to half
@@ -1153,6 +1227,24 @@ define i32 @fcvtzs_sat_f32_i32_32(float %flt) {
   ret i32 %cvt
 }
 
+define float @fcvtzs_sat_f32_i32_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzs_sat_f32_i32_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs s0, s0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzs_sat_f32_i32_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs s0, s0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul float %flt, 128.0
+  %cvt = call i32 @llvm.fptosi.sat.i32.f32(float %fix)
+  %bc = bitcast i32 %cvt to float
+  ret float %bc
+}
+
 define i64 @fcvtzs_sat_f32_i64_64(float %flt) {
 ; CHECK-SD-LABEL: fcvtzs_sat_f32_i64_64:
 ; CHECK-SD:       // %bb.0:
@@ -1243,6 +1335,25 @@ define i64 @fcvtzs_sat_f64_i64_64(double %dbl) {
   ret i64 %cvt
 }
 
+define double @fcvtzs_sat_f64_i64_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzs_sat_f64_i64_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs d0, d0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzs_sat_f64_i64_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov x8, #4638707616191610880 // =0x4060000000000000
+; CHECK-GI-NEXT:    fmov d1, x8
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzs d0, d0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul double %dbl, 128.0
+  %cvt = call i64 @llvm.fptosi.sat.i64.f64(double %fix)
+  %bc = bitcast i64 %cvt to double
+  ret double %bc
+}
+
 define i32 @fcvtzs_sat_f16_i32_7(half %dbl) {
 ; CHECK-NO16-LABEL: fcvtzs_sat_f16_i32_7:
 ; CHECK-NO16:       // %bb.0:
@@ -1261,8 +1372,8 @@ define i32 @fcvtzs_sat_f16_i32_7(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_sat_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI55_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI55_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI61_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI61_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1289,8 +1400,8 @@ define i32 @fcvtzs_sat_f16_i32_15(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_sat_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI56_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI56_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI62_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI62_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1317,8 +1428,8 @@ define i64 @fcvtzs_sat_f16_i64_7(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_sat_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI57_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI57_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI63_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI63_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1345,8 +1456,8 @@ define i64 @fcvtzs_sat_f16_i64_15(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_sat_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI58_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI58_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI64_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI64_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1399,6 +1510,24 @@ define i32 @fcvtzu_sat_f32_i32_32(float %flt) {
   ret i32 %cvt
 }
 
+define float @fcvtzu_sat_f32_i32_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzu_sat_f32_i32_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu s0, s0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzu_sat_f32_i32_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu s0, s0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul float %flt, 128.0
+  %cvt = call i32 @llvm.fptoui.sat.i32.f32(float %fix)
+  %bc = bitcast i32 %cvt to float
+  ret float %bc
+}
+
 define i64 @fcvtzu_sat_f32_i64_64(float %flt) {
 ; CHECK-SD-LABEL: fcvtzu_sat_f32_i64_64:
 ; CHECK-SD:       // %bb.0:
@@ -1489,6 +1618,25 @@ define i64 @fcvtzu_sat_f64_i64_64(double %dbl) {
   ret i64 %cvt
 }
 
+define double @fcvtzu_sat_f64_i64_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzu_sat_f64_i64_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu d0, d0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzu_sat_f64_i64_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov x8, #4638707616191610880 // =0x4060000000000000
+; CHECK-GI-NEXT:    fmov d1, x8
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzu d0, d0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul double %dbl, 128.0
+  %cvt = call i64 @llvm.fptoui.sat.i64.f64(double %fix)
+  %bc = bitcast i64 %cvt to double
+  ret double %bc
+}
+
 define i32 @fcvtzu_sat_f16_i32_7(half %dbl) {
 ; CHECK-NO16-LABEL: fcvtzu_sat_f16_i32_7:
 ; CHECK-NO16:       // %bb.0:
@@ -1507,8 +1655,8 @@ define i32 @fcvtzu_sat_f16_i32_7(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_sat_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI66_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI66_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI74_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI74_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1535,8 +1683,8 @@ define i32 @fcvtzu_sat_f16_i32_15(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_sat_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI67_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI67_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI75_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI75_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1563,8 +1711,8 @@ define i64 @fcvtzu_sat_f16_i64_7(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_sat_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI68_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI68_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI76_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI76_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1591,8 +1739,8 @@ define i64 @fcvtzu_sat_f16_i64_15(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_sat_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI69_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI69_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI77_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI77_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
diff --git a/llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll b/llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll
new file mode 100644
index 0000000000000..ca162ac506502
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll
@@ -0,0 +1,148 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SD,CHECK-NO16,CHECK-SD-NO16
+; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI,CHECK-NO16,CHECK-GI-NO16
+
+define i32 @neon_fcvtzs_f32_i32(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzs_f32_i32:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs w0, s0, #3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzs_f32_i32:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    fmov s1, #8.00000000
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs w0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 8.000000e+00
+  %r = call i32 @llvm.aarch64.neon.fcvtzs.i32.f32(float %mul)
+  ret i32 %r
+}
+
+define float @neon_fcvtzs_f32_i32_bitcast(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzs_f32_i32_bitcast:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs s0, s0, #3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzs_f32_i32_bitcast:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    fmov s1, #8.00000000
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs s0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 8.000000e+00
+  %r = call i32 @llvm.aarch64.neon.fcvtzs.i32.f32(float %mul)
+  %bc = bitcast i32 %r to float
+  ret float %bc
+}
+
+define i64 @neon_fcvtzs_f64_i64(double %a) {
+; CHECK-SD-LABEL: neon_fcvtzs_f64_i64:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs x0, d0, #3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzs_f64_i64:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    fmov d1, #8.00000000
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzs x0, d0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul double %a, 8.000000e+00
+  %r = call i64 @llvm.aarch64.neon.fcvtzs.i64.f64(double %mul)
+  ret i64 %r
+}
+
+define double @neon_fcvtzs_f64_i64_bitcast(double %a) {
+; CHECK-SD-LABEL: neon_fcvtzs_f64_i64_bitcast:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs d0, d0, #3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzs_f64_i64_bitcast:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    fmov d1, #8.00000000
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzs d0, d0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul double %a, 8.000000e+00
+  %r = call i64 @llvm.aarch64.neon.fcvtzs.i64.f64(double %mul)
+  %bc = bitcast i64 %r to double
+  ret double %bc
+}
+
+define i32 @neon_fcvtzu_f32_i32(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzu_f32_i32:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu w0, s0, #3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzu_f32_i32:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    fmov s1, #8.00000000
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu w0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 8.000000e+00
+  %r = call i32 @llvm.aarch64.neon.fcvtzu.i32.f32(float %mul)
+  ret i32 %r
+}
+
+define float @neon_fcvtzu_f32_i32_bitcast(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzu_f32_i32_bitcast:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu s0, s0, #3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzu_f32_i32_bitcast:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    fmov s1, #8.00000000
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu s0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 8.000000e+00
+  %r = call i32 @llvm.aarch64.neon.fcvtzu.i32.f32(float %mul)
+  %bc = bitcast i32 %r to float
+  ret float %bc
+}
+
+define i64 @neon_fcvtzu_f64_i64(double %a) {
+; CHECK-SD-LABEL: neon_fcvtzu_f64_i64:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu x0, d0, #3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzu_f64_i64:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    fmov d1, #8.00000000
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzu x0, d0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul double %a, 8.000000e+00
+  %r = call i64 @llvm.aarch64.neon.fcvtzu.i64.f64(double %mul)
+  ret i64 %r
+}
+
+define double @neon_fcvtzu_f64_i64_bitcast(double %a) {
+; CHECK-SD-LABEL: neon_fcvtzu_f64_i64_bitcast:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu d0, d0, #3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzu_f64_i64_bitcast:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    fmov d1, #8.00000000
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzu d0, d0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul double %a, 8.000000e+00
+  %r = call i64 @llvm.aarch64.neon.fcvtzu.i64.f64(double %mul)
+  %bc = bitcast i64 %r to double
+  ret double %bc
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
+; CHECK-GI-NO16: {{.*}}
+; CHECK-NO16: {{.*}}
+; CHECK-SD-NO16: {{.*}}

>From ed45e7cacfb6e6a3b64f3cabfd44b8a76f251e56 Mon Sep 17 00:00:00 2001
From: Kieran Bailey <kieran.bailey at arm.com>
Date: Mon, 27 Jul 2026 15:43:12 +0000
Subject: [PATCH 2/3] Review Commit

- Add maximum scale test for fpr resulting conversions
- Moved neon-fcvt to fcvt-fixed.ll instead of separate file
- Reverted comment back to original
---
 llvm/lib/Target/AArch64/AArch64InstrInfo.td  |   5 +-
 llvm/test/CodeGen/AArch64/fcvt-fixed.ll      | 430 +++++++++++++++----
 llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll | 148 -------
 3 files changed, 357 insertions(+), 226 deletions(-)
 delete mode 100644 llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll

diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 43cd4e6466524..63cf927a6d7c9 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -9252,9 +9252,8 @@ class fixedpoint_vec_f32<ValueType FloatVT>
 class fixedpoint_vec_f16<ValueType FloatVT>
     : ComplexPattern<FloatVT, 1, "SelectCVTFixedPointVec<16>">;
     
-// Shared by scalar and vector fixed-point FCVT patterns. 
-// Allows transformation of fixedpoint -> vecshift. The imm
-// value we want is already in V from SelectCVTFixedPointVec.
+// This thing just allows us to change the type of the node produced. 
+// The imm value we want is already in V from SelectCVTFixedPointVec.
 def fixedpoint_vec_xform : SDNodeXForm<timm, [{
   (void)N;
   return V;
diff --git a/llvm/test/CodeGen/AArch64/fcvt-fixed.ll b/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
index 4ff1e1cbcda6a..7419d88ef6c8d 100644
--- a/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
+++ b/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
@@ -41,13 +41,13 @@ define i32 @fcvtzs_f32_i32_32(float %flt) {
   ret i32 %cvt
 }
 
-define float @fcvtzs_f32_i32_fpr(float %flt) {
-; CHECK-SD-LABEL: fcvtzs_f32_i32_fpr:
+define float @fcvtzs_f32_i32_7_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzs_f32_i32_7_fpr:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzs s0, s0, #7
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: fcvtzs_f32_i32_fpr:
+; CHECK-GI-LABEL: fcvtzs_f32_i32_7_fpr:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
 ; CHECK-GI-NEXT:    fmul s0, s0, s1
@@ -59,6 +59,25 @@ define float @fcvtzs_f32_i32_fpr(float %flt) {
   ret float %bc
 }
 
+define float @fcvtzs_f32_i32_32_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzs_f32_i32_32_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs s0, s0, #32
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzs_f32_i32_32_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
+; CHECK-GI-NEXT:    fmov s1, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs s0, s0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul float %flt, 4294967296.0
+  %cvt = fptosi float %fix to i32
+  %bc = bitcast i32 %cvt to float
+  ret float %bc
+}
+
 define i64 @fcvtzs_f32_i64_7(float %flt) {
 ; CHECK-SD-LABEL: fcvtzs_f32_i64_7:
 ; CHECK-SD:       // %bb.0:
@@ -166,13 +185,13 @@ define i64 @fcvtzs_f64_i64_64(double %dbl) {
   ret i64 %cvt
 }
 
-define double @fcvtzs_f64_i64_fpr(double %dbl) {
-; CHECK-SD-LABEL: fcvtzs_f64_i64_fpr:
+define double @fcvtzs_f64_i64_7_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzs_f64_i64_7_fpr:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzs d0, d0, #7
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: fcvtzs_f64_i64_fpr:
+; CHECK-GI-LABEL: fcvtzs_f64_i64_7_fpr:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    mov x8, #4638707616191610880 // =0x4060000000000000
 ; CHECK-GI-NEXT:    fmov d1, x8
@@ -185,6 +204,25 @@ define double @fcvtzs_f64_i64_fpr(double %dbl) {
   ret double %bc
 }
 
+define double @fcvtzs_f64_i64_64_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzs_f64_i64_64_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs d0, d0, #64
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzs_f64_i64_64_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov x8, #4895412794951729152 // =0x43f0000000000000
+; CHECK-GI-NEXT:    fmov d1, x8
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzs d0, d0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul double %dbl, 18446744073709551616.0
+  %cvt = fptosi double %fix to i64
+  %bc = bitcast i64 %cvt to double
+  ret double %bc
+}
+
 define i32 @fcvtzs_f16_i32_7(half %flt) {
 ; CHECK-NO16-LABEL: fcvtzs_f16_i32_7:
 ; CHECK-NO16:       // %bb.0:
@@ -203,8 +241,8 @@ define i32 @fcvtzs_f16_i32_7(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI10_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI10_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI12_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI12_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -231,8 +269,8 @@ define i32 @fcvtzs_f16_i32_15(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI11_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI11_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI13_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI13_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -259,8 +297,8 @@ define i64 @fcvtzs_f16_i64_7(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI12_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI12_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI14_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI14_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -287,8 +325,8 @@ define i64 @fcvtzs_f16_i64_15(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI13_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI13_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI15_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI15_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -316,13 +354,31 @@ define i32 @fcvtzu_f32_i32_7(float %flt) {
   ret i32 %cvt
 }
 
-define float @fcvtzu_f32_i32_fpr(float %flt) {
-; CHECK-SD-LABEL: fcvtzu_f32_i32_fpr:
+define i32 @fcvtzu_f32_i32_32(float %flt) {
+; CHECK-SD-LABEL: fcvtzu_f32_i32_32:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu w0, s0, #32
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzu_f32_i32_32:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
+; CHECK-GI-NEXT:    fmov s1, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu w0, s0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul float %flt, 4294967296.0
+  %cvt = fptoui float %fix to i32
+  ret i32 %cvt
+}
+
+define float @fcvtzu_f32_i32_7_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzu_f32_i32_7_fpr:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzu s0, s0, #7
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: fcvtzu_f32_i32_fpr:
+; CHECK-GI-LABEL: fcvtzu_f32_i32_7_fpr:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
 ; CHECK-GI-NEXT:    fmul s0, s0, s1
@@ -334,22 +390,23 @@ define float @fcvtzu_f32_i32_fpr(float %flt) {
   ret float %bc
 }
 
-define i32 @fcvtzu_f32_i32_32(float %flt) {
-; CHECK-SD-LABEL: fcvtzu_f32_i32_32:
+define float @fcvtzu_f32_i32_32_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzu_f32_i32_32_fpr:
 ; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzu w0, s0, #32
+; CHECK-SD-NEXT:    fcvtzu s0, s0, #32
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: fcvtzu_f32_i32_32:
+; CHECK-GI-LABEL: fcvtzu_f32_i32_32_fpr:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
 ; CHECK-GI-NEXT:    fmov s1, w8
 ; CHECK-GI-NEXT:    fmul s0, s0, s1
-; CHECK-GI-NEXT:    fcvtzu w0, s0
+; CHECK-GI-NEXT:    fcvtzu s0, s0
 ; CHECK-GI-NEXT:    ret
   %fix = fmul float %flt, 4294967296.0
   %cvt = fptoui float %fix to i32
-  ret i32 %cvt
+  %bc = bitcast i32 %cvt to float
+  ret float %bc
 }
 
 define i64 @fcvtzu_f32_i64_7(float %flt) {
@@ -496,8 +553,8 @@ define i32 @fcvtzu_f16_i32_7(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI24_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI24_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI27_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI27_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -524,8 +581,8 @@ define i32 @fcvtzu_f16_i32_15(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI25_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI25_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI28_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI28_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -552,8 +609,8 @@ define i64 @fcvtzu_f16_i64_7(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI26_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI26_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI29_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI29_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -580,8 +637,8 @@ define i64 @fcvtzu_f16_i64_15(half %flt) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI27_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI27_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI30_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI30_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -763,8 +820,8 @@ define half @scvtf_f16_i32_7(i32 %int) {
 ; CHECK-GI-FP16-LABEL: scvtf_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    scvtf h0, w0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI36_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI36_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI39_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI39_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = sitofp i32 %int to half
@@ -801,8 +858,8 @@ define half @scvtf_f16_i32_15(i32 %int) {
 ; CHECK-GI-FP16-LABEL: scvtf_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    scvtf h0, w0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI37_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI37_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI40_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI40_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = sitofp i32 %int to half
@@ -839,8 +896,8 @@ define half @scvtf_f16_i64_7(i64 %long) {
 ; CHECK-GI-FP16-LABEL: scvtf_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    scvtf h0, x0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI38_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI38_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI41_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI41_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = sitofp i64 %long to half
@@ -877,8 +934,8 @@ define half @scvtf_f16_i64_15(i64 %long) {
 ; CHECK-GI-FP16-LABEL: scvtf_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    scvtf h0, x0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI39_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI39_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI42_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI42_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = sitofp i64 %long to half
@@ -1059,8 +1116,8 @@ define half @ucvtf_f16_i32_7(i32 %int) {
 ; CHECK-GI-FP16-LABEL: ucvtf_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    ucvtf h0, w0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI48_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI48_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI51_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI51_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = uitofp i32 %int to half
@@ -1097,8 +1154,8 @@ define half @ucvtf_f16_i32_15(i32 %int) {
 ; CHECK-GI-FP16-LABEL: ucvtf_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    ucvtf h0, w0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI49_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI49_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI52_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI52_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = uitofp i32 %int to half
@@ -1135,8 +1192,8 @@ define half @ucvtf_f16_i64_7(i64 %long) {
 ; CHECK-GI-FP16-LABEL: ucvtf_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    ucvtf h0, x0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI50_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI50_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI53_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI53_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = uitofp i64 %long to half
@@ -1173,8 +1230,8 @@ define half @ucvtf_f16_i64_15(i64 %long) {
 ; CHECK-GI-FP16-LABEL: ucvtf_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
 ; CHECK-GI-FP16-NEXT:    ucvtf h0, x0
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI51_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI51_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI54_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI54_0]
 ; CHECK-GI-FP16-NEXT:    fdiv h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    ret
   %cvt = uitofp i64 %long to half
@@ -1227,13 +1284,13 @@ define i32 @fcvtzs_sat_f32_i32_32(float %flt) {
   ret i32 %cvt
 }
 
-define float @fcvtzs_sat_f32_i32_fpr(float %flt) {
-; CHECK-SD-LABEL: fcvtzs_sat_f32_i32_fpr:
+define float @fcvtzs_sat_f32_i32_7_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzs_sat_f32_i32_7_fpr:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzs s0, s0, #7
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: fcvtzs_sat_f32_i32_fpr:
+; CHECK-GI-LABEL: fcvtzs_sat_f32_i32_7_fpr:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
 ; CHECK-GI-NEXT:    fmul s0, s0, s1
@@ -1245,6 +1302,25 @@ define float @fcvtzs_sat_f32_i32_fpr(float %flt) {
   ret float %bc
 }
 
+define float @fcvtzs_sat_f32_i32_32_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzs_sat_f32_i32_32_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs s0, s0, #32
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzs_sat_f32_i32_32_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
+; CHECK-GI-NEXT:    fmov s1, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs s0, s0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul float %flt, 4294967296.0
+  %cvt = call i32 @llvm.fptosi.sat.i32.f32(float %fix)
+  %bc = bitcast i32 %cvt to float
+  ret float %bc
+}
+
 define i64 @fcvtzs_sat_f32_i64_64(float %flt) {
 ; CHECK-SD-LABEL: fcvtzs_sat_f32_i64_64:
 ; CHECK-SD:       // %bb.0:
@@ -1335,13 +1411,13 @@ define i64 @fcvtzs_sat_f64_i64_64(double %dbl) {
   ret i64 %cvt
 }
 
-define double @fcvtzs_sat_f64_i64_fpr(double %dbl) {
-; CHECK-SD-LABEL: fcvtzs_sat_f64_i64_fpr:
+define double @fcvtzs_sat_f64_i64_7_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzs_sat_f64_i64_7_fpr:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzs d0, d0, #7
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: fcvtzs_sat_f64_i64_fpr:
+; CHECK-GI-LABEL: fcvtzs_sat_f64_i64_7_fpr:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    mov x8, #4638707616191610880 // =0x4060000000000000
 ; CHECK-GI-NEXT:    fmov d1, x8
@@ -1354,6 +1430,26 @@ define double @fcvtzs_sat_f64_i64_fpr(double %dbl) {
   ret double %bc
 }
 
+define double @fcvtzs_sat_f64_i64_64_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzs_sat_f64_i64_64_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs d0, d0, #64
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzs_sat_f64_i64_64_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov x8, #4895412794951729152 // =0x43f0000000000000
+; CHECK-GI-NEXT:    fmov d1, x8
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzs d0, d0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul double %dbl, 18446744073709551616.0
+  %cvt = call i64 @llvm.fptosi.sat.i64.f64(double %fix)
+  %bc = bitcast i64 %cvt to double
+  ret double %bc
+}
+
+
 define i32 @fcvtzs_sat_f16_i32_7(half %dbl) {
 ; CHECK-NO16-LABEL: fcvtzs_sat_f16_i32_7:
 ; CHECK-NO16:       // %bb.0:
@@ -1372,8 +1468,8 @@ define i32 @fcvtzs_sat_f16_i32_7(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_sat_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI61_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI61_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI66_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI66_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1400,8 +1496,8 @@ define i32 @fcvtzs_sat_f16_i32_15(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_sat_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI62_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI62_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI67_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI67_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1428,8 +1524,8 @@ define i64 @fcvtzs_sat_f16_i64_7(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_sat_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI63_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI63_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI68_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI68_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1456,8 +1552,8 @@ define i64 @fcvtzs_sat_f16_i64_15(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzs_sat_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI64_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI64_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI69_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI69_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzs x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1510,13 +1606,13 @@ define i32 @fcvtzu_sat_f32_i32_32(float %flt) {
   ret i32 %cvt
 }
 
-define float @fcvtzu_sat_f32_i32_fpr(float %flt) {
-; CHECK-SD-LABEL: fcvtzu_sat_f32_i32_fpr:
+define float @fcvtzu_sat_f32_i32_7_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzu_sat_f32_i32_7_fpr:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzu s0, s0, #7
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: fcvtzu_sat_f32_i32_fpr:
+; CHECK-GI-LABEL: fcvtzu_sat_f32_i32_7_fpr:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
 ; CHECK-GI-NEXT:    fmul s0, s0, s1
@@ -1528,6 +1624,25 @@ define float @fcvtzu_sat_f32_i32_fpr(float %flt) {
   ret float %bc
 }
 
+define float @fcvtzu_sat_f32_i32_32_fpr(float %flt) {
+; CHECK-SD-LABEL: fcvtzu_sat_f32_i32_32_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu s0, s0, #32
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzu_sat_f32_i32_32_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
+; CHECK-GI-NEXT:    fmov s1, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu s0, s0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul float %flt, 4294967296.0
+  %cvt = call i32 @llvm.fptoui.sat.i32.f32(float %fix)
+  %bc = bitcast i32 %cvt to float
+  ret float %bc
+}
+
 define i64 @fcvtzu_sat_f32_i64_64(float %flt) {
 ; CHECK-SD-LABEL: fcvtzu_sat_f32_i64_64:
 ; CHECK-SD:       // %bb.0:
@@ -1618,13 +1733,13 @@ define i64 @fcvtzu_sat_f64_i64_64(double %dbl) {
   ret i64 %cvt
 }
 
-define double @fcvtzu_sat_f64_i64_fpr(double %dbl) {
-; CHECK-SD-LABEL: fcvtzu_sat_f64_i64_fpr:
+define double @fcvtzu_sat_f64_i64_7_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzu_sat_f64_i64_7_fpr:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzu d0, d0, #7
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: fcvtzu_sat_f64_i64_fpr:
+; CHECK-GI-LABEL: fcvtzu_sat_f64_i64_7_fpr:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    mov x8, #4638707616191610880 // =0x4060000000000000
 ; CHECK-GI-NEXT:    fmov d1, x8
@@ -1637,6 +1752,26 @@ define double @fcvtzu_sat_f64_i64_fpr(double %dbl) {
   ret double %bc
 }
 
+define double @fcvtzu_sat_f64_i64_64_fpr(double %dbl) {
+; CHECK-SD-LABEL: fcvtzu_sat_f64_i64_64_fpr:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu d0, d0, #64
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: fcvtzu_sat_f64_i64_64_fpr:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov x8, #4895412794951729152 // =0x43f0000000000000
+; CHECK-GI-NEXT:    fmov d1, x8
+; CHECK-GI-NEXT:    fmul d0, d0, d1
+; CHECK-GI-NEXT:    fcvtzu d0, d0
+; CHECK-GI-NEXT:    ret
+  %fix = fmul double %dbl, 18446744073709551616.0
+  %cvt = call i64 @llvm.fptoui.sat.i64.f64(double %fix)
+  %bc = bitcast i64 %cvt to double
+  ret double %bc
+}
+
+
 define i32 @fcvtzu_sat_f16_i32_7(half %dbl) {
 ; CHECK-NO16-LABEL: fcvtzu_sat_f16_i32_7:
 ; CHECK-NO16:       // %bb.0:
@@ -1655,8 +1790,8 @@ define i32 @fcvtzu_sat_f16_i32_7(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_sat_f16_i32_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI74_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI74_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI81_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI81_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1683,8 +1818,8 @@ define i32 @fcvtzu_sat_f16_i32_15(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_sat_f16_i32_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI75_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI75_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI82_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI82_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu w0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1711,8 +1846,8 @@ define i64 @fcvtzu_sat_f16_i64_7(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_sat_f16_i64_7:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI76_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI76_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI83_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI83_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1739,8 +1874,8 @@ define i64 @fcvtzu_sat_f16_i64_15(half %dbl) {
 ;
 ; CHECK-GI-FP16-LABEL: fcvtzu_sat_f16_i64_15:
 ; CHECK-GI-FP16:       // %bb.0:
-; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI77_0
-; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI77_0]
+; CHECK-GI-FP16-NEXT:    adrp x8, .LCPI84_0
+; CHECK-GI-FP16-NEXT:    ldr h1, [x8, :lo12:.LCPI84_0]
 ; CHECK-GI-FP16-NEXT:    fmul h0, h0, h1
 ; CHECK-GI-FP16-NEXT:    fcvtzu x0, h0
 ; CHECK-GI-FP16-NEXT:    ret
@@ -1748,6 +1883,151 @@ define i64 @fcvtzu_sat_f16_i64_15(half %dbl) {
   %cvt = call i64 @llvm.fptoui.sat.i64.f16(half %fix)
   ret i64 %cvt
 }
+
+define i32 @neon_fcvtzs_f32_i32_7(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzs_f32_i32_7:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs w0, s0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzs_f32_i32_7:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs w0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 128.0
+  %r = call i32 @llvm.aarch64.neon.fcvtzs.i32.f32(float %mul)
+  ret i32 %r
+}
+
+define i32 @neon_fcvtzs_f32_i32_32(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzs_f32_i32_32:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs w0, s0, #32
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzs_f32_i32_32:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
+; CHECK-GI-NEXT:    fmov s1, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs w0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 4294967296.0
+  %r = call i32 @llvm.aarch64.neon.fcvtzs.i32.f32(float %mul)
+  ret i32 %r
+}
+
+define float @neon_fcvtzs_f32_i32_7_bitcast(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzs_f32_i32_7_bitcast:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs s0, s0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzs_f32_i32_7_bitcast:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs s0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 128.0
+  %r = call i32 @llvm.aarch64.neon.fcvtzs.i32.f32(float %mul)
+  %bc = bitcast i32 %r to float
+  ret float %bc
+}
+
+define float @neon_fcvtzs_f32_i32_32_bitcast(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzs_f32_i32_32_bitcast:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzs s0, s0, #32
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzs_f32_i32_32_bitcast:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
+; CHECK-GI-NEXT:    fmov s1, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzs s0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 4294967296.0
+  %r = call i32 @llvm.aarch64.neon.fcvtzs.i32.f32(float %mul)
+  %bc = bitcast i32 %r to float
+  ret float %bc
+}
+
+define i32 @neon_fcvtzu_f32_i32_7(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzu_f32_i32_7:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu w0, s0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzu_f32_i32_7:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu w0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 128.0
+  %r = call i32 @llvm.aarch64.neon.fcvtzu.i32.f32(float %mul)
+  ret i32 %r
+}
+
+define i32 @neon_fcvtzu_f32_i32_32(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzu_f32_i32_32:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu w0, s0, #32
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzu_f32_i32_32:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
+; CHECK-GI-NEXT:    fmov s1, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu w0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 4294967296.0
+  %r = call i32 @llvm.aarch64.neon.fcvtzu.i32.f32(float %mul)
+  ret i32 %r
+}
+
+define float @neon_fcvtzu_f32_i32_7_bitcast(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzu_f32_i32_7_bitcast:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu s0, s0, #7
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzu_f32_i32_7_bitcast:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    movi v1.2s, #67, lsl #24
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu s0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 128.0
+  %r = call i32 @llvm.aarch64.neon.fcvtzu.i32.f32(float %mul)
+  %bc = bitcast i32 %r to float
+  ret float %bc
+}
+
+define float @neon_fcvtzu_f32_i32_32_bitcast(float %a) {
+; CHECK-SD-LABEL: neon_fcvtzu_f32_i32_32_bitcast:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    fcvtzu s0, s0, #32
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: neon_fcvtzu_f32_i32_32_bitcast:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    mov w8, #1333788672 // =0x4f800000
+; CHECK-GI-NEXT:    fmov s1, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s1
+; CHECK-GI-NEXT:    fcvtzu s0, s0
+; CHECK-GI-NEXT:    ret
+  %mul = fmul float %a, 4294967296.0
+  %r = call i32 @llvm.aarch64.neon.fcvtzu.i32.f32(float %mul)
+  %bc = bitcast i32 %r to float
+  ret float %bc
+}
+
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
 ; CHECK: {{.*}}
 ; CHECK-FP16: {{.*}}
diff --git a/llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll b/llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll
deleted file mode 100644
index ca162ac506502..0000000000000
--- a/llvm/test/CodeGen/AArch64/neon-fcvt-fixed.ll
+++ /dev/null
@@ -1,148 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SD,CHECK-NO16,CHECK-SD-NO16
-; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-none-linux-gnu -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI,CHECK-NO16,CHECK-GI-NO16
-
-define i32 @neon_fcvtzs_f32_i32(float %a) {
-; CHECK-SD-LABEL: neon_fcvtzs_f32_i32:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzs w0, s0, #3
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: neon_fcvtzs_f32_i32:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    fmov s1, #8.00000000
-; CHECK-GI-NEXT:    fmul s0, s0, s1
-; CHECK-GI-NEXT:    fcvtzs w0, s0
-; CHECK-GI-NEXT:    ret
-  %mul = fmul float %a, 8.000000e+00
-  %r = call i32 @llvm.aarch64.neon.fcvtzs.i32.f32(float %mul)
-  ret i32 %r
-}
-
-define float @neon_fcvtzs_f32_i32_bitcast(float %a) {
-; CHECK-SD-LABEL: neon_fcvtzs_f32_i32_bitcast:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzs s0, s0, #3
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: neon_fcvtzs_f32_i32_bitcast:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    fmov s1, #8.00000000
-; CHECK-GI-NEXT:    fmul s0, s0, s1
-; CHECK-GI-NEXT:    fcvtzs s0, s0
-; CHECK-GI-NEXT:    ret
-  %mul = fmul float %a, 8.000000e+00
-  %r = call i32 @llvm.aarch64.neon.fcvtzs.i32.f32(float %mul)
-  %bc = bitcast i32 %r to float
-  ret float %bc
-}
-
-define i64 @neon_fcvtzs_f64_i64(double %a) {
-; CHECK-SD-LABEL: neon_fcvtzs_f64_i64:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzs x0, d0, #3
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: neon_fcvtzs_f64_i64:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    fmov d1, #8.00000000
-; CHECK-GI-NEXT:    fmul d0, d0, d1
-; CHECK-GI-NEXT:    fcvtzs x0, d0
-; CHECK-GI-NEXT:    ret
-  %mul = fmul double %a, 8.000000e+00
-  %r = call i64 @llvm.aarch64.neon.fcvtzs.i64.f64(double %mul)
-  ret i64 %r
-}
-
-define double @neon_fcvtzs_f64_i64_bitcast(double %a) {
-; CHECK-SD-LABEL: neon_fcvtzs_f64_i64_bitcast:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzs d0, d0, #3
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: neon_fcvtzs_f64_i64_bitcast:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    fmov d1, #8.00000000
-; CHECK-GI-NEXT:    fmul d0, d0, d1
-; CHECK-GI-NEXT:    fcvtzs d0, d0
-; CHECK-GI-NEXT:    ret
-  %mul = fmul double %a, 8.000000e+00
-  %r = call i64 @llvm.aarch64.neon.fcvtzs.i64.f64(double %mul)
-  %bc = bitcast i64 %r to double
-  ret double %bc
-}
-
-define i32 @neon_fcvtzu_f32_i32(float %a) {
-; CHECK-SD-LABEL: neon_fcvtzu_f32_i32:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzu w0, s0, #3
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: neon_fcvtzu_f32_i32:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    fmov s1, #8.00000000
-; CHECK-GI-NEXT:    fmul s0, s0, s1
-; CHECK-GI-NEXT:    fcvtzu w0, s0
-; CHECK-GI-NEXT:    ret
-  %mul = fmul float %a, 8.000000e+00
-  %r = call i32 @llvm.aarch64.neon.fcvtzu.i32.f32(float %mul)
-  ret i32 %r
-}
-
-define float @neon_fcvtzu_f32_i32_bitcast(float %a) {
-; CHECK-SD-LABEL: neon_fcvtzu_f32_i32_bitcast:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzu s0, s0, #3
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: neon_fcvtzu_f32_i32_bitcast:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    fmov s1, #8.00000000
-; CHECK-GI-NEXT:    fmul s0, s0, s1
-; CHECK-GI-NEXT:    fcvtzu s0, s0
-; CHECK-GI-NEXT:    ret
-  %mul = fmul float %a, 8.000000e+00
-  %r = call i32 @llvm.aarch64.neon.fcvtzu.i32.f32(float %mul)
-  %bc = bitcast i32 %r to float
-  ret float %bc
-}
-
-define i64 @neon_fcvtzu_f64_i64(double %a) {
-; CHECK-SD-LABEL: neon_fcvtzu_f64_i64:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzu x0, d0, #3
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: neon_fcvtzu_f64_i64:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    fmov d1, #8.00000000
-; CHECK-GI-NEXT:    fmul d0, d0, d1
-; CHECK-GI-NEXT:    fcvtzu x0, d0
-; CHECK-GI-NEXT:    ret
-  %mul = fmul double %a, 8.000000e+00
-  %r = call i64 @llvm.aarch64.neon.fcvtzu.i64.f64(double %mul)
-  ret i64 %r
-}
-
-define double @neon_fcvtzu_f64_i64_bitcast(double %a) {
-; CHECK-SD-LABEL: neon_fcvtzu_f64_i64_bitcast:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    fcvtzu d0, d0, #3
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: neon_fcvtzu_f64_i64_bitcast:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    fmov d1, #8.00000000
-; CHECK-GI-NEXT:    fmul d0, d0, d1
-; CHECK-GI-NEXT:    fcvtzu d0, d0
-; CHECK-GI-NEXT:    ret
-  %mul = fmul double %a, 8.000000e+00
-  %r = call i64 @llvm.aarch64.neon.fcvtzu.i64.f64(double %mul)
-  %bc = bitcast i64 %r to double
-  ret double %bc
-}
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}
-; CHECK-GI-NO16: {{.*}}
-; CHECK-NO16: {{.*}}
-; CHECK-SD-NO16: {{.*}}

>From f627a42cc0fc5aece07174b705023b1432786841 Mon Sep 17 00:00:00 2001
From: Kieran Bailey <kieran.bailey at arm.com>
Date: Tue, 28 Jul 2026 14:07:03 +0000
Subject: [PATCH 3/3] [AArch64][SelectionDAG] Fold fp_to_int(fmul) for FPR
 results

Bundled the FPR with the GPR variants of the patterns.

The multiclass FPToIntegerIntPats cannot be used with any_fp_to_int. Due to the parameter taking an intrinsic, when changed to SDPattternOperator and passing the generic any_fp_to_int, compilation fails due to overlapping patterns in fastIsel. So, I have kept these in a separate multiclass FPToIntegerFmulPats.

The saturated patterns are bundled into its FPToIntegerSatPats class without problem.
---
 llvm/lib/Target/AArch64/AArch64InstrInfo.td | 55 ++++++++++++++-------
 1 file changed, 36 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 63cf927a6d7c9..69cf99e54309e 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -6675,6 +6675,8 @@ defm FCVTPU : SIMDFPTwoScalar<   1, 1, 0b11010, "fcvtpu", int_aarch64_neon_fcvtp
 def  FCVTXNv1i64 : SIMDInexactCvtTwoScalar<0b10110, "fcvtxn">;
 defm FCVTZS : SIMDFPTwoScalar<   0, 1, 0b11011, "fcvtzs", any_fp_to_sint>;
 defm FCVTZU : SIMDFPTwoScalar<   1, 1, 0b11011, "fcvtzu", any_fp_to_uint>;
+defm FCVTZS : SIMDFPScalarRShift<0, 0b11111, "fcvtzs">;
+defm FCVTZU : SIMDFPScalarRShift<1, 0b11111, "fcvtzu">;
 defm FRECPE : SIMDFPTwoScalarNonCVT<   0, 1, 0b11101, "frecpe">;
 defm FRECPX : SIMDFPTwoScalarNonCVT<   0, 1, 0b11111, "frecpx">;
 defm FRSQRTE : SIMDFPTwoScalarNonCVT<  1, 1, 0b11101, "frsqrte">;
@@ -6809,25 +6811,46 @@ multiclass FPToIntegerIntPats<Intrinsic round, string INST> {
   def : Pat<(f64 (bitconvert (i64 (round f64:$Rn)))), 
             (!cast<Instruction>(INST # v1i64) $Rn)>;
   }
+}
+
+defm : FPToIntegerIntPats<int_aarch64_neon_fcvtzs, "FCVTZS">;
+defm : FPToIntegerIntPats<int_aarch64_neon_fcvtzu, "FCVTZU">;
+
+// This thing just allows us to change the type of the node produced. The imm
+// value we want is already in V from SelectCVTFixedPointVec.
+def fixedpoint_vec_xform : SDNodeXForm<timm, [{
+  (void)N;
+  return V;
+}]>;
+def gi_fixedpoint_vec_xform : GICustomOperandRenderer<"renderFixedPointXForm">,
+  GISDNodeXFormEquiv<fixedpoint_vec_xform>;
 
+multiclass FPToIntegerFmulPats<SDPatternOperator OpN, string INST> { 
   let Predicates = [HasFullFP16] in {
-  def : Pat<(i32 (round (fmul f16:$Rn, fixedpoint_f16_i32:$scale))),
+  def : Pat<(i32 (OpN (fmul f16:$Rn, fixedpoint_f16_i32:$scale))),
             (!cast<Instruction>(INST # SWHri) $Rn, $scale)>;
-  def : Pat<(i64 (round (fmul f16:$Rn, fixedpoint_f16_i64:$scale))),
+  def : Pat<(i64 (OpN (fmul f16:$Rn, fixedpoint_f16_i64:$scale))),
             (!cast<Instruction>(INST # SXHri) $Rn, $scale)>;
   }
-  def : Pat<(i32 (round (fmul f32:$Rn, fixedpoint_f32_i32:$scale))),
+  def : Pat<(i32 (OpN (fmul f32:$Rn, fixedpoint_f32_i32:$scale))),
             (!cast<Instruction>(INST # SWSri) $Rn, $scale)>;
-  def : Pat<(i64 (round (fmul f32:$Rn, fixedpoint_f32_i64:$scale))),
+  def : Pat<(i64 (OpN (fmul f32:$Rn, fixedpoint_f32_i64:$scale))),
             (!cast<Instruction>(INST # SXSri) $Rn, $scale)>;
-  def : Pat<(i32 (round (fmul f64:$Rn, fixedpoint_f64_i32:$scale))),
+  def : Pat<(i32 (OpN (fmul f64:$Rn, fixedpoint_f64_i32:$scale))),
             (!cast<Instruction>(INST # SWDri) $Rn, $scale)>;
-  def : Pat<(i64 (round (fmul f64:$Rn, fixedpoint_f64_i64:$scale))),
+  def : Pat<(i64 (OpN (fmul f64:$Rn, fixedpoint_f64_i64:$scale))),
             (!cast<Instruction>(INST # SXDri) $Rn, $scale)>;
+
+  def : Pat<(f32 (bitconvert (i32 (OpN (fmul FPR32:$Rn, fixedpoint_f32_i32:$scale))))),
+      (!cast<Instruction>(INST # "s") FPR32:$Rn, (fixedpoint_vec_xform fixedpoint_f32_i32:$scale))>;
+  def : Pat<(f64 (bitconvert (i64 (OpN (fmul FPR64:$Rn, fixedpoint_f64_i64:$scale))))),
+      (!cast<Instruction>(INST # "d") FPR64:$Rn, (fixedpoint_vec_xform fixedpoint_f64_i64:$scale))>;
 }
 
-defm : FPToIntegerIntPats<int_aarch64_neon_fcvtzs, "FCVTZS">;
-defm : FPToIntegerIntPats<int_aarch64_neon_fcvtzu, "FCVTZU">;
+defm : FPToIntegerFmulPats<any_fp_to_sint, "FCVTZS">;
+defm : FPToIntegerFmulPats<any_fp_to_uint, "FCVTZU">;
+defm : FPToIntegerFmulPats<int_aarch64_neon_fcvtzs, "FCVTZS">;
+defm : FPToIntegerFmulPats<int_aarch64_neon_fcvtzu, "FCVTZU">;
 
 // AArch64's FCVT instructions saturate when out of range.
 multiclass FPToIntegerSatPats<SDNode to_int_sat, string INST> {
@@ -6898,6 +6921,11 @@ multiclass FPToIntegerSatPats<SDNode to_int_sat, string INST> {
             (!cast<Instruction>(INST # SWDri) $Rn, $scale)>;
   def : Pat<(i64 (to_int_sat (fmul f64:$Rn, fixedpoint_f64_i64:$scale), i64)),
             (!cast<Instruction>(INST # SXDri) $Rn, $scale)>;
+  
+  def : Pat<(f32 (bitconvert (i32 (to_int_sat (fmul FPR32:$Rn, fixedpoint_f32_i32:$scale), i32)))),
+            (!cast<Instruction>(INST # "s") FPR32:$Rn, (fixedpoint_vec_xform fixedpoint_f32_i32:$scale))>;
+  def : Pat<(f64 (bitconvert (i64 (to_int_sat (fmul FPR64:$Rn, fixedpoint_f64_i64:$scale), i64)))),
+            (!cast<Instruction>(INST # "d") FPR64:$Rn, (fixedpoint_vec_xform fixedpoint_f64_i64:$scale))>;
 }
 
 defm : FPToIntegerSatPats<fp_to_sint_sat, "FCVTZS">;
@@ -9117,8 +9145,6 @@ def : Pat<(i64 (int_aarch64_neon_sqsub (i64 FPR64:$Rd),
 //----------------------------------------------------------------------------
 // AdvSIMD scalar shift instructions
 //----------------------------------------------------------------------------
-defm FCVTZS : SIMDFPScalarRShift<0, 0b11111, "fcvtzs">;
-defm FCVTZU : SIMDFPScalarRShift<1, 0b11111, "fcvtzu">;
 defm SCVTF  : SIMDFPScalarRShift<0, 0b11100, "scvtf">;
 defm UCVTF  : SIMDFPScalarRShift<1, 0b11100, "ucvtf">;
 // Codegen patterns for the above. We don't put these directly on the
@@ -9251,15 +9277,6 @@ class fixedpoint_vec_f32<ValueType FloatVT>
     : ComplexPattern<FloatVT, 1, "SelectCVTFixedPointVec<32>">;
 class fixedpoint_vec_f16<ValueType FloatVT>
     : ComplexPattern<FloatVT, 1, "SelectCVTFixedPointVec<16>">;
-    
-// This thing just allows us to change the type of the node produced. 
-// The imm value we want is already in V from SelectCVTFixedPointVec.
-def fixedpoint_vec_xform : SDNodeXForm<timm, [{
-  (void)N;
-  return V;
-}]>;
-def gi_fixedpoint_vec_xform : GICustomOperandRenderer<"renderFixedPointXForm">,
-  GISDNodeXFormEquiv<fixedpoint_vec_xform>;
 
 def fixedpoint_v2f64 : fixedpoint_vec_f64<v2f64>;
 def fixedpoint_v2f32 : fixedpoint_vec_f32<v2f32>;



More information about the llvm-commits mailing list