[llvm] [DAG][AArch64] Lower to FRINTZ instructions (PR #198477)

Jacob Crawley via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 1 04:10:11 PDT 2026


https://github.com/jacob-crawley updated https://github.com/llvm/llvm-project/pull/198477

>From 76954477e28c4ab444359abcfdbfd52e0ecfb6ca Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Wed, 13 May 2026 08:05:43 +0000
Subject: [PATCH 1/9] [AArch64] Lower to FRINTZ instructions

Simplifies the codegen of fp to int to fp conversions by making use of
the FRINTZ instruction.

This patch implements this optimization for both scalable and fixed
SVE vectors.
---
 .../Target/AArch64/AArch64ISelLowering.cpp    | 95 +++++++++++++++++++
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   | 15 +++
 llvm/test/CodeGen/AArch64/neon-frintz.ll      | 70 ++++++++++++++
 .../AArch64/sve2p2-fixed-length-frintz.ll     | 87 +++++++++++++++++
 llvm/test/CodeGen/AArch64/sve2p2-frintz.ll    | 57 +++++++++++
 5 files changed, 324 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/neon-frintz.ll
 create mode 100644 llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll
 create mode 100644 llvm/test/CodeGen/AArch64/sve2p2-frintz.ll

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 710ca7fcba756..dd7ce2e6e75a8 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -21029,6 +21029,98 @@ static SDValue performFpToIntCombine(SDNode *N, SelectionDAG &DAG,
   return SDValue();
 }
 
+static SDValue performFpToSIntToFPCombineNEON(SelectionDAG &DAG, SDLoc DL,
+                                              EVT VT, unsigned int IntBits,
+                                              SDValue FPSrc) {
+  unsigned FrintOpc;
+
+  if (IntBits == 32)
+    FrintOpc = Intrinsic::aarch64_neon_frint32z;
+  else if (IntBits == 64)
+    FrintOpc = Intrinsic::aarch64_neon_frint64z;
+  else
+    return SDValue();
+
+  auto IsNEONVT = [](EVT VT) {
+    return VT == MVT::v2f32 || VT == MVT::v4f32 || VT == MVT::v2f64;
+  };
+
+  if (!IsNEONVT(VT))
+    return SDValue();
+
+  return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, VT,
+                     DAG.getTargetConstant(FrintOpc, DL, MVT::i64), FPSrc);
+}
+
+static SDValue performFpToSIntToFPCombineSVE(SelectionDAG &DAG, SDLoc DL,
+                                             EVT VT, unsigned int IntBits,
+                                             SDValue FPSrc, SDNodeFlags Flags) {
+  unsigned FrintOpc;
+
+  if (IntBits == 64)
+    FrintOpc = AArch64ISD::FTRUNC64_MERGE_PASSTHRU;
+  else if (IntBits == 32)
+    FrintOpc = AArch64ISD::FTRUNC32_MERGE_PASSTHRU;
+  else
+    return SDValue();
+
+  EVT ContainerVT =
+      VT.isFixedLengthVector() ? getContainerForFixedLengthVector(DAG, VT) : VT;
+
+  SDValue Pg = getPredicateForVector(DAG, DL, VT);
+  SDValue Val = VT.isFixedLengthVector()
+                    ? convertToScalableVector(DAG, ContainerVT, FPSrc)
+                    : FPSrc;
+
+  SDValue Res = DAG.getNode(FrintOpc, DL, ContainerVT, Pg, Val,
+                            DAG.getPOISON(ContainerVT), Flags);
+
+  return VT.isFixedLengthVector() ? convertFromScalableVector(DAG, VT, Res)
+                                  : Res;
+}
+
+// Combine (sint_to_fp (fp_to_sint (x) )) to FRINT*X instructions
+static SDValue performFpToSIntToFPCombine(SDNode *N, SelectionDAG &DAG,
+                                          const AArch64Subtarget *Subtarget,
+                                          const AArch64TargetLowering &TLI) {
+  SDValue Op(N, 0);
+  assert(Op.getOpcode() == ISD::SINT_TO_FP && "Expected sint_to_fp combine");
+
+  EVT VT = Op.getValueType();
+  if (!VT.isVector())
+    return SDValue();
+
+  SDLoc DL(Op);
+  SDValue Src = Op.getOperand(0);
+  // Only combine if the first opcode is fp_to_sint with a single use
+  if (Src.getOpcode() != ISD::FP_TO_SINT || !Src.hasOneUse())
+    return SDValue();
+
+  SDValue FPSrc = Src.getOperand(0);
+  // The source FP type must match the result type
+  if (FPSrc.getValueType() != VT)
+    return SDValue();
+
+  unsigned IntBits = Src.getValueType().getVectorElementType().getSizeInBits();
+
+  if (VT.isFixedLengthVector() && Subtarget->isNeonAvailable() &&
+      Subtarget->hasFRInt3264()) {
+    if (SDValue Res =
+            performFpToSIntToFPCombineNEON(DAG, DL, VT, IntBits, FPSrc))
+      return Res;
+  }
+
+  if (Subtarget->isSVEorStreamingSVEAvailable() && Subtarget->hasSVE2p2()) {
+    if (VT.isScalableVector() ||
+        (VT.isFixedLengthVector() &&
+         TLI.useSVEForFixedLengthVectorVT(VT, !Subtarget->isNeonAvailable())))
+      return performFpToSIntToFPCombineSVE(DAG, DL, VT, IntBits, FPSrc,
+                                           Op->getFlags());
+  }
+
+  return SDValue();
+}
+
 // Given a tree of and/or(csel(0, 1, cc0), csel(0, 1, cc1)), we may be able to
 // convert to csel(ccmp(.., cc0)), depending on cc1:
 
@@ -29720,6 +29812,9 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
   case ISD::MUL:
     return performMulCombine(N, DAG, DCI, Subtarget);
   case ISD::SINT_TO_FP:
+    if (auto R = performFpToSIntToFPCombine(N, DAG, Subtarget, *this))
+      return R;
+    return performIntToFpCombine(N, DAG, DCI, Subtarget);
   case ISD::UINT_TO_FP:
     return performIntToFpCombine(N, DAG, DCI, Subtarget);
   case ISD::FP_TO_SINT:
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 9db82fa86348e..741e8855ff52d 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -5976,6 +5976,21 @@ let Predicates = [HasFRInt3264] in {
   defm FRINT64X : FRIntNNTVector<1, 1, "frint64x", int_aarch64_neon_frint64x>;
 } // HasFRInt3264
 
+let Predicates = [HasFRInt3264] in {
+  def : Pat<(v2f32 (sint_to_fp (v2i32 (fp_to_sint v2f32:$Rn)))),
+                      (FRINT32Zv2f32 V64:$Rn)>;
+  def : Pat<(v4f32 (sint_to_fp (v4i32 (fp_to_sint v4f32:$Rn)))),
+                      (FRINT32Zv4f32 V128:$Rn)>;
+  def : Pat<(v2f32 (sint_to_fp (v2i64 (fp_to_sint v2f32:$Rn)))),
+                      (FRINT64Zv2f32 V64:$Rn)>;
+  def : Pat<(v4f32 (sint_to_fp (v4i64 (fp_to_sint v4f32:$Rn)))),
+                      (FRINT64Zv4f32 V128:$Rn)>;
+  def : Pat<(v2f64 (sint_to_fp (v2i32 (fp_to_sint v2f64:$Rn)))),
+                      (FRINT32Zv2f64 V128:$Rn)>;
+  def : Pat<(v2f64 (sint_to_fp (v2i64 (fp_to_sint v2f64:$Rn)))),
+                      (FRINT64Zv2f64 V128:$Rn)>;
+}
+
 defm FRSQRTE: SIMDTwoVectorFP<1, 1, 0b11101, "frsqrte", int_aarch64_neon_frsqrte>;
 defm FSQRT  : SIMDTwoVectorFP<1, 1, 0b11111, "fsqrt", any_fsqrt>;
 defm NEG    : SIMDTwoVectorBHSD<1, 0b01011, "neg",
