[llvm] [AArch64] missed fold vector fptoui(fdiv(uitofp(x), uitofp(y))) or fptosi(fdiv(sitofp(x), sitofp(y))) into udiv(x, y) or sdiv(x, y) for sve (PR #215146)

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 9 13:37:08 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: Durgesh Nandan Mohanty (dnmohanty)

<details>
<summary>Changes</summary>

This PR implements a DAG combine in `AArch64ISelLowering.cpp` to fold vector floating-point division and conversions into native SVE integer division (`udiv`/`sdiv`).


DAG Combine Logic: Added `performFPToIntToDivCombine` supporting `ISD::FP_TO_UINT` and ISD::FP_TO_SINT` with strict type checks ensuring safe conversions (`i32` vectors via `f64`).
Tests: Added `llvm/test/CodeGen/AArch64/sve-fdiv-int-fold.ll` to verify optimal single-instruction codegen.
Commit History: Structured into two clean commits as requested:
  1. Pre-commit baseline test (NFC)
  2. Fixup commit with compiler changes and updated test checks

Fixes #<!-- -->214927

---
Full diff: https://github.com/llvm/llvm-project/pull/215146.diff


2 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+32) 
- (added) llvm/test/CodeGen/AArch64/sve-fdiv-int-fold.ll (+34) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 2ac6c5fbc471a..2bde72a6a9593 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -31167,7 +31167,36 @@ static SDValue performPredicateLoadCombine(SDNode *N,
   DAG.makeEquivalentMemoryOrdering(Load, LoadPred);
   return LoadPred;
 }
+static SDValue performFPToIntToDivCombine(SDNode *N, SelectionDAG &DAG) {
+  unsigned Opc = N->getOpcode();
+  bool IsSigned = (Opc == ISD::FP_TO_SINT);
+
+  SDValue FDiv = N->getOperand(0);
+  if (FDiv.getOpcode() != ISD::FDIV)
+    return SDValue();
+
+  EVT IntVT = N->getValueType(0);
+  EVT FPVT = FDiv.getValueType();
+
+  if (IntVT.getVectorElementType() != MVT::i32 ||
+      FPVT.getVectorElementType() != MVT::f64)
+    return SDValue();
+
+  unsigned CastOpc = IsSigned ? ISD::SINT_TO_FP : ISD::UINT_TO_FP;
+  SDValue Op0 = FDiv.getOperand(0);
+  SDValue Op1 = FDiv.getOperand(1);
 
+  if (Op0.getOpcode() != CastOpc || Op1.getOpcode() != CastOpc)
+    return SDValue();
+
+  if (Op0.getOperand(0).getValueType() != IntVT ||
+      Op1.getOperand(0).getValueType() != IntVT)
+    return SDValue();
+
+  unsigned DivOpc = IsSigned ? ISD::SDIV : ISD::UDIV;
+  return DAG.getNode(DivOpc, SDLoc(N), IntVT, Op0.getOperand(0),
+                     Op1.getOperand(0));
+}
 SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
                                                  DAGCombinerInfo &DCI) const {
   SelectionDAG &DAG = DCI.DAG;
@@ -31175,6 +31204,9 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
   default:
     LLVM_DEBUG(dbgs() << "Custom combining: skipping\n");
     break;
+  case ISD::FP_TO_UINT:
+  case ISD::FP_TO_SINT:
+    return performFPToIntToDivCombine(N, DAG);
   case ISD::VECTOR_DEINTERLEAVE:
     return performVectorDeinterleaveCombine(N, DCI, DAG);
   case ISD::VECREDUCE_AND:
diff --git a/llvm/test/CodeGen/AArch64/sve-fdiv-int-fold.ll b/llvm/test/CodeGen/AArch64/sve-fdiv-int-fold.ll
new file mode 100644
index 0000000000000..953187c7208d5
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve-fdiv-int-fold.ll
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve < %s | FileCheck %s
+
+define <vscale x 2 x i32> @fptoui_fdiv_uitofp_nxv2i32(<vscale x 2 x i32> %a, <vscale x 2 x i32> %b) {
+; CHECK-LABEL: fptoui_fdiv_uitofp_nxv2i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.d
+; CHECK-NEXT:    ucvtf z0.d, p0/m, z0.s
+; CHECK-NEXT:    ucvtf z1.d, p0/m, z1.s
+; CHECK-NEXT:    fdiv z0.d, p0/m, z0.d, z1.d
+; CHECK-NEXT:    fcvtzs z0.d, p0/m, z0.d
+; CHECK-NEXT:    ret
+  %fa = uitofp <vscale x 2 x i32> %a to <vscale x 2 x double>
+  %fb = uitofp <vscale x 2 x i32> %b to <vscale x 2 x double>
+  %fdiv = fdiv <vscale x 2 x double> %fa, %fb
+  %res = fptoui <vscale x 2 x double> %fdiv to <vscale x 2 x i32>
+  ret <vscale x 2 x i32> %res
+}
+
+define <vscale x 2 x i32> @fptosi_fdiv_sitofp_nxv2i32(<vscale x 2 x i32> %a, <vscale x 2 x i32> %b) {
+; CHECK-LABEL: fptosi_fdiv_sitofp_nxv2i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.d
+; CHECK-NEXT:    scvtf z0.d, p0/m, z0.s
+; CHECK-NEXT:    scvtf z1.d, p0/m, z1.s
+; CHECK-NEXT:    fdiv z0.d, p0/m, z0.d, z1.d
+; CHECK-NEXT:    fcvtzs z0.d, p0/m, z0.d
+; CHECK-NEXT:    ret
+  %fa = sitofp <vscale x 2 x i32> %a to <vscale x 2 x double>
+  %fb = sitofp <vscale x 2 x i32> %b to <vscale x 2 x double>
+  %fdiv = fdiv <vscale x 2 x double> %fa, %fb
+  %res = fptosi <vscale x 2 x double> %fdiv to <vscale x 2 x i32>
+  ret <vscale x 2 x i32> %res
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/215146


More information about the llvm-commits mailing list