[llvm] [AArch64] Parameterize repeated FP divisor combine threshold by subtarget (PR #216930)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 17 23:57:18 PDT 2026
https://github.com/yamash-fj created https://github.com/llvm/llvm-project/pull/216930
Changes:
This patch makes the threshold for combining repeated FP divisors configurable per AArch64 subtarget, instead of using a single fixed value 3 for all CPUs. Additionaly, set this value 2 for A64FX (I checked A64FX benefits).
Motivation:
Today, AArch64 uses a fixed threshold of 3 for reciprocal transform. This means the transform runs when there are 3 FDIVs with the same divisor (not 2). That is conservative for some subtargets, and it can miss profitable opportunities on CPUs such as A64FX, where a lower threshold appears to produce better code generation.
```
a / D; b / D; ...
=>
recip = 1.0 / D; a * recip; b * recip; ...
```
Note:
It does not change the semantics of the reciprocal transform itself.
>From 05b534d7c615c57f786556e498d5d5976a018efa Mon Sep 17 00:00:00 2001
From: yamash-fj <yamashita.ta-16 at fujitsu.com>
Date: Tue, 18 Aug 2026 15:50:56 +0900
Subject: [PATCH] [AArch64] Parameterize repeated FP divisor combine threshold
by subtarget
This change makes the threshold for combining repeated FP divisors configurable by AArch64 subtarget, instead of using fixed value.
The existing fixed value is 3, but some subtargets may benefit with lower threshold, such as A64FX. This patch also includes setting this parameter of A64FX 2.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 5 +-
llvm/lib/Target/AArch64/AArch64Subtarget.cpp | 1 +
llvm/lib/Target/AArch64/AArch64Subtarget.h | 3 +
llvm/test/CodeGen/AArch64/fdiv-combine.ll | 123 +++++++++++++-----
4 files changed, 97 insertions(+), 35 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 213a0042461ae..59445cb33b7be 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -32410,8 +32410,9 @@ SDValue AArch64TargetLowering::emitStackGuardMixFP(SelectionDAG &DAG,
unsigned AArch64TargetLowering::combineRepeatedFPDivisors() const {
// Combine multiple FDIVs with the same divisor into multiple FMULs by the
- // reciprocal if there are three or more FDIVs.
- return 3;
+ // reciprocal if there are enough FDivs. The threshold is set as
+ // MinFDivForCombining.
+ return Subtarget->getMinFDivForCombining();
}
TargetLoweringBase::LegalizeTypeAction
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
index 9ee3d0cc9e0ea..5c6cfd638b6ce 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
@@ -205,6 +205,7 @@ void AArch64Subtarget::initializeProperties(bool HasMinSize) {
MinPrefetchStride = 1024;
MaxPrefetchIterationsAhead = 4;
VScaleForTuning = 4;
+ MinFDivForCombining = 2;
break;
case MONAKA:
VScaleForTuning = 2;
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h
index b8303224a8976..0517f5daf0dc0 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -72,6 +72,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
unsigned MinimumJumpTableEntries = 4;
unsigned MaxJumpTableSize = 0;
unsigned FixedLoadLatency = 0;
+ unsigned MinFDivForCombining = 3;
// ReserveXRegister[i] - X#i is not available as a general purpose register.
BitVector ReserveXRegister;
@@ -303,6 +304,8 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
unsigned getFixedLoadLatency() const { return FixedLoadLatency; }
+ unsigned getMinFDivForCombining() const { return MinFDivForCombining; }
+
/// CPU has TBI (top byte of addresses is ignored during HW address
/// translation) and OS enables it.
bool supportsAddressTopByteIgnored() const;
diff --git a/llvm/test/CodeGen/AArch64/fdiv-combine.ll b/llvm/test/CodeGen/AArch64/fdiv-combine.ll
index 9eacb61eecd06..e5dc5275696cb 100644
--- a/llvm/test/CodeGen/AArch64/fdiv-combine.ll
+++ b/llvm/test/CodeGen/AArch64/fdiv-combine.ll
@@ -1,6 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=aarch64-unknown-unknown < %s | FileCheck %s --check-prefixes=CHECK,CHECK-SD
-; RUN: llc -mtriple=aarch64-unknown-unknown < %s -global-isel -global-isel-abort=2 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
+; RUN: llc -mtriple=aarch64-unknown-unknown < %s | FileCheck %s --check-prefixes=CHECK,CHECK-THREE,CHECK-SDGI,CHECK-SD
+; RUN: llc -mtriple=aarch64-unknown-unknown < %s -global-isel -global-isel-abort=2 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-THREE,CHECK-SDGI,CHECK-GI
+; RUN: llc -mtriple=aarch64-unknown-unknown -mcpu=neoverse-v2 < %s | FileCheck %s --check-prefixes=CHECK,CHECK-THREE,CHECK-MCPU
+; RUN: llc -mtriple=aarch64-unknown-unknown -mcpu=a64fx < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MCPU,CHECK-TWO
; CHECK-GI: warning: Instruction selection used fallback path for splat_fdiv_nxv4f32
; CHECK-GI-NEXT: warning: Instruction selection used fallback path for splat_three_fdiv_nxv4f32
@@ -75,15 +77,23 @@ define void @three_fdiv_2xdouble(<2 x double> %D, <2 x double> %a, <2 x double>
ret void
}
-; Following test cases check we never combine two FDIVs if neither of them
-; calculates a reciprocal.
+; Following test cases check we combine two FDIVs
+; if MinFDivForCombining setting by the subtarget is 2.
define void @two_fdiv_float(float %D, float %a, float %b) {
-; CHECK-LABEL: two_fdiv_float:
-; CHECK: // %bb.0:
-; CHECK-NEXT: fdiv s3, s1, s0
-; CHECK-NEXT: fdiv s1, s2, s0
-; CHECK-NEXT: fmov s0, s3
-; CHECK-NEXT: b foo_2f
+; CHECK-THREE-LABEL: two_fdiv_float:
+; CHECK-THREE: // %bb.0:
+; CHECK-THREE-NEXT: fdiv s3, s1, s0
+; CHECK-THREE-NEXT: fdiv s1, s2, s0
+; CHECK-THREE-NEXT: fmov s0, s3
+; CHECK-THREE-NEXT: b foo_2f
+;
+; CHECK-TWO-LABEL: two_fdiv_float:
+; CHECK-TWO: // %bb.0:
+; CHECK-TWO-NEXT: fmov s3, #1.00000000
+; CHECK-TWO-NEXT: fdiv s3, s3, s0
+; CHECK-TWO-NEXT: fmul s0, s1, s3
+; CHECK-TWO-NEXT: fmul s1, s2, s3
+; CHECK-TWO-NEXT: b foo_2f
%div = fdiv arcp float %a, %D
%div1 = fdiv arcp float %b, %D
tail call void @foo_2f(float %div, float %div1)
@@ -91,12 +101,20 @@ define void @two_fdiv_float(float %D, float %a, float %b) {
}
define void @two_fdiv_double(double %D, double %a, double %b) {
-; CHECK-LABEL: two_fdiv_double:
-; CHECK: // %bb.0:
-; CHECK-NEXT: fdiv d3, d1, d0
-; CHECK-NEXT: fdiv d1, d2, d0
-; CHECK-NEXT: fmov d0, d3
-; CHECK-NEXT: b foo_2d
+; CHECK-THREE-LABEL: two_fdiv_double:
+; CHECK-THREE: // %bb.0:
+; CHECK-THREE-NEXT: fdiv d3, d1, d0
+; CHECK-THREE-NEXT: fdiv d1, d2, d0
+; CHECK-THREE-NEXT: fmov d0, d3
+; CHECK-THREE-NEXT: b foo_2d
+;
+; CHECK-TWO-LABEL: two_fdiv_double:
+; CHECK-TWO: // %bb.0:
+; CHECK-TWO-NEXT: fmov d3, #1.00000000
+; CHECK-TWO-NEXT: fdiv d3, d3, d0
+; CHECK-TWO-NEXT: fmul d0, d1, d3
+; CHECK-TWO-NEXT: fmul d1, d2, d3
+; CHECK-TWO-NEXT: b foo_2d
%div = fdiv arcp double %a, %D
%div1 = fdiv arcp double %b, %D
tail call void @foo_2d(double %div, double %div1)
@@ -125,6 +143,17 @@ define void @four_fdiv_multi_float(float %D, float %a, float %b, float %c) #0 {
; CHECK-GI-NEXT: fmul s2, s3, s5
; CHECK-GI-NEXT: fmov s3, s4
; CHECK-GI-NEXT: b foo_4f
+;
+; CHECK-MCPU-LABEL: four_fdiv_multi_float:
+; CHECK-MCPU: // %bb.0:
+; CHECK-MCPU-NEXT: fmov s4, #1.00000000
+; CHECK-MCPU-NEXT: fdiv s5, s4, s0
+; CHECK-MCPU-NEXT: fmul s4, s1, s5
+; CHECK-MCPU-NEXT: fmul s1, s2, s5
+; CHECK-MCPU-NEXT: fmul s2, s3, s5
+; CHECK-MCPU-NEXT: fmul s3, s0, s5
+; CHECK-MCPU-NEXT: fmov s0, s4
+; CHECK-MCPU-NEXT: b foo_4f
%div = fdiv arcp float %a, %D
%div1 = fdiv arcp float %b, %D
%div2 = fdiv arcp float %c, %D
@@ -134,16 +163,27 @@ define void @four_fdiv_multi_float(float %D, float %a, float %b, float %c) #0 {
}
define void @splat_three_fdiv_4xfloat(float %D, <4 x float> %a, <4 x float> %b, <4 x float> %c) {
-; CHECK-LABEL: splat_three_fdiv_4xfloat:
-; CHECK: // %bb.0:
-; CHECK-NEXT: // kill: def $s0 killed $s0 def $q0
-; CHECK-NEXT: fmov v4.4s, #1.00000000
-; CHECK-NEXT: dup v0.4s, v0.s[0]
-; CHECK-NEXT: fdiv v4.4s, v4.4s, v0.4s
-; CHECK-NEXT: fmul v0.4s, v1.4s, v4.4s
-; CHECK-NEXT: fmul v1.4s, v2.4s, v4.4s
-; CHECK-NEXT: fmul v2.4s, v3.4s, v4.4s
-; CHECK-NEXT: b foo_3_4xf
+; CHECK-SDGI-LABEL: splat_three_fdiv_4xfloat:
+; CHECK-SDGI: // %bb.0:
+; CHECK-SDGI-NEXT: // kill: def $s0 killed $s0 def $q0
+; CHECK-SDGI-NEXT: fmov v4.4s, #1.00000000
+; CHECK-SDGI-NEXT: dup v0.4s, v0.s[0]
+; CHECK-SDGI-NEXT: fdiv v4.4s, v4.4s, v0.4s
+; CHECK-SDGI-NEXT: fmul v0.4s, v1.4s, v4.4s
+; CHECK-SDGI-NEXT: fmul v1.4s, v2.4s, v4.4s
+; CHECK-SDGI-NEXT: fmul v2.4s, v3.4s, v4.4s
+; CHECK-SDGI-NEXT: b foo_3_4xf
+;
+; CHECK-MCPU-LABEL: splat_three_fdiv_4xfloat:
+; CHECK-MCPU: // %bb.0:
+; CHECK-MCPU-NEXT: // kill: def $s0 killed $s0 def $q0
+; CHECK-MCPU-NEXT: dup v0.4s, v0.s[0]
+; CHECK-MCPU-NEXT: fmov v4.4s, #1.00000000
+; CHECK-MCPU-NEXT: fdiv v4.4s, v4.4s, v0.4s
+; CHECK-MCPU-NEXT: fmul v0.4s, v1.4s, v4.4s
+; CHECK-MCPU-NEXT: fmul v1.4s, v2.4s, v4.4s
+; CHECK-MCPU-NEXT: fmul v2.4s, v3.4s, v4.4s
+; CHECK-MCPU-NEXT: b foo_3_4xf
%D.ins = insertelement <4 x float> poison, float %D, i64 0
%splat = shufflevector <4 x float> %D.ins, <4 x float> poison, <4 x i32> zeroinitializer
%div = fdiv arcp <4 x float> %a, %splat
@@ -169,6 +209,15 @@ define <4 x float> @splat_fdiv_v4f32(float %D, <4 x float> %a) #0 {
; CHECK-GI-NEXT: dup v0.4s, v0.s[0]
; CHECK-GI-NEXT: fdiv v0.4s, v1.4s, v0.4s
; CHECK-GI-NEXT: ret
+;
+; CHECK-MCPU-LABEL: splat_fdiv_v4f32:
+; CHECK-MCPU: // %bb.0: // %entry
+; CHECK-MCPU-NEXT: // kill: def $s0 killed $s0 def $q0
+; CHECK-MCPU-NEXT: dup v0.4s, v0.s[0]
+; CHECK-MCPU-NEXT: fmov v2.4s, #1.00000000
+; CHECK-MCPU-NEXT: fdiv v0.4s, v2.4s, v0.4s
+; CHECK-MCPU-NEXT: fmul v0.4s, v1.4s, v0.4s
+; CHECK-MCPU-NEXT: ret
entry:
%D.ins = insertelement <4 x float> poison, float %D, i64 0
%splat = shufflevector <4 x float> %D.ins, <4 x float> poison, <4 x i32> zeroinitializer
@@ -212,13 +261,21 @@ entry:
}
define <vscale x 2 x double> @splat_fdiv_nxv2f64(double %D, <vscale x 2 x double> %a) #0 {
-; CHECK-LABEL: splat_fdiv_nxv2f64:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: // kill: def $d0 killed $d0 def $z0
-; CHECK-NEXT: ptrue p0.d
-; CHECK-NEXT: mov z0.d, d0
-; CHECK-NEXT: fdivr z0.d, p0/m, z0.d, z1.d
-; CHECK-NEXT: ret
+; CHECK-SDGI-LABEL: splat_fdiv_nxv2f64:
+; CHECK-SDGI: // %bb.0: // %entry
+; CHECK-SDGI-NEXT: // kill: def $d0 killed $d0 def $z0
+; CHECK-SDGI-NEXT: ptrue p0.d
+; CHECK-SDGI-NEXT: mov z0.d, d0
+; CHECK-SDGI-NEXT: fdivr z0.d, p0/m, z0.d, z1.d
+; CHECK-SDGI-NEXT: ret
+;
+; CHECK-MCPU-LABEL: splat_fdiv_nxv2f64:
+; CHECK-MCPU: // %bb.0: // %entry
+; CHECK-MCPU-NEXT: // kill: def $d0 killed $d0 def $z0
+; CHECK-MCPU-NEXT: mov z0.d, d0
+; CHECK-MCPU-NEXT: ptrue p0.d
+; CHECK-MCPU-NEXT: fdivr z0.d, p0/m, z0.d, z1.d
+; CHECK-MCPU-NEXT: ret
entry:
%D.ins = insertelement <vscale x 2 x double> poison, double %D, i64 0
%splat = shufflevector <vscale x 2 x double> %D.ins, <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer
More information about the llvm-commits
mailing list