diff --git a/llvm/test/CodeGen/AArch64/neon-frintz.ll b/llvm/test/CodeGen/AArch64/neon-frintz.ll
new file mode 100644
index 0000000000000..f2c9640ad264f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/neon-frintz.ll
@@ -0,0 +1,70 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64-linux-gnu --mattr=+neon,+fptoint < %s | FileCheck %s
+
+; Check that fp -> int -> fp conversions can be
+; lowered to the NEON FRINT*Z instructions for
+; fixed vectors.
+
+; FRINT32Z
+
+define <2 x float> @frint32z_v2_f32_i32_f32(<2 x float> %in) {
+; CHECK-LABEL: frint32z_v2_f32_i32_f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    frint32z v0.2s, v0.2s
+; CHECK-NEXT:    ret
+    %res = fptosi <2 x float> %in to <2 x i32>
+    %res2 = sitofp <2 x i32> %res to <2 x float>
+    ret <2 x float> %res2
+}
+
+define <4 x float> @frint32z_v4_f32_i32_f32(<4 x float> %in) {
+; CHECK-LABEL: frint32z_v4_f32_i32_f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    frint32z v0.4s, v0.4s
+; CHECK-NEXT:    ret
+    %res = fptosi <4 x float> %in to <4 x i32>
+    %res2 = sitofp <4 x i32> %res to <4 x float>
+    ret <4 x float> %res2
+}
+
+define <2 x double> @frint32z_f64_i32_f64(<2 x double> %in) {
+; CHECK-LABEL: frint32z_f64_i32_f64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    frint32z v0.2d, v0.2d
+; CHECK-NEXT:    ret
+    %res = fptosi <2 x double> %in to <2 x i32>
+    %res2 = sitofp <2 x i32> %res to <2 x double>
+    ret <2 x double> %res2
+}
+
+; FRINT64Z
+
+define <2 x double> @frint64z_f64_i64_f64(<2 x double> %in) {
+; CHECK-LABEL: frint64z_f64_i64_f64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    frint64z v0.2d, v0.2d
+; CHECK-NEXT:    ret
+    %res = fptosi <2 x double> %in to <2 x i64>
+    %res2 = sitofp <2 x i64> %res to <2 x double>
+    ret <2 x double> %res2
+}
+
+define <2 x float> @frint64z_v2_f32_i64_f32(<2 x float> %in) {
+; CHECK-LABEL: frint64z_v2_f32_i64_f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    frint64z v0.2s, v0.2s
+; CHECK-NEXT:    ret
+    %res = fptosi <2 x float> %in to <2 x i64>
+    %res2 = sitofp <2 x i64> %res to <2 x float>
+    ret <2 x float> %res2
+}
+
+define <4 x float> @frint64z_v4_f32_i64_f32(<4 x float> %in) {
+; CHECK-LABEL: frint64z_v4_f32_i64_f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    frint64z v0.4s, v0.4s
+; CHECK-NEXT:    ret
+    %res = fptosi <4 x float> %in to <4 x i64>
+    %res2 = sitofp <4 x i64> %res to <4 x float>
+    ret <4 x float> %res2
+}
diff --git a/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll b/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll
new file mode 100644
index 0000000000000..e15781d29582b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll
@@ -0,0 +1,87 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2p2 -aarch64-sve-vector-bits-min=256 < %s | FileCheck %s
+
+; Check that fp -> int -> fp conversions can be
+; lowered to the SVE FRINT*Z instructions for
+; fixed vectors.
+
+; FRINT32Z
+
+define <8 x float> @frint32z_f32_i32_f32(<8 x float> %in) {
+; CHECK-LABEL: frint32z_f32_i32_f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
+; CHECK-NEXT:    ptrue p0.s, vl4
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
+; CHECK-NEXT:    splice z0.s, p0, { z0.s, z1.s }
+; CHECK-NEXT:    ptrue p0.s, vl8
+; CHECK-NEXT:    frint32z z0.s, p0/z, z0.s
+; CHECK-NEXT:    movprfx z1, z0
+; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z1
+; CHECK-NEXT:    ret
+    %res = fptosi <8 x float> %in to <8 x i32>
+    %res2 = sitofp <8 x i32> %res to <8 x float>
+    ret <8 x float> %res2
+}
+
+define <4 x double> @frint32z_f64_i32_f64(<4 x double> %in) {
+; CHECK-LABEL: frint32z_f64_i32_f64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
+; CHECK-NEXT:    ptrue p0.d, vl2
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
+; CHECK-NEXT:    splice z0.d, p0, { z0.d, z1.d }
+; CHECK-NEXT:    ptrue p0.d, vl4
+; CHECK-NEXT:    frint32z z0.d, p0/z, z0.d
+; CHECK-NEXT:    movprfx z1, z0
+; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z1
+; CHECK-NEXT:    ret
+    %res = fptosi <4 x double> %in to <4 x i32>
+    %res2 = sitofp <4 x i32> %res to <4 x double>
+    ret <4 x double> %res2
+}
+
+
+; FRINT64Z
+
+define <4 x double> @frint64z_f64_i64_f64(<4 x double> %in) {
+; CHECK-LABEL: frint64z_f64_i64_f64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
+; CHECK-NEXT:    ptrue p0.d, vl2
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
+; CHECK-NEXT:    splice z0.d, p0, { z0.d, z1.d }
+; CHECK-NEXT:    ptrue p0.d, vl4
+; CHECK-NEXT:    frint64z z0.d, p0/z, z0.d
+; CHECK-NEXT:    movprfx z1, z0
+; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z1
+; CHECK-NEXT:    ret
+    %res = fptosi <4 x double> %in to <4 x i64>
+    %res2 = sitofp <4 x i64> %res to <4 x double>
+    ret <4 x double> %res2
+}
+
+define <8 x float> @frint64z_f32_i64_f32(<8 x float> %in) {
+; CHECK-LABEL: frint64z_f32_i64_f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
+; CHECK-NEXT:    ptrue p0.s, vl4
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
+; CHECK-NEXT:    splice z0.s, p0, { z0.s, z1.s }
+; CHECK-NEXT:    ptrue p0.s, vl8
+; CHECK-NEXT:    frint64z z0.s, p0/z, z0.s
+; CHECK-NEXT:    movprfx z1, z0
+; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z1
+; CHECK-NEXT:    ret
+    %res = fptosi <8 x float> %in to <8 x i64>
+    %res2 = sitofp <8 x i64> %res to <8 x float>
+    ret <8 x float> %res2
+}
diff --git a/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll b/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
new file mode 100644
index 0000000000000..fb1c8e1a501d0
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
@@ -0,0 +1,57 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2p2 < %s | FileCheck %s
+
+; Check that fp -> int -> fp conversions can be
+; lowered to the SVE FRINT*Z instructions for
+; scalable vectors.
+
+; FRINT32Z
+
+define <vscale x 4 x float> @frint32z_f32_i32_f32(<vscale x 4 x float> %in) {
+; CHECK-LABEL: frint32z_f32_i32_f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.s
+; CHECK-NEXT:    frint32z z0.s, p0/z, z0.s
+; CHECK-NEXT:    ret
+    %res = fptosi <vscale x 4 x float> %in to <vscale x 4 x i32>
+    %res2 = sitofp <vscale x 4 x i32> %res to <vscale x 4 x float>
+    ret <vscale x 4 x float> %res2
+}
+
+define <vscale x 2 x double> @frint32z_f64_i32_f64(<vscale x 2 x double> %in) {
+; CHECK-LABEL: frint32z_f64_i32_f64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.d
+; CHECK-NEXT:    frint32z z0.d, p0/z, z0.d
+; CHECK-NEXT:    ret
+    %res = fptosi <vscale x 2 x double> %in to <vscale x 2 x i32>
+    %res2 = sitofp <vscale x 2 x i32> %res to <vscale x 2 x double>
+    ret <vscale x 2 x double> %res2
+}
+
+; FRINT64Z
+
+define <vscale x 2 x double> @frint64z_f64_i64_f64(<vscale x 2 x double> %in) {
+; CHECK-LABEL: frint64z_f64_i64_f64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.d
+; CHECK-NEXT:    frint64z z0.d, p0/z, z0.d
+; CHECK-NEXT:    ret
+    %res = fptosi <vscale x 2 x double> %in to <vscale x 2 x i64>
+    %res2 = sitofp <vscale x 2 x i64> %res to <vscale x 2 x double>
+    ret <vscale x 2 x double> %res2
+}
+
+define <vscale x 4 x float> @frint64z_f32_i64_f32(<vscale x 4 x float> %in) {
+; CHECK-LABEL: frint64z_f32_i64_f32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.s
+; CHECK-NEXT:    frint64z z0.s, p0/z, z0.s
+; CHECK-NEXT:    ret
+    %res = fptosi <vscale x 4 x float> %in to <vscale x 4 x i64>
+    %res2 = sitofp <vscale x 4 x i64> %res to <vscale x 4 x float>
+    ret <vscale x 4 x float> %res2
+}
+
+
+

>From d2b1787b1a4592232d7f2fc068dbf72b7b3f69dc Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Thu, 21 May 2026 09:16:05 +0000
Subject: [PATCH 2/9] rm neon pattern match

---
 llvm/lib/Target/AArch64/AArch64InstrInfo.td | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 741e8855ff52d..9db82fa86348e 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -5976,21 +5976,6 @@ let Predicates = [HasFRInt3264] in {
   defm FRINT64X : FRIntNNTVector<1, 1, "frint64x", int_aarch64_neon_frint64x>;
 } // HasFRInt3264
 
-let Predicates = [HasFRInt3264] in {
-  def : Pat<(v2f32 (sint_to_fp (v2i32 (fp_to_sint v2f32:$Rn)))),
-                      (FRINT32Zv2f32 V64:$Rn)>;
-  def : Pat<(v4f32 (sint_to_fp (v4i32 (fp_to_sint v4f32:$Rn)))),
-                      (FRINT32Zv4f32 V128:$Rn)>;
-  def : Pat<(v2f32 (sint_to_fp (v2i64 (fp_to_sint v2f32:$Rn)))),
-                      (FRINT64Zv2f32 V64:$Rn)>;
-  def : Pat<(v4f32 (sint_to_fp (v4i64 (fp_to_sint v4f32:$Rn)))),
-                      (FRINT64Zv4f32 V128:$Rn)>;
-  def : Pat<(v2f64 (sint_to_fp (v2i32 (fp_to_sint v2f64:$Rn)))),
-                      (FRINT32Zv2f64 V128:$Rn)>;
-  def : Pat<(v2f64 (sint_to_fp (v2i64 (fp_to_sint v2f64:$Rn)))),
-                      (FRINT64Zv2f64 V128:$Rn)>;
-}
-
 defm FRSQRTE: SIMDTwoVectorFP<1, 1, 0b11101, "frsqrte", int_aarch64_neon_frsqrte>;
 defm FSQRT  : SIMDTwoVectorFP<1, 1, 0b11111, "fsqrt", any_fsqrt>;
 defm NEG    : SIMDTwoVectorBHSD<1, 0b01011, "neg",

>From f0e8718ccac053f88938a0c3b871f1166f65ef00 Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Thu, 21 May 2026 10:04:41 +0000
Subject: [PATCH 3/9] fix up frintz combine for illegal sve vectors

