[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