[llvm] [DAGCombine] Do not gate a pre-legalization FADD fold on FMUL legality (PR #218748)
Dennis Duda via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 10 03:24:44 PDT 2026
https://github.com/seritools updated https://github.com/llvm/llvm-project/pull/218748
>From 558b3c1d0bf8a3a5d06672c0e73b1191eb7ec0e5 Mon Sep 17 00:00:00 2001
From: Dennis Duda <git at seri.tools>
Date: Tue, 25 Aug 2026 19:56:57 +0200
Subject: [PATCH 1/2] [DAGCombine] Pre-commit test for the FADD-chain-to-FMUL
fold
---
.../CodeGen/RISCV/fadd-fmul-dagcombine.ll | 67 +++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
diff --git a/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll b/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
new file mode 100644
index 0000000000000..d52fb3d9b76da
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
@@ -0,0 +1,67 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV32I %s
+; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+f -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV32IF %s
+
+; Chains of FADDs of the same value can fold into a multiplication. RV32I
+; expands FMUL to a libcall, so the fold's gating on FMUL legality is
+; observable here; RV32IF has a legal FMUL for comparison.
+
+define float @fadd_chain_to_fmul(float %a) nounwind {
+; RV32I-LABEL: fadd_chain_to_fmul:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
+; RV32I-NEXT: mv s0, a0
+; RV32I-NEXT: mv a1, a0
+; RV32I-NEXT: call __addsf3
+; RV32I-NEXT: mv a1, s0
+; RV32I-NEXT: call __addsf3
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IF-LABEL: fadd_chain_to_fmul:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: lui a1, 263168
+; RV32IF-NEXT: fmv.w.x fa5, a0
+; RV32IF-NEXT: fmv.w.x fa4, a1
+; RV32IF-NEXT: fmul.s fa5, fa5, fa4
+; RV32IF-NEXT: fmv.x.w a0, fa5
+; RV32IF-NEXT: ret
+ %1 = fadd fast float %a, %a
+ %2 = fadd fast float %1, %a
+ ret float %2
+}
+
+define float @fmul_fadd_to_fmul(float %a) nounwind {
+; RV32I-LABEL: fmul_fadd_to_fmul:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
+; RV32I-NEXT: mv s0, a0
+; RV32I-NEXT: lui a1, 263168
+; RV32I-NEXT: call __mulsf3
+; RV32I-NEXT: mv a1, s0
+; RV32I-NEXT: call __addsf3
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IF-LABEL: fmul_fadd_to_fmul:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: lui a1, 264192
+; RV32IF-NEXT: fmv.w.x fa5, a0
+; RV32IF-NEXT: fmv.w.x fa4, a1
+; RV32IF-NEXT: fmul.s fa5, fa5, fa4
+; RV32IF-NEXT: fmv.x.w a0, fa5
+; RV32IF-NEXT: ret
+ %1 = fmul fast float %a, 3.0
+ %2 = fadd fast float %1, %a
+ ret float %2
+}
>From 2fba8fc45ef393a00733818163ef9e0854bc45b6 Mon Sep 17 00:00:00 2001
From: Dennis Duda <git at seri.tools>
Date: Tue, 25 Aug 2026 20:08:42 +0200
Subject: [PATCH 2/2] [DAGCombine] Do not gate a pre-legalization FADD fold on
FMUL legality
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 3 ++-
llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll | 16 +++-------------
2 files changed, 5 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index a8e6d24a774ce..3e13de8d3545e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -19400,7 +19400,8 @@ SDValue DAGCombiner::visitFADD(SDNode *N) {
// We can fold chains of FADD's of the same value into multiplications.
// This transform is not safe in general because we are reducing the number
// of rounding steps.
- if (TLI.isOperationLegalOrCustom(ISD::FMUL, VT) && !N0CFP && !N1CFP) {
+ if ((!LegalOperations || TLI.isOperationLegalOrCustom(ISD::FMUL, VT)) &&
+ !N0CFP && !N1CFP) {
if (N0.getOpcode() == ISD::FMUL) {
bool CFP00 = DAG.isConstantFPBuildVectorOrConstantFP(N0.getOperand(0));
bool CFP01 = DAG.isConstantFPBuildVectorOrConstantFP(N0.getOperand(1));
diff --git a/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll b/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
index d52fb3d9b76da..239adf74847ef 100644
--- a/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
+++ b/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
@@ -13,14 +13,9 @@ define float @fadd_chain_to_fmul(float %a) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: addi sp, sp, -16
; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
-; RV32I-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
-; RV32I-NEXT: mv s0, a0
-; RV32I-NEXT: mv a1, a0
-; RV32I-NEXT: call __addsf3
-; RV32I-NEXT: mv a1, s0
-; RV32I-NEXT: call __addsf3
+; RV32I-NEXT: lui a1, 263168
+; RV32I-NEXT: call __mulsf3
; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
-; RV32I-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
; RV32I-NEXT: addi sp, sp, 16
; RV32I-NEXT: ret
;
@@ -42,14 +37,9 @@ define float @fmul_fadd_to_fmul(float %a) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: addi sp, sp, -16
; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
-; RV32I-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
-; RV32I-NEXT: mv s0, a0
-; RV32I-NEXT: lui a1, 263168
+; RV32I-NEXT: lui a1, 264192
; RV32I-NEXT: call __mulsf3
-; RV32I-NEXT: mv a1, s0
-; RV32I-NEXT: call __addsf3
; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
-; RV32I-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
; RV32I-NEXT: addi sp, sp, 16
; RV32I-NEXT: ret
;
More information about the llvm-commits
mailing list