[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
Fri Sep 11 07:14:17 PDT 2026


https://github.com/seritools updated https://github.com/llvm/llvm-project/pull/218748

>From c94f07dce76f705541a0ce57b55c5769507476bf 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     | 61 +++++++++++++++++++
 1 file changed, 61 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..4ff7dd48f9a64
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
@@ -0,0 +1,61 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32I %s
+; RUN: llc -mtriple=riscv32 -mattr=+f < %s | 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 a0, 263168
+; RV32IF-NEXT:    fmv.w.x fa5, a0
+; RV32IF-NEXT:    fmul.s fa0, fa0, 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 a0, 264192
+; RV32IF-NEXT:    fmv.w.x fa5, a0
+; RV32IF-NEXT:    fmul.s fa0, fa0, fa5
+; RV32IF-NEXT:    ret
+  %1 = fmul fast float %a, 3.0
+  %2 = fadd fast float %1, %a
+  ret float %2
+}

>From a6ae1f34a0475626a97530a00ec3c35112eb0644 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 5567fcaf7fcb3..ca292fc81afa6 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 4ff7dd48f9a64..9afcd1f1f0d11 100644
--- a/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
+++ b/llvm/test/CodeGen/RISCV/fadd-fmul-dagcombine.ll
@@ -11,14 +11,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
 ;
@@ -38,14 +33,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