---
 .../Target/AArch64/AArch64ISelLowering.cpp    | 13 ++++------
 llvm/test/CodeGen/AArch64/sve2p2-frintz.ll    | 26 +++++++++++++++++--
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index dd7ce2e6e75a8..58996debd00f4 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -21041,11 +21041,7 @@ static SDValue performFpToSIntToFPCombineNEON(SelectionDAG &DAG, SDLoc DL,
   else
     return SDValue();
 
-  auto IsNEONVT = [](EVT VT) {
-    return VT == MVT::v2f32 || VT == MVT::v4f32 || VT == MVT::v2f64;
-  };
-
-  if (!IsNEONVT(VT))
+  if (VT != MVT::v2f32 && VT != MVT::v4f32 && VT != MVT::v2f64)
     return SDValue();
 
   return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, VT,
@@ -21079,7 +21075,7 @@ static SDValue performFpToSIntToFPCombineSVE(SelectionDAG &DAG, SDLoc DL,
                                   : Res;
 }
 
-// Combine (sint_to_fp (fp_to_sint (x) )) to FRINT*X instructions
+// Combine (sint_to_fp (fp_to_sint (x) )) to FRINT*Z instructions
 static SDValue performFpToSIntToFPCombine(SDNode *N, SelectionDAG &DAG,
                                           const AArch64Subtarget *Subtarget,
                                           const AArch64TargetLowering &TLI) {
@@ -21110,8 +21106,9 @@ static SDValue performFpToSIntToFPCombine(SDNode *N, SelectionDAG &DAG,
       return Res;
   }
 
-  if (Subtarget->isSVEorStreamingSVEAvailable() && Subtarget->hasSVE2p2()) {
-    if (VT.isScalableVector() ||
+  if (Subtarget->isSVEorStreamingSVEAvailable() &&
+      (Subtarget->hasSVE2p2() || Subtarget->hasSME2p2())) {
+    if ((VT.isScalableVector() && TLI.isTypeLegal(VT)) ||
         (VT.isFixedLengthVector() &&
          TLI.useSVEForFixedLengthVectorVT(VT, !Subtarget->isNeonAvailable())))
       return performFpToSIntToFPCombineSVE(DAG, DL, VT, IntBits, FPSrc,
diff --git a/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll b/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
index fb1c8e1a501d0..9e18a9e05effb 100644
--- a/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
+++ b/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
@@ -29,6 +29,19 @@ define <vscale x 2 x double> @frint32z_f64_i32_f64(<vscale x 2 x double> %in) {
     ret <vscale x 2 x double> %res2
 }
 
+define <vscale x 8 x float> @frint32z_f32_i32_f32_nxv8i32(<vscale x 8 x float> %in) {
+; CHECK-LABEL: frint32z_f32_i32_f32_nxv8i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.s
+; CHECK-NEXT:    frint32z z0.s, p0/z, z0.s
+; CHECK-NEXT:    frint32z z1.s, p0/z, z1.s
+; CHECK-NEXT:    ret
+    %res = fptosi <vscale x 8 x float> %in to <vscale x 8 x i32>
+    %res2 = sitofp <vscale x 8 x i32> %res to <vscale x 8 x float>
+    ret <vscale x 8 x float> %res2
+}
+
+
 ; FRINT64Z
 
 define <vscale x 2 x double> @frint64z_f64_i64_f64(<vscale x 2 x double> %in) {
@@ -53,5 +66,14 @@ define <vscale x 4 x float> @frint64z_f32_i64_f32(<vscale x 4 x float> %in) {
     ret <vscale x 4 x float> %res2
 }
 
-
-
+define <vscale x 4 x double> @frint64z_f64_i64_f64_nxv4i64(<vscale x 4 x double> %in) {
+; CHECK-LABEL: frint64z_f64_i64_f64_nxv4i64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.d
+; CHECK-NEXT:    frint64z z0.d, p0/z, z0.d
+; CHECK-NEXT:    frint64z z1.d, p0/z, z1.d
+; CHECK-NEXT:    ret
+    %res = fptosi <vscale x 4 x double> %in to <vscale x 4 x i64>
+    %res2 = sitofp <vscale x 4 x i64> %res to <vscale x 4 x double>
+    ret <vscale x 4 x double> %res2
+}

>From b73f3ab4874081c6f771c00fc024ce8ccc461af1 Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Wed, 27 May 2026 15:11:31 +0000
Subject: [PATCH 4/9] Refactor to use frintz only when nsz is enabled

---
 .../Target/AArch64/AArch64ISelLowering.cpp    |  89 +++++----------
 llvm/test/CodeGen/AArch64/neon-frintz.ll      |  70 ------------
 .../AArch64/sve2p2-fixed-length-frintz.ll     |  33 +++---
 llvm/test/CodeGen/AArch64/sve2p2-frintz.ll    | 101 +++++++++++++-----
 4 files changed, 115 insertions(+), 178 deletions(-)
 delete mode 100644 llvm/test/CodeGen/AArch64/neon-frintz.ll

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 58996debd00f4..6f2f32d16b82f 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -21029,53 +21029,8 @@ static SDValue performFpToIntCombine(SDNode *N, SelectionDAG &DAG,
   return SDValue();
 }
 
-static SDValue performFpToSIntToFPCombineNEON(SelectionDAG &DAG, SDLoc DL,
-                                              EVT VT, unsigned int IntBits,
-                                              SDValue FPSrc) {
-  unsigned FrintOpc;
-
-  if (IntBits == 32)
-    FrintOpc = Intrinsic::aarch64_neon_frint32z;
-  else if (IntBits == 64)
-    FrintOpc = Intrinsic::aarch64_neon_frint64z;
-  else
-    return SDValue();
-
-  if (VT != MVT::v2f32 && VT != MVT::v4f32 && VT != MVT::v2f64)
-    return SDValue();
-
-  return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, VT,
-                     DAG.getTargetConstant(FrintOpc, DL, MVT::i64), FPSrc);
-}
-
-static SDValue performFpToSIntToFPCombineSVE(SelectionDAG &DAG, SDLoc DL,
-                                             EVT VT, unsigned int IntBits,
-                                             SDValue FPSrc, SDNodeFlags Flags) {
-  unsigned FrintOpc;
-
-  if (IntBits == 64)
-    FrintOpc = AArch64ISD::FTRUNC64_MERGE_PASSTHRU;
-  else if (IntBits == 32)
-    FrintOpc = AArch64ISD::FTRUNC32_MERGE_PASSTHRU;
-  else
-    return SDValue();
-
-  EVT ContainerVT =
-      VT.isFixedLengthVector() ? getContainerForFixedLengthVector(DAG, VT) : VT;
-
-  SDValue Pg = getPredicateForVector(DAG, DL, VT);
-  SDValue Val = VT.isFixedLengthVector()
-                    ? convertToScalableVector(DAG, ContainerVT, FPSrc)
-                    : FPSrc;
-
-  SDValue Res = DAG.getNode(FrintOpc, DL, ContainerVT, Pg, Val,
-                            DAG.getPOISON(ContainerVT), Flags);
-
-  return VT.isFixedLengthVector() ? convertFromScalableVector(DAG, VT, Res)
-                                  : Res;
-}
-
-// Combine (sint_to_fp (fp_to_sint (x) )) to FRINT*Z instructions
+// Combine (sint_to_fp (fp_to_sint (x) )) to FRINTZ instructions,
+// provided that signed zeros can be ignored.
 static SDValue performFpToSIntToFPCombine(SDNode *N, SelectionDAG &DAG,
                                           const AArch64Subtarget *Subtarget,
                                           const AArch64TargetLowering &TLI) {
@@ -21097,25 +21052,35 @@ static SDValue performFpToSIntToFPCombine(SDNode *N, SelectionDAG &DAG,
   if (FPSrc.getValueType() != VT)
     return SDValue();
 
+  if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
+      !DAG.canIgnoreSignBitOfZero(Op))
+    return SDValue();
+
   unsigned IntBits = Src.getValueType().getVectorElementType().getSizeInBits();
 
-  if (VT.isFixedLengthVector() && Subtarget->isNeonAvailable() &&
-      Subtarget->hasFRInt3264()) {
-    if (SDValue Res =
-            performFpToSIntToFPCombineNEON(DAG, DL, VT, IntBits, FPSrc))
-      return Res;
-  }
+  if (!Subtarget->isSVEorStreamingSVEAvailable() ||
+      !(Subtarget->hasSVE2p2() || Subtarget->hasSME2p2()))
+    return SDValue();
 
-  if (Subtarget->isSVEorStreamingSVEAvailable() &&
-      (Subtarget->hasSVE2p2() || Subtarget->hasSME2p2())) {
-    if ((VT.isScalableVector() && TLI.isTypeLegal(VT)) ||
-        (VT.isFixedLengthVector() &&
-         TLI.useSVEForFixedLengthVectorVT(VT, !Subtarget->isNeonAvailable())))
-      return performFpToSIntToFPCombineSVE(DAG, DL, VT, IntBits, FPSrc,
-                                           Op->getFlags());
-  }
+  if (!(VT.isScalableVector() && TLI.isTypeLegal(VT)) ||
+      !(VT.isFixedLengthVector() &&
+        TLI.useSVEForFixedLengthVectorVT(VT, !Subtarget->isNeonAvailable())))
+    return SDValue();
 
-  return SDValue();
+  EVT ContainerVT =
+      VT.isFixedLengthVector() ? getContainerForFixedLengthVector(DAG, VT) : VT;
+
+  SDValue Pg = getPredicateForVector(DAG, DL, VT);
+  SDValue Val = VT.isFixedLengthVector()
+                    ? convertToScalableVector(DAG, ContainerVT, FPSrc)
+                    : FPSrc;
+
+  SDValue Res =
+      DAG.getNode(AArch64ISD::FTRUNC_MERGE_PASSTHRU, DL, ContainerVT, Pg, Val,
+                  DAG.getPOISON(ContainerVT), Op->getFlags());
+
+  return VT.isFixedLengthVector() ? convertFromScalableVector(DAG, VT, Res)
+                                  : Res;
 }
 
 // Given a tree of and/or(csel(0, 1, cc0), csel(0, 1, cc1)), we may be able to
diff --git a/llvm/test/CodeGen/AArch64/neon-frintz.ll b/llvm/test/CodeGen/AArch64/neon-frintz.ll
deleted file mode 100644
index f2c9640ad264f..0000000000000
--- a/llvm/test/CodeGen/AArch64/neon-frintz.ll
+++ /dev/null
@@ -1,70 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=aarch64-linux-gnu --mattr=+neon,+fptoint < %s | FileCheck %s
-
-; Check that fp -> int -> fp conversions can be
-; lowered to the NEON FRINT*Z instructions for
-; fixed vectors.
-
-; FRINT32Z
-
-define <2 x float> @frint32z_v2_f32_i32_f32(<2 x float> %in) {
-; CHECK-LABEL: frint32z_v2_f32_i32_f32:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    frint32z v0.2s, v0.2s
-; CHECK-NEXT:    ret
-    %res = fptosi <2 x float> %in to <2 x i32>
-    %res2 = sitofp <2 x i32> %res to <2 x float>
-    ret <2 x float> %res2
-}
-
-define <4 x float> @frint32z_v4_f32_i32_f32(<4 x float> %in) {
-; CHECK-LABEL: frint32z_v4_f32_i32_f32:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    frint32z v0.4s, v0.4s
-; CHECK-NEXT:    ret
-    %res = fptosi <4 x float> %in to <4 x i32>
-    %res2 = sitofp <4 x i32> %res to <4 x float>
-    ret <4 x float> %res2
-}
-
-define <2 x double> @frint32z_f64_i32_f64(<2 x double> %in) {
-; CHECK-LABEL: frint32z_f64_i32_f64:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    frint32z v0.2d, v0.2d
-; CHECK-NEXT:    ret
-    %res = fptosi <2 x double> %in to <2 x i32>
-    %res2 = sitofp <2 x i32> %res to <2 x double>
-    ret <2 x double> %res2
-}
-
-; FRINT64Z
-
-define <2 x double> @frint64z_f64_i64_f64(<2 x double> %in) {
-; CHECK-LABEL: frint64z_f64_i64_f64:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    frint64z v0.2d, v0.2d
-; CHECK-NEXT:    ret
-    %res = fptosi <2 x double> %in to <2 x i64>
-    %res2 = sitofp <2 x i64> %res to <2 x double>
-    ret <2 x double> %res2
-}
-
-define <2 x float> @frint64z_v2_f32_i64_f32(<2 x float> %in) {
-; CHECK-LABEL: frint64z_v2_f32_i64_f32:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    frint64z v0.2s, v0.2s
-; CHECK-NEXT:    ret
-    %res = fptosi <2 x float> %in to <2 x i64>
-    %res2 = sitofp <2 x i64> %res to <2 x float>
-    ret <2 x float> %res2
-}
-
-define <4 x float> @frint64z_v4_f32_i64_f32(<4 x float> %in) {
-; CHECK-LABEL: frint64z_v4_f32_i64_f32:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    frint64z v0.4s, v0.4s
-; CHECK-NEXT:    ret
-    %res = fptosi <4 x float> %in to <4 x i64>
-    %res2 = sitofp <4 x i64> %res to <4 x float>
-    ret <4 x float> %res2
-}
diff --git a/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll b/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll
index e15781d29582b..bb4f06a637e87 100644
--- a/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll
+++ b/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll
@@ -1,21 +1,19 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2p2 -aarch64-sve-vector-bits-min=256 < %s | FileCheck %s
+; RUN: llc -mtriple=aarch64-linux-gnu --enable-no-signed-zeros-fp-math -mattr=+sve2p2 -aarch64-sve-vector-bits-min=256 < %s | FileCheck %s
 
 ; Check that fp -> int -> fp conversions can be
-; lowered to the SVE FRINT*Z instructions for
+; lowered to the SVE FRINTZ instructions for
 ; fixed vectors.
 
-; FRINT32Z
-
-define <8 x float> @frint32z_f32_i32_f32(<8 x float> %in) {
-; CHECK-LABEL: frint32z_f32_i32_f32:
+define <8 x float> @frintz_f32_i32_f32(<8 x float> %in) {
+; CHECK-LABEL: frintz_f32_i32_f32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    ptrue p0.s, vl4
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    splice z0.s, p0, { z0.s, z1.s }
 ; CHECK-NEXT:    ptrue p0.s, vl8
-; CHECK-NEXT:    frint32z z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
 ; CHECK-NEXT:    movprfx z1, z0
 ; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
@@ -26,15 +24,15 @@ define <8 x float> @frint32z_f32_i32_f32(<8 x float> %in) {
     ret <8 x float> %res2
 }
 
-define <4 x double> @frint32z_f64_i32_f64(<4 x double> %in) {
-; CHECK-LABEL: frint32z_f64_i32_f64:
+define <4 x double> @frintz_f64_i32_f64(<4 x double> %in) {
+; CHECK-LABEL: frintz_f64_i32_f64:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    ptrue p0.d, vl2
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    splice z0.d, p0, { z0.d, z1.d }
 ; CHECK-NEXT:    ptrue p0.d, vl4
-; CHECK-NEXT:    frint32z z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
 ; CHECK-NEXT:    movprfx z1, z0
 ; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
@@ -45,18 +43,15 @@ define <4 x double> @frint32z_f64_i32_f64(<4 x double> %in) {
     ret <4 x double> %res2
 }
 
-
-; FRINT64Z
-
-define <4 x double> @frint64z_f64_i64_f64(<4 x double> %in) {
-; CHECK-LABEL: frint64z_f64_i64_f64:
+define <4 x double> @frintz_f64_i64_f64(<4 x double> %in) {
+; CHECK-LABEL: frintz_f64_i64_f64:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    ptrue p0.d, vl2
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    splice z0.d, p0, { z0.d, z1.d }
 ; CHECK-NEXT:    ptrue p0.d, vl4
-; CHECK-NEXT:    frint64z z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
 ; CHECK-NEXT:    movprfx z1, z0
 ; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
@@ -67,15 +62,15 @@ define <4 x double> @frint64z_f64_i64_f64(<4 x double> %in) {
     ret <4 x double> %res2
 }
 
-define <8 x float> @frint64z_f32_i64_f32(<8 x float> %in) {
-; CHECK-LABEL: frint64z_f32_i64_f32:
+define <8 x float> @frintz_f32_i64_f32(<8 x float> %in) {
+; CHECK-LABEL: frintz_f32_i64_f32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    ptrue p0.s, vl4
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    splice z0.s, p0, { z0.s, z1.s }
 ; CHECK-NEXT:    ptrue p0.s, vl8
-; CHECK-NEXT:    frint64z z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
 ; CHECK-NEXT:    movprfx z1, z0
 ; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
diff --git a/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll b/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
index 9e18a9e05effb..98f946b8e90b8 100644
--- a/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
+++ b/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
@@ -1,78 +1,125 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2p2 < %s | FileCheck %s
+; RUN: llc -mtriple=aarch64-linux-gnu --enable-no-signed-zeros-fp-math -mattr=+sve2p2 < %s | FileCheck %s
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2p2 < %s | FileCheck %s --check-prefix=SIGNED-ZEROS
 
 ; Check that fp -> int -> fp conversions can be
-; lowered to the SVE FRINT*Z instructions for
+; lowered to the SVE FRINTZ instructions for
 ; scalable vectors.
 
-; FRINT32Z
-
-define <vscale x 4 x float> @frint32z_f32_i32_f32(<vscale x 4 x float> %in) {
-; CHECK-LABEL: frint32z_f32_i32_f32:
+define <vscale x 4 x float> @frintz_f32_i32_f32(<vscale x 4 x float> %in) {
+; CHECK-LABEL: frintz_f32_i32_f32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.s
-; CHECK-NEXT:    frint32z z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
 ; CHECK-NEXT:    ret
+;
+; SIGNED-ZEROS-LABEL: frintz_f32_i32_f32:
+; SIGNED-ZEROS:       // %bb.0:
+; SIGNED-ZEROS-NEXT:    ptrue p0.s
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.s, p0/z, z0.s
+; SIGNED-ZEROS-NEXT:    scvtf z0.s, p0/z, z0.s
+; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 4 x float> %in to <vscale x 4 x i32>
     %res2 = sitofp <vscale x 4 x i32> %res to <vscale x 4 x float>
     ret <vscale x 4 x float> %res2
 }
 
-define <vscale x 2 x double> @frint32z_f64_i32_f64(<vscale x 2 x double> %in) {
-; CHECK-LABEL: frint32z_f64_i32_f64:
+define <vscale x 2 x double> @frintz_f64_i32_f64(<vscale x 2 x double> %in) {
+; CHECK-LABEL: frintz_f64_i32_f64:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.d
-; CHECK-NEXT:    frint32z z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
 ; CHECK-NEXT:    ret
+;
+; SIGNED-ZEROS-LABEL: frintz_f64_i32_f64:
+; SIGNED-ZEROS:       // %bb.0:
+; SIGNED-ZEROS-NEXT:    ptrue p0.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/z, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/z, z0.d
+; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 2 x double> %in to <vscale x 2 x i32>
     %res2 = sitofp <vscale x 2 x i32> %res to <vscale x 2 x double>
     ret <vscale x 2 x double> %res2
 }
 
-define <vscale x 8 x float> @frint32z_f32_i32_f32_nxv8i32(<vscale x 8 x float> %in) {
-; CHECK-LABEL: frint32z_f32_i32_f32_nxv8i32:
+define <vscale x 8 x float> @frintz_f32_i32_f32_nxv8i32(<vscale x 8 x float> %in) {
+; CHECK-LABEL: frintz_f32_i32_f32_nxv8i32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.s
-; CHECK-NEXT:    frint32z z0.s, p0/z, z0.s
-; CHECK-NEXT:    frint32z z1.s, p0/z, z1.s
+; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z1.s, p0/z, z1.s
 ; CHECK-NEXT:    ret
+;
+; SIGNED-ZEROS-LABEL: frintz_f32_i32_f32_nxv8i32:
+; SIGNED-ZEROS:       // %bb.0:
+; SIGNED-ZEROS-NEXT:    ptrue p0.s
+; SIGNED-ZEROS-NEXT:    fcvtzs z1.s, p0/z, z1.s
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.s, p0/z, z0.s
+; SIGNED-ZEROS-NEXT:    scvtf z0.s, p0/z, z0.s
+; SIGNED-ZEROS-NEXT:    scvtf z1.s, p0/z, z1.s
+; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 8 x float> %in to <vscale x 8 x i32>
     %res2 = sitofp <vscale x 8 x i32> %res to <vscale x 8 x float>
     ret <vscale x 8 x float> %res2
 }
 
-
-; FRINT64Z
-
-define <vscale x 2 x double> @frint64z_f64_i64_f64(<vscale x 2 x double> %in) {
-; CHECK-LABEL: frint64z_f64_i64_f64:
+define <vscale x 2 x double> @frintz_f64_i64_f64(<vscale x 2 x double> %in) {
+; CHECK-LABEL: frintz_f64_i64_f64:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.d
-; CHECK-NEXT:    frint64z z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
 ; CHECK-NEXT:    ret
+;
+; SIGNED-ZEROS-LABEL: frintz_f64_i64_f64:
+; SIGNED-ZEROS:       // %bb.0:
+; SIGNED-ZEROS-NEXT:    ptrue p0.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/z, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/z, z0.d
+; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 2 x double> %in to <vscale x 2 x i64>
     %res2 = sitofp <vscale x 2 x i64> %res to <vscale x 2 x double>
     ret <vscale x 2 x double> %res2
 }
 
-define <vscale x 4 x float> @frint64z_f32_i64_f32(<vscale x 4 x float> %in) {
-; CHECK-LABEL: frint64z_f32_i64_f32:
+define <vscale x 4 x float> @frintz_f32_i64_f32(<vscale x 4 x float> %in) {
+; CHECK-LABEL: frintz_f32_i64_f32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.s
-; CHECK-NEXT:    frint64z z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
 ; CHECK-NEXT:    ret
+;
+; SIGNED-ZEROS-LABEL: frintz_f32_i64_f32:
+; SIGNED-ZEROS:       // %bb.0:
+; SIGNED-ZEROS-NEXT:    uunpklo z1.d, z0.s
+; SIGNED-ZEROS-NEXT:    uunpkhi z0.d, z0.s
+; SIGNED-ZEROS-NEXT:    ptrue p0.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z1.d, p0/m, z1.s
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/m, z0.s
+; SIGNED-ZEROS-NEXT:    scvtf z0.s, p0/m, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z1.s, p0/m, z1.d
+; SIGNED-ZEROS-NEXT:    uzp1 z0.s, z1.s, z0.s
+; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 4 x float> %in to <vscale x 4 x i64>
     %res2 = sitofp <vscale x 4 x i64> %res to <vscale x 4 x float>
     ret <vscale x 4 x float> %res2
 }
 
-define <vscale x 4 x double> @frint64z_f64_i64_f64_nxv4i64(<vscale x 4 x double> %in) {
-; CHECK-LABEL: frint64z_f64_i64_f64_nxv4i64:
+define <vscale x 4 x double> @frintz_f64_i64_f64_nxv4i64(<vscale x 4 x double> %in) {
+; CHECK-LABEL: frintz_f64_i64_f64_nxv4i64:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.d
-; CHECK-NEXT:    frint64z z0.d, p0/z, z0.d
-; CHECK-NEXT:    frint64z z1.d, p0/z, z1.d
+; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z1.d, p0/z, z1.d
 ; CHECK-NEXT:    ret
+;
+; SIGNED-ZEROS-LABEL: frintz_f64_i64_f64_nxv4i64:
+; SIGNED-ZEROS:       // %bb.0:
+; SIGNED-ZEROS-NEXT:    ptrue p0.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z1.d, p0/z, z1.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/z, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/z, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z1.d, p0/z, z1.d
+; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 4 x double> %in to <vscale x 4 x i64>
     %res2 = sitofp <vscale x 4 x i64> %res to <vscale x 4 x double>
     ret <vscale x 4 x double> %res2

>From 13140a8940933e6561ba9527219669a28985ce3d Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Wed, 27 May 2026 15:45:14 +0000
Subject: [PATCH 5/9] rm unused IntBits variable

---
 llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 6f2f32d16b82f..6ed87782587a9 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -21056,8 +21056,6 @@ static SDValue performFpToSIntToFPCombine(SDNode *N, SelectionDAG &DAG,
       !DAG.canIgnoreSignBitOfZero(Op))
     return SDValue();
 
-  unsigned IntBits = Src.getValueType().getVectorElementType().getSizeInBits();
-
   if (!Subtarget->isSVEorStreamingSVEAvailable() ||
       !(Subtarget->hasSVE2p2() || Subtarget->hasSME2p2()))
     return SDValue();

>From 7a9a80b94914e52d99f043b57ece280d707d9bb8 Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Thu, 28 May 2026 09:49:07 +0000
Subject: [PATCH 6/9] Use foldFPToIntToFP to lower to frintz

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  2 +-
 .../Target/AArch64/AArch64ISelLowering.cpp    | 54 -------------------
 ...h-frintz.ll => sve-fixed-length-frintz.ll} | 38 ++++++-------
 .../{sve2p2-frintz.ll => sve-frintz.ll}       | 48 ++++++++---------
 4 files changed, 44 insertions(+), 98 deletions(-)
 rename llvm/test/CodeGen/AArch64/{sve2p2-fixed-length-frintz.ll => sve-fixed-length-frintz.ll} (68%)
 rename llvm/test/CodeGen/AArch64/{sve2p2-frintz.ll => sve-frintz.ll} (76%)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 2a9ecebeb1508..eca182010db21 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -19959,7 +19959,7 @@ static SDValue foldFPToIntToFP(SDNode *N, const SDLoc &DL, SelectionDAG &DAG,
 
   // FIXME: We should be able to use node-level FMF here.
   EVT VT = N->getValueType(0);
-  if (!TLI.isOperationLegal(ISD::FTRUNC, VT))
+  if (!TLI.isOperationLegalOrCustom(ISD::FTRUNC, VT))
     return SDValue();
 
   bool IsUnsigned = N->getOpcode() == ISD::UINT_TO_FP;
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 6ed87782587a9..533cf33030ef4 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -21029,58 +21029,6 @@ static SDValue performFpToIntCombine(SDNode *N, SelectionDAG &DAG,
   return SDValue();
 }
 
-// Combine (sint_to_fp (fp_to_sint (x) )) to FRINTZ instructions,
-// provided that signed zeros can be ignored.
-static SDValue performFpToSIntToFPCombine(SDNode *N, SelectionDAG &DAG,
-                                          const AArch64Subtarget *Subtarget,
-                                          const AArch64TargetLowering &TLI) {
-  SDValue Op(N, 0);
-  assert(Op.getOpcode() == ISD::SINT_TO_FP && "Expected sint_to_fp combine");
-
-  EVT VT = Op.getValueType();
-  if (!VT.isVector())
-    return SDValue();
-
-  SDLoc DL(Op);
-  SDValue Src = Op.getOperand(0);
-  // Only combine if the first opcode is fp_to_sint with a single use
-  if (Src.getOpcode() != ISD::FP_TO_SINT || !Src.hasOneUse())
-    return SDValue();
-
-  SDValue FPSrc = Src.getOperand(0);
-  // The source FP type must match the result type
-  if (FPSrc.getValueType() != VT)
-    return SDValue();
-
-  if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
-      !DAG.canIgnoreSignBitOfZero(Op))
-    return SDValue();
-
-  if (!Subtarget->isSVEorStreamingSVEAvailable() ||
-      !(Subtarget->hasSVE2p2() || Subtarget->hasSME2p2()))
-    return SDValue();
-
-  if (!(VT.isScalableVector() && TLI.isTypeLegal(VT)) ||
-      !(VT.isFixedLengthVector() &&
-        TLI.useSVEForFixedLengthVectorVT(VT, !Subtarget->isNeonAvailable())))
-    return SDValue();
-
-  EVT ContainerVT =
-      VT.isFixedLengthVector() ? getContainerForFixedLengthVector(DAG, VT) : VT;
-
-  SDValue Pg = getPredicateForVector(DAG, DL, VT);
-  SDValue Val = VT.isFixedLengthVector()
-                    ? convertToScalableVector(DAG, ContainerVT, FPSrc)
-                    : FPSrc;
-
-  SDValue Res =
-      DAG.getNode(AArch64ISD::FTRUNC_MERGE_PASSTHRU, DL, ContainerVT, Pg, Val,
-                  DAG.getPOISON(ContainerVT), Op->getFlags());
-
-  return VT.isFixedLengthVector() ? convertFromScalableVector(DAG, VT, Res)
-                                  : Res;
-}
-
 // Given a tree of and/or(csel(0, 1, cc0), csel(0, 1, cc1)), we may be able to
 // convert to csel(ccmp(.., cc0)), depending on cc1:
 
@@ -29772,8 +29720,6 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
   case ISD::MUL:
     return performMulCombine(N, DAG, DCI, Subtarget);
   case ISD::SINT_TO_FP:
-    if (auto R = performFpToSIntToFPCombine(N, DAG, Subtarget, *this))
-      return R;
     return performIntToFpCombine(N, DAG, DCI, Subtarget);
   case ISD::UINT_TO_FP:
     return performIntToFpCombine(N, DAG, DCI, Subtarget);
diff --git a/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-frintz.ll
similarity index 68%
rename from llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll
rename to llvm/test/CodeGen/AArch64/sve-fixed-length-frintz.ll
index bb4f06a637e87..5a34728b8d596 100644
--- a/llvm/test/CodeGen/AArch64/sve2p2-fixed-length-frintz.ll
+++ b/llvm/test/CodeGen/AArch64/sve-fixed-length-frintz.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=aarch64-linux-gnu --enable-no-signed-zeros-fp-math -mattr=+sve2p2 -aarch64-sve-vector-bits-min=256 < %s | FileCheck %s
+; RUN: llc -mtriple=aarch64-linux-gnu --enable-no-signed-zeros-fp-math -mattr=+sve -aarch64-sve-vector-bits-min=256 < %s | FileCheck %s
 
 ; Check that fp -> int -> fp conversions can be
 ; lowered to the SVE FRINTZ instructions for
@@ -8,12 +8,12 @@
 define <8 x float> @frintz_f32_i32_f32(<8 x float> %in) {
 ; CHECK-LABEL: frintz_f32_i32_f32:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
-; CHECK-NEXT:    ptrue p0.s, vl4
-; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
-; CHECK-NEXT:    splice z0.s, p0, { z0.s, z1.s }
+; CHECK-NEXT:    ptrue p0.d, vl2
+; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
+; CHECK-NEXT:    // kill: def $q1 killed $q1 def $z1
+; CHECK-NEXT:    splice z0.d, p0, z0.d, z1.d
 ; CHECK-NEXT:    ptrue p0.s, vl8
-; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z0.s, p0/m, z0.s
 ; CHECK-NEXT:    movprfx z1, z0
 ; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
@@ -27,12 +27,12 @@ define <8 x float> @frintz_f32_i32_f32(<8 x float> %in) {
 define <4 x double> @frintz_f64_i32_f64(<4 x double> %in) {
 ; CHECK-LABEL: frintz_f64_i32_f64:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    ptrue p0.d, vl2
-; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
-; CHECK-NEXT:    splice z0.d, p0, { z0.d, z1.d }
+; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
+; CHECK-NEXT:    // kill: def $q1 killed $q1 def $z1
+; CHECK-NEXT:    splice z0.d, p0, z0.d, z1.d
 ; CHECK-NEXT:    ptrue p0.d, vl4
-; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z0.d, p0/m, z0.d
 ; CHECK-NEXT:    movprfx z1, z0
 ; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
@@ -46,12 +46,12 @@ define <4 x double> @frintz_f64_i32_f64(<4 x double> %in) {
 define <4 x double> @frintz_f64_i64_f64(<4 x double> %in) {
 ; CHECK-LABEL: frintz_f64_i64_f64:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
 ; CHECK-NEXT:    ptrue p0.d, vl2
-; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
-; CHECK-NEXT:    splice z0.d, p0, { z0.d, z1.d }
+; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
+; CHECK-NEXT:    // kill: def $q1 killed $q1 def $z1
+; CHECK-NEXT:    splice z0.d, p0, z0.d, z1.d
 ; CHECK-NEXT:    ptrue p0.d, vl4
-; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z0.d, p0/m, z0.d
 ; CHECK-NEXT:    movprfx z1, z0
 ; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
@@ -65,12 +65,12 @@ define <4 x double> @frintz_f64_i64_f64(<4 x double> %in) {
 define <8 x float> @frintz_f32_i64_f32(<8 x float> %in) {
 ; CHECK-LABEL: frintz_f32_i64_f32:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    // kill: def $q1 killed $q1 killed $z0_z1 def $z0_z1
-; CHECK-NEXT:    ptrue p0.s, vl4
-; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0_z1 def $z0_z1
-; CHECK-NEXT:    splice z0.s, p0, { z0.s, z1.s }
+; CHECK-NEXT:    ptrue p0.d, vl2
+; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
+; CHECK-NEXT:    // kill: def $q1 killed $q1 def $z1
+; CHECK-NEXT:    splice z0.d, p0, z0.d, z1.d
 ; CHECK-NEXT:    ptrue p0.s, vl8
-; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z0.s, p0/m, z0.s
 ; CHECK-NEXT:    movprfx z1, z0
 ; CHECK-NEXT:    ext z1.b, z1.b, z0.b, #16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
diff --git a/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll b/llvm/test/CodeGen/AArch64/sve-frintz.ll
similarity index 76%
rename from llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
rename to llvm/test/CodeGen/AArch64/sve-frintz.ll
index 98f946b8e90b8..45dcc500de8c5 100644
--- a/llvm/test/CodeGen/AArch64/sve2p2-frintz.ll
+++ b/llvm/test/CodeGen/AArch64/sve-frintz.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=aarch64-linux-gnu --enable-no-signed-zeros-fp-math -mattr=+sve2p2 < %s | FileCheck %s
-; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2p2 < %s | FileCheck %s --check-prefix=SIGNED-ZEROS
+; RUN: llc -mtriple=aarch64-linux-gnu --enable-no-signed-zeros-fp-math -mattr=+sve < %s | FileCheck %s
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve < %s | FileCheck %s --check-prefix=SIGNED-ZEROS
 
 ; Check that fp -> int -> fp conversions can be
 ; lowered to the SVE FRINTZ instructions for
@@ -10,14 +10,14 @@ define <vscale x 4 x float> @frintz_f32_i32_f32(<vscale x 4 x float> %in) {
 ; CHECK-LABEL: frintz_f32_i32_f32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.s
-; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z0.s, p0/m, z0.s
 ; CHECK-NEXT:    ret
 ;
 ; SIGNED-ZEROS-LABEL: frintz_f32_i32_f32:
 ; SIGNED-ZEROS:       // %bb.0:
 ; SIGNED-ZEROS-NEXT:    ptrue p0.s
-; SIGNED-ZEROS-NEXT:    fcvtzs z0.s, p0/z, z0.s
-; SIGNED-ZEROS-NEXT:    scvtf z0.s, p0/z, z0.s
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.s, p0/m, z0.s
+; SIGNED-ZEROS-NEXT:    scvtf z0.s, p0/m, z0.s
 ; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 4 x float> %in to <vscale x 4 x i32>
     %res2 = sitofp <vscale x 4 x i32> %res to <vscale x 4 x float>
@@ -28,14 +28,14 @@ define <vscale x 2 x double> @frintz_f64_i32_f64(<vscale x 2 x double> %in) {
 ; CHECK-LABEL: frintz_f64_i32_f64:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.d
-; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z0.d, p0/m, z0.d
 ; CHECK-NEXT:    ret
 ;
 ; SIGNED-ZEROS-LABEL: frintz_f64_i32_f64:
 ; SIGNED-ZEROS:       // %bb.0:
 ; SIGNED-ZEROS-NEXT:    ptrue p0.d
-; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/z, z0.d
-; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/z, z0.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/m, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/m, z0.d
 ; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 2 x double> %in to <vscale x 2 x i32>
     %res2 = sitofp <vscale x 2 x i32> %res to <vscale x 2 x double>
@@ -46,17 +46,17 @@ define <vscale x 8 x float> @frintz_f32_i32_f32_nxv8i32(<vscale x 8 x float> %in
 ; CHECK-LABEL: frintz_f32_i32_f32_nxv8i32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.s
-; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
-; CHECK-NEXT:    frintz z1.s, p0/z, z1.s
+; CHECK-NEXT:    frintz z0.s, p0/m, z0.s
+; CHECK-NEXT:    frintz z1.s, p0/m, z1.s
 ; CHECK-NEXT:    ret
 ;
 ; SIGNED-ZEROS-LABEL: frintz_f32_i32_f32_nxv8i32:
 ; SIGNED-ZEROS:       // %bb.0:
 ; SIGNED-ZEROS-NEXT:    ptrue p0.s
-; SIGNED-ZEROS-NEXT:    fcvtzs z1.s, p0/z, z1.s
-; SIGNED-ZEROS-NEXT:    fcvtzs z0.s, p0/z, z0.s
-; SIGNED-ZEROS-NEXT:    scvtf z0.s, p0/z, z0.s
-; SIGNED-ZEROS-NEXT:    scvtf z1.s, p0/z, z1.s
+; SIGNED-ZEROS-NEXT:    fcvtzs z1.s, p0/m, z1.s
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.s, p0/m, z0.s
+; SIGNED-ZEROS-NEXT:    scvtf z0.s, p0/m, z0.s
+; SIGNED-ZEROS-NEXT:    scvtf z1.s, p0/m, z1.s
 ; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 8 x float> %in to <vscale x 8 x i32>
     %res2 = sitofp <vscale x 8 x i32> %res to <vscale x 8 x float>
@@ -67,14 +67,14 @@ define <vscale x 2 x double> @frintz_f64_i64_f64(<vscale x 2 x double> %in) {
 ; CHECK-LABEL: frintz_f64_i64_f64:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.d
-; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
+; CHECK-NEXT:    frintz z0.d, p0/m, z0.d
 ; CHECK-NEXT:    ret
 ;
 ; SIGNED-ZEROS-LABEL: frintz_f64_i64_f64:
 ; SIGNED-ZEROS:       // %bb.0:
 ; SIGNED-ZEROS-NEXT:    ptrue p0.d
-; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/z, z0.d
-; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/z, z0.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/m, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/m, z0.d
 ; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 2 x double> %in to <vscale x 2 x i64>
     %res2 = sitofp <vscale x 2 x i64> %res to <vscale x 2 x double>
@@ -85,7 +85,7 @@ define <vscale x 4 x float> @frintz_f32_i64_f32(<vscale x 4 x float> %in) {
 ; CHECK-LABEL: frintz_f32_i64_f32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.s
-; CHECK-NEXT:    frintz z0.s, p0/z, z0.s
+; CHECK-NEXT:    frintz z0.s, p0/m, z0.s
 ; CHECK-NEXT:    ret
 ;
 ; SIGNED-ZEROS-LABEL: frintz_f32_i64_f32:
@@ -108,17 +108,17 @@ define <vscale x 4 x double> @frintz_f64_i64_f64_nxv4i64(<vscale x 4 x double> %
 ; CHECK-LABEL: frintz_f64_i64_f64_nxv4i64:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.d
-; CHECK-NEXT:    frintz z0.d, p0/z, z0.d
-; CHECK-NEXT:    frintz z1.d, p0/z, z1.d
+; CHECK-NEXT:    frintz z0.d, p0/m, z0.d
+; CHECK-NEXT:    frintz z1.d, p0/m, z1.d
 ; CHECK-NEXT:    ret
 ;
 ; SIGNED-ZEROS-LABEL: frintz_f64_i64_f64_nxv4i64:
 ; SIGNED-ZEROS:       // %bb.0:
 ; SIGNED-ZEROS-NEXT:    ptrue p0.d
-; SIGNED-ZEROS-NEXT:    fcvtzs z1.d, p0/z, z1.d
-; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/z, z0.d
-; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/z, z0.d
-; SIGNED-ZEROS-NEXT:    scvtf z1.d, p0/z, z1.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z1.d, p0/m, z1.d
+; SIGNED-ZEROS-NEXT:    fcvtzs z0.d, p0/m, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z0.d, p0/m, z0.d
+; SIGNED-ZEROS-NEXT:    scvtf z1.d, p0/m, z1.d
 ; SIGNED-ZEROS-NEXT:    ret
     %res = fptosi <vscale x 4 x double> %in to <vscale x 4 x i64>
     %res2 = sitofp <vscale x 4 x i64> %res to <vscale x 4 x double>

>From 14415edf0baaf69987de76d2d01a22c5f15ad05f Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Thu, 28 May 2026 10:06:34 +0000
Subject: [PATCH 7/9] restore fallback for SINT_TO_FP case

---
 llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 533cf33030ef4..710ca7fcba756 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -29720,7 +29720,6 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
   case ISD::MUL:
     return performMulCombine(N, DAG, DCI, Subtarget);
   case ISD::SINT_TO_FP:
-    return performIntToFpCombine(N, DAG, DCI, Subtarget);
   case ISD::UINT_TO_FP:
     return performIntToFpCombine(N, DAG, DCI, Subtarget);
   case ISD::FP_TO_SINT:

>From 97d07e25421f198d94645d044fbc17ccd72b26c8 Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Thu, 28 May 2026 13:04:10 +0000
Subject: [PATCH 8/9] update amdgpu test

---
 llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll | 101 ++++++++++++----------
 1 file changed, 56 insertions(+), 45 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll b/llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll
index 49204f84acb85..59f3473cae919 100644
--- a/llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll
+++ b/llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll
@@ -184,12 +184,27 @@ define amdgpu_kernel void @fptoui_f64_to_i16_to_f64(ptr addrspace(1) %out, doubl
 ; GFX6-LABEL: fptoui_f64_to_i16_to_f64:
 ; GFX6:       ; %bb.0: ; %entry
 ; GFX6-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; GFX6-NEXT:    s_mov_b32 s6, -1
+; GFX6-NEXT:    s_mov_b32 s7, 0xf000
 ; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
-; GFX6-NEXT:    v_cvt_u32_f64_e32 v0, s[2:3]
-; GFX6-NEXT:    s_mov_b32 s3, 0xf000
-; GFX6-NEXT:    s_mov_b32 s2, -1
-; GFX6-NEXT:    v_cvt_f64_u32_e32 v[0:1], v0
-; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[0:3], 0
+; GFX6-NEXT:    s_bitset0_b32 s3, 31
+; GFX6-NEXT:    s_mov_b32 s4, s0
+; GFX6-NEXT:    s_bfe_u32 s0, s3, 0xb0014
+; GFX6-NEXT:    s_mov_b32 s5, s1
+; GFX6-NEXT:    s_add_i32 s8, s0, 0xfffffc01
+; GFX6-NEXT:    s_mov_b32 s1, 0xfffff
+; GFX6-NEXT:    s_mov_b32 s0, s6
+; GFX6-NEXT:    s_lshr_b64 s[0:1], s[0:1], s8
+; GFX6-NEXT:    s_andn2_b64 s[0:1], s[2:3], s[0:1]
+; GFX6-NEXT:    s_cmp_lt_i32 s8, 0
+; GFX6-NEXT:    s_cselect_b32 s0, 0, s0
+; GFX6-NEXT:    s_cselect_b32 s1, 0, s1
+; GFX6-NEXT:    s_cmp_gt_i32 s8, 51
+; GFX6-NEXT:    s_cselect_b32 s1, s3, s1
+; GFX6-NEXT:    s_cselect_b32 s0, s2, s0
+; GFX6-NEXT:    v_mov_b32_e32 v0, s0
+; GFX6-NEXT:    v_mov_b32_e32 v1, s1
+; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[4:7], 0
 ; GFX6-NEXT:    s_endpgm
 ;
 ; GFX9-LABEL: fptoui_f64_to_i16_to_f64:
@@ -211,12 +226,27 @@ define amdgpu_kernel void @fptoui_f64_to_i32_to_f64(ptr addrspace(1) %out, doubl
 ; GFX6-LABEL: fptoui_f64_to_i32_to_f64:
 ; GFX6:       ; %bb.0: ; %entry
 ; GFX6-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; GFX6-NEXT:    s_mov_b32 s6, -1
+; GFX6-NEXT:    s_mov_b32 s7, 0xf000
 ; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
-; GFX6-NEXT:    v_cvt_u32_f64_e32 v0, s[2:3]
-; GFX6-NEXT:    s_mov_b32 s3, 0xf000
-; GFX6-NEXT:    s_mov_b32 s2, -1
-; GFX6-NEXT:    v_cvt_f64_u32_e32 v[0:1], v0
-; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[0:3], 0
+; GFX6-NEXT:    s_bitset0_b32 s3, 31
+; GFX6-NEXT:    s_mov_b32 s4, s0
+; GFX6-NEXT:    s_bfe_u32 s0, s3, 0xb0014
+; GFX6-NEXT:    s_mov_b32 s5, s1
+; GFX6-NEXT:    s_add_i32 s8, s0, 0xfffffc01
+; GFX6-NEXT:    s_mov_b32 s1, 0xfffff
+; GFX6-NEXT:    s_mov_b32 s0, s6
+; GFX6-NEXT:    s_lshr_b64 s[0:1], s[0:1], s8
+; GFX6-NEXT:    s_andn2_b64 s[0:1], s[2:3], s[0:1]
+; GFX6-NEXT:    s_cmp_lt_i32 s8, 0
+; GFX6-NEXT:    s_cselect_b32 s0, 0, s0
+; GFX6-NEXT:    s_cselect_b32 s1, 0, s1
+; GFX6-NEXT:    s_cmp_gt_i32 s8, 51
+; GFX6-NEXT:    s_cselect_b32 s1, s3, s1
+; GFX6-NEXT:    s_cselect_b32 s0, s2, s0
+; GFX6-NEXT:    v_mov_b32_e32 v0, s0
+; GFX6-NEXT:    v_mov_b32_e32 v1, s1
+; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[4:7], 0
 ; GFX6-NEXT:    s_endpgm
 ;
 ; GFX9-LABEL: fptoui_f64_to_i32_to_f64:
@@ -239,44 +269,25 @@ define amdgpu_kernel void @fptoui_f64_to_i64_to_f64(ptr addrspace(1) %out, doubl
 ; GFX6:       ; %bb.0: ; %entry
 ; GFX6-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
 ; GFX6-NEXT:    s_mov_b32 s6, -1
-; GFX6-NEXT:    s_mov_b32 s5, 0xfffff
-; GFX6-NEXT:    s_mov_b32 s4, s6
-; GFX6-NEXT:    v_not_b32_e32 v0, 31
-; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
-; GFX6-NEXT:    s_bfe_u32 s7, s3, 0xb0014
-; GFX6-NEXT:    s_addk_i32 s7, 0xfc01
-; GFX6-NEXT:    s_lshr_b64 s[4:5], s[4:5], s7
-; GFX6-NEXT:    s_and_b32 s8, s3, 0x80000000
-; GFX6-NEXT:    s_andn2_b64 s[4:5], s[2:3], s[4:5]
-; GFX6-NEXT:    s_cmp_lt_i32 s7, 0
-; GFX6-NEXT:    s_cselect_b32 s4, 0, s4
-; GFX6-NEXT:    s_cselect_b32 s5, s8, s5
-; GFX6-NEXT:    s_cmp_gt_i32 s7, 51
-; GFX6-NEXT:    s_cselect_b32 s3, s3, s5
-; GFX6-NEXT:    s_cselect_b32 s2, s2, s4
-; GFX6-NEXT:    v_ldexp_f64 v[0:1], s[2:3], v0
-; GFX6-NEXT:    v_mov_b32_e32 v4, -1
-; GFX6-NEXT:    v_fract_f64_e32 v[2:3], v[0:1]
-; GFX6-NEXT:    v_mov_b32_e32 v5, 0x3fefffff
-; GFX6-NEXT:    v_min_f64 v[2:3], v[2:3], v[4:5]
-; GFX6-NEXT:    v_cmp_class_f64_e64 vcc, v[0:1], 3
-; GFX6-NEXT:    s_mov_b32 s4, 0
-; GFX6-NEXT:    v_cndmask_b32_e32 v2, v2, v0, vcc
-; GFX6-NEXT:    v_cndmask_b32_e32 v3, v3, v1, vcc
-; GFX6-NEXT:    v_add_f64 v[0:1], v[0:1], -v[2:3]
-; GFX6-NEXT:    v_mov_b32_e32 v2, s2
-; GFX6-NEXT:    s_mov_b32 s5, 0xc1f00000
-; GFX6-NEXT:    v_mov_b32_e32 v3, s3
-; GFX6-NEXT:    v_fma_f64 v[2:3], v[0:1], s[4:5], v[2:3]
-; GFX6-NEXT:    v_cvt_u32_f64_e32 v0, v[0:1]
-; GFX6-NEXT:    v_cvt_u32_f64_e32 v2, v[2:3]
 ; GFX6-NEXT:    s_mov_b32 s7, 0xf000
+; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX6-NEXT:    s_bitset0_b32 s3, 31
 ; GFX6-NEXT:    s_mov_b32 s4, s0
-; GFX6-NEXT:    v_cvt_f64_u32_e32 v[0:1], v0
-; GFX6-NEXT:    v_cvt_f64_u32_e32 v[2:3], v2
+; GFX6-NEXT:    s_bfe_u32 s0, s3, 0xb0014
 ; GFX6-NEXT:    s_mov_b32 s5, s1
-; GFX6-NEXT:    v_ldexp_f64 v[0:1], v[0:1], 32
-; GFX6-NEXT:    v_add_f64 v[0:1], v[0:1], v[2:3]
+; GFX6-NEXT:    s_add_i32 s8, s0, 0xfffffc01
+; GFX6-NEXT:    s_mov_b32 s1, 0xfffff
+; GFX6-NEXT:    s_mov_b32 s0, s6
+; GFX6-NEXT:    s_lshr_b64 s[0:1], s[0:1], s8
+; GFX6-NEXT:    s_andn2_b64 s[0:1], s[2:3], s[0:1]
+; GFX6-NEXT:    s_cmp_lt_i32 s8, 0
+; GFX6-NEXT:    s_cselect_b32 s0, 0, s0
+; GFX6-NEXT:    s_cselect_b32 s1, 0, s1
+; GFX6-NEXT:    s_cmp_gt_i32 s8, 51
+; GFX6-NEXT:    s_cselect_b32 s1, s3, s1
+; GFX6-NEXT:    s_cselect_b32 s0, s2, s0
+; GFX6-NEXT:    v_mov_b32_e32 v0, s0
+; GFX6-NEXT:    v_mov_b32_e32 v1, s1
 ; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[4:7], 0
 ; GFX6-NEXT:    s_endpgm
 ;

>From a0b748f58b3460413bde3ebe58308571de35fb9d Mon Sep 17 00:00:00 2001
From: Jacob Crawley <jacob.crawley at arm.com>
Date: Mon, 1 Jun 2026 11:00:05 +0000
Subject: [PATCH 9/9] skip combine if cast operations are legal

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 11 ++-
 llvm/test/CodeGen/AMDGPU/fp-to-int-to-fp.ll   | 40 +++++------
 llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll     | 71 ++++++-------------
 3 files changed, 49 insertions(+), 73 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index eca182010db21..b110fc916b5e8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -19966,6 +19966,16 @@ static SDValue foldFPToIntToFP(SDNode *N, const SDLoc &DL, SelectionDAG &DAG,
   bool IsSigned = N->getOpcode() == ISD::SINT_TO_FP;
   assert(IsSigned || IsUnsigned);
 
+  // Don't fold if the individual cast operations are already legal,
+  // as FTRUNC may have a more expensive custom expansion.
+  EVT IntVT = N->getOperand(0).getValueType();
+  EVT LegalIntVT = TLI.getTypeToTransformTo(*DAG.getContext(), IntVT);
+  unsigned FPToIntOp = IsUnsigned ? ISD::FP_TO_UINT : ISD::FP_TO_SINT;
+  unsigned IntToFPOp = N->getOpcode(); // UINT_TO_FP or SINT_TO_FP
+  if (TLI.isOperationLegal(FPToIntOp, LegalIntVT) &&
+      TLI.isOperationLegal(IntToFPOp, VT))
+    return SDValue();
+
   bool IsSignedZeroSafe = DAG.getTarget().Options.NoSignedZerosFPMath ||
                           DAG.canIgnoreSignBitOfZero(SDValue(N, 0));
   // For signed conversions: The optimization changes signed zero behavior.
@@ -20011,7 +20021,6 @@ static SDValue foldFPToIntToFP(SDNode *N, const SDLoc &DL, SelectionDAG &DAG,
   }
 
   // Check that the sequence ends with the correct kind of fpto[us]i.
-  unsigned FPToIntOp = IsUnsigned ? ISD::FP_TO_UINT : ISD::FP_TO_SINT;
   if (IntVal.getOpcode() != FPToIntOp ||
       IntVal.getOperand(0).getValueType() != VT)
     return SDValue();
diff --git a/llvm/test/CodeGen/AMDGPU/fp-to-int-to-fp.ll b/llvm/test/CodeGen/AMDGPU/fp-to-int-to-fp.ll
index 2416d6a852eb9..caa7c77ac0786 100644
--- a/llvm/test/CodeGen/AMDGPU/fp-to-int-to-fp.ll
+++ b/llvm/test/CodeGen/AMDGPU/fp-to-int-to-fp.ll
@@ -1,22 +1,16 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc -mtriple=amdgcn < %s | FileCheck %s --check-prefixes=CHECK,SIGNED-ZEROS
 ; RUN: llc -mtriple=amdgcn --enable-no-signed-zeros-fp-math < %s | FileCheck %s --check-prefixes=CHECK,NO-SIGNED-ZEROS
 
 ; Test folding of float->int->float roundtrips into float-only operations.
 
 define float @test_signed_basic(float %x) {
-; SIGNED-ZEROS-LABEL: test_signed_basic:
-; SIGNED-ZEROS:       ; %bb.0: ; %entry
-; SIGNED-ZEROS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SIGNED-ZEROS-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; SIGNED-ZEROS-NEXT:    v_cvt_f32_i32_e32 v0, v0
-; SIGNED-ZEROS-NEXT:    s_setpc_b64 s[30:31]
-;
-; NO-SIGNED-ZEROS-LABEL: test_signed_basic:
-; NO-SIGNED-ZEROS:       ; %bb.0: ; %entry
-; NO-SIGNED-ZEROS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; NO-SIGNED-ZEROS-NEXT:    v_trunc_f32_e32 v0, v0
-; NO-SIGNED-ZEROS-NEXT:    s_setpc_b64 s[30:31]
+; CHECK-LABEL: test_signed_basic:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_cvt_i32_f32_e32 v0, v0
+; CHECK-NEXT:    v_cvt_f32_i32_e32 v0, v0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
 entry:
   %i = fptosi float %x to i32
   %f = sitofp i32 %i to float
@@ -26,17 +20,12 @@ entry:
 ; For unsigned conversions, even when signed zeros are possible, we can still
 ; use truncate because fabs is free.
 define float @test_unsigned_basic(float %x) {
-; SIGNED-ZEROS-LABEL: test_unsigned_basic:
-; SIGNED-ZEROS:       ; %bb.0: ; %entry
-; SIGNED-ZEROS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SIGNED-ZEROS-NEXT:    v_trunc_f32_e64 v0, |v0|
-; SIGNED-ZEROS-NEXT:    s_setpc_b64 s[30:31]
-;
-; NO-SIGNED-ZEROS-LABEL: test_unsigned_basic:
-; NO-SIGNED-ZEROS:       ; %bb.0: ; %entry
-; NO-SIGNED-ZEROS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; NO-SIGNED-ZEROS-NEXT:    v_trunc_f32_e32 v0, v0
-; NO-SIGNED-ZEROS-NEXT:    s_setpc_b64 s[30:31]
+; CHECK-LABEL: test_unsigned_basic:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_cvt_u32_f32_e32 v0, v0
+; CHECK-NEXT:    v_cvt_f32_u32_e32 v0, v0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
 entry:
   %i = fptoui float %x to i32
   %f = uitofp i32 %i to float
@@ -60,3 +49,6 @@ entry:
 }
 
 declare i32 @llvm.smin.i32(i32, i32)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; NO-SIGNED-ZEROS: {{.*}}
+; SIGNED-ZEROS: {{.*}}
diff --git a/llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll b/llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll
index 59f3473cae919..c8b33c931637a 100644
--- a/llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll
+++ b/llvm/test/CodeGen/AMDGPU/fptoui_uitofp.ll
@@ -5,12 +5,14 @@
 define amdgpu_kernel void @fptoui_f32_to_i16_to_f32(ptr addrspace(1) %out, float %x) {
 ; GFX6-LABEL: fptoui_f32_to_i16_to_f32:
 ; GFX6:       ; %bb.0: ; %entry
-; GFX6-NEXT:    s_load_dword s6, s[4:5], 0xb
-; GFX6-NEXT:    s_load_dwordx2 s[0:1], s[4:5], 0x9
+; GFX6-NEXT:    s_load_dword s0, s[4:5], 0xb
 ; GFX6-NEXT:    s_mov_b32 s3, 0xf000
 ; GFX6-NEXT:    s_mov_b32 s2, -1
 ; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
-; GFX6-NEXT:    v_trunc_f32_e64 v0, |s6|
+; GFX6-NEXT:    v_cvt_u32_f32_e32 v0, s0
+; GFX6-NEXT:    s_load_dwordx2 s[0:1], s[4:5], 0x9
+; GFX6-NEXT:    v_cvt_f32_u32_e32 v0, v0
+; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
 ; GFX6-NEXT:    buffer_store_dword v0, off, s[0:3], 0
 ; GFX6-NEXT:    s_endpgm
 ;
@@ -33,12 +35,14 @@ entry:
 define amdgpu_kernel void @fptoui_f32_to_i32_to_f32(ptr addrspace(1) %out, float %x) {
 ; GFX6-LABEL: fptoui_f32_to_i32_to_f32:
 ; GFX6:       ; %bb.0: ; %entry
-; GFX6-NEXT:    s_load_dword s6, s[4:5], 0xb
-; GFX6-NEXT:    s_load_dwordx2 s[0:1], s[4:5], 0x9
+; GFX6-NEXT:    s_load_dword s0, s[4:5], 0xb
 ; GFX6-NEXT:    s_mov_b32 s3, 0xf000
 ; GFX6-NEXT:    s_mov_b32 s2, -1
 ; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
-; GFX6-NEXT:    v_trunc_f32_e64 v0, |s6|
+; GFX6-NEXT:    v_cvt_u32_f32_e32 v0, s0
+; GFX6-NEXT:    s_load_dwordx2 s[0:1], s[4:5], 0x9
+; GFX6-NEXT:    v_cvt_f32_u32_e32 v0, v0
+; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
 ; GFX6-NEXT:    buffer_store_dword v0, off, s[0:3], 0
 ; GFX6-NEXT:    s_endpgm
 ;
@@ -125,9 +129,10 @@ define amdgpu_kernel void @fptoui_f16_to_i32_to_f16(ptr addrspace(1) %out, half
 ; GFX6-NEXT:    s_mov_b32 s3, 0xf000
 ; GFX6-NEXT:    s_mov_b32 s2, -1
 ; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
-; GFX6-NEXT:    v_cvt_f32_f16_e64 v0, |s0|
+; GFX6-NEXT:    v_cvt_f32_f16_e32 v0, s0
 ; GFX6-NEXT:    s_load_dwordx2 s[0:1], s[4:5], 0x9
-; GFX6-NEXT:    v_trunc_f32_e32 v0, v0
+; GFX6-NEXT:    v_cvt_u32_f32_e32 v0, v0
+; GFX6-NEXT:    v_cvt_f32_u32_e32 v0, v0
 ; GFX6-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
 ; GFX6-NEXT:    buffer_store_short v0, off, s[0:3], 0
@@ -184,27 +189,12 @@ define amdgpu_kernel void @fptoui_f64_to_i16_to_f64(ptr addrspace(1) %out, doubl
 ; GFX6-LABEL: fptoui_f64_to_i16_to_f64:
 ; GFX6:       ; %bb.0: ; %entry
 ; GFX6-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
-; GFX6-NEXT:    s_mov_b32 s6, -1
-; GFX6-NEXT:    s_mov_b32 s7, 0xf000
 ; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
-; GFX6-NEXT:    s_bitset0_b32 s3, 31
-; GFX6-NEXT:    s_mov_b32 s4, s0
-; GFX6-NEXT:    s_bfe_u32 s0, s3, 0xb0014
-; GFX6-NEXT:    s_mov_b32 s5, s1
-; GFX6-NEXT:    s_add_i32 s8, s0, 0xfffffc01
-; GFX6-NEXT:    s_mov_b32 s1, 0xfffff
-; GFX6-NEXT:    s_mov_b32 s0, s6
-; GFX6-NEXT:    s_lshr_b64 s[0:1], s[0:1], s8
-; GFX6-NEXT:    s_andn2_b64 s[0:1], s[2:3], s[0:1]
-; GFX6-NEXT:    s_cmp_lt_i32 s8, 0
-; GFX6-NEXT:    s_cselect_b32 s0, 0, s0
-; GFX6-NEXT:    s_cselect_b32 s1, 0, s1
-; GFX6-NEXT:    s_cmp_gt_i32 s8, 51
-; GFX6-NEXT:    s_cselect_b32 s1, s3, s1
-; GFX6-NEXT:    s_cselect_b32 s0, s2, s0
-; GFX6-NEXT:    v_mov_b32_e32 v0, s0
-; GFX6-NEXT:    v_mov_b32_e32 v1, s1
-; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[4:7], 0
+; GFX6-NEXT:    v_cvt_u32_f64_e32 v0, s[2:3]
+; GFX6-NEXT:    s_mov_b32 s3, 0xf000
+; GFX6-NEXT:    s_mov_b32 s2, -1
+; GFX6-NEXT:    v_cvt_f64_u32_e32 v[0:1], v0
+; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[0:3], 0
 ; GFX6-NEXT:    s_endpgm
 ;
 ; GFX9-LABEL: fptoui_f64_to_i16_to_f64:
@@ -226,27 +216,12 @@ define amdgpu_kernel void @fptoui_f64_to_i32_to_f64(ptr addrspace(1) %out, doubl
 ; GFX6-LABEL: fptoui_f64_to_i32_to_f64:
 ; GFX6:       ; %bb.0: ; %entry
 ; GFX6-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
-; GFX6-NEXT:    s_mov_b32 s6, -1
-; GFX6-NEXT:    s_mov_b32 s7, 0xf000
 ; GFX6-NEXT:    s_waitcnt lgkmcnt(0)
-; GFX6-NEXT:    s_bitset0_b32 s3, 31
-; GFX6-NEXT:    s_mov_b32 s4, s0
-; GFX6-NEXT:    s_bfe_u32 s0, s3, 0xb0014
-; GFX6-NEXT:    s_mov_b32 s5, s1
-; GFX6-NEXT:    s_add_i32 s8, s0, 0xfffffc01
-; GFX6-NEXT:    s_mov_b32 s1, 0xfffff
-; GFX6-NEXT:    s_mov_b32 s0, s6
-; GFX6-NEXT:    s_lshr_b64 s[0:1], s[0:1], s8
-; GFX6-NEXT:    s_andn2_b64 s[0:1], s[2:3], s[0:1]
-; GFX6-NEXT:    s_cmp_lt_i32 s8, 0
-; GFX6-NEXT:    s_cselect_b32 s0, 0, s0
-; GFX6-NEXT:    s_cselect_b32 s1, 0, s1
-; GFX6-NEXT:    s_cmp_gt_i32 s8, 51
-; GFX6-NEXT:    s_cselect_b32 s1, s3, s1
-; GFX6-NEXT:    s_cselect_b32 s0, s2, s0
-; GFX6-NEXT:    v_mov_b32_e32 v0, s0
-; GFX6-NEXT:    v_mov_b32_e32 v1, s1
-; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[4:7], 0
+; GFX6-NEXT:    v_cvt_u32_f64_e32 v0, s[2:3]
+; GFX6-NEXT:    s_mov_b32 s3, 0xf000
+; GFX6-NEXT:    s_mov_b32 s2, -1
+; GFX6-NEXT:    v_cvt_f64_u32_e32 v[0:1], v0
+; GFX6-NEXT:    buffer_store_dwordx2 v[0:1], off, s[0:3], 0
 ; GFX6-NEXT:    s_endpgm
 ;
 ; GFX9-LABEL: fptoui_f64_to_i32_to_f64:



More information about the llvm-commits mailing list