[llvm-branch-commits] [llvm] DAGCombiner: Drop AllowFPOpFusion from visitFSUBForFMACombine (PR #221439)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Sep 5 05:28:16 PDT 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/221439

Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>

>From c6b91b68425c58f22b0439be0062af477746162a Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sat, 5 Sep 2026 00:31:25 +0200
Subject: [PATCH] DAGCombiner: Drop AllowFPOpFusion from visitFSUBForFMACombine

Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |   6 +-
 .../CodeGen/ARM/cortex-a57-misched-vfma.ll    | 234 +++++++++++++++---
 llvm/test/CodeGen/Hexagon/sffms.ll            |   6 +-
 3 files changed, 209 insertions(+), 37 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 82d4921ae405b..733d0eb9baa40 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -18910,7 +18910,6 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
   EVT VT = N->getValueType(0);
   SDLoc SL(N);
 
-  const TargetOptions &Options = DAG.getTarget().Options;
   // Floating-point multiply-add with intermediate rounding.
   bool HasFMAD = (LegalOperations && TLI.isFMADLegal(DAG, N));
 
@@ -18924,8 +18923,9 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
     return SDValue();
 
   const SDNodeFlags Flags = N->getFlags();
-  bool AllowFusionGlobally =
-      (Options.AllowFPOpFusion == FPOpFusion::Fast || HasFMAD);
+  // FMAD (with intermediate rounding) is always safe to form; FMA requires the
+  // contract fast-math flag.
+  bool AllowFusionGlobally = HasFMAD;
 
   // If the subtraction is not contractable, do not combine.
   if (!AllowFusionGlobally && !N->getFlags().hasAllowContract())
diff --git a/llvm/test/CodeGen/ARM/cortex-a57-misched-vfma.ll b/llvm/test/CodeGen/ARM/cortex-a57-misched-vfma.ll
index 557102c24bd7c..1d5eb8f73aac2 100644
--- a/llvm/test/CodeGen/ARM/cortex-a57-misched-vfma.ll
+++ b/llvm/test/CodeGen/ARM/cortex-a57-misched-vfma.ll
@@ -1,6 +1,5 @@
 ; REQUIRES: asserts
-; RUN: llc < %s -mtriple=armv8r-eabi -mcpu=cortex-a57 -enable-misched -verify-misched -debug-only=machine-scheduler -o - 2>&1 > /dev/null | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-DEFAULT
-; RUN: llc < %s -mtriple=armv8r-eabi -mcpu=cortex-a57 -enable-misched -verify-misched -debug-only=machine-scheduler -o - 2>&1 > /dev/null -fp-contract=fast | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FAST
+; RUN: llc < %s -mtriple=armv8r-eabi -mcpu=cortex-a57 -enable-misched -verify-misched -debug-only=machine-scheduler -o - 2>&1 > /dev/null | FileCheck %s --check-prefix=CHECK
 ; Check latencies of vmul/vfma accumulate chains.
 
 define arm_aapcs_vfpcc float @Test1(float %f1, float %f2, float %f3, float %f4, float %f5, float %f6) {
@@ -15,8 +14,7 @@ define arm_aapcs_vfpcc float @Test1(float %f1, float %f2, float %f3, float %f4,
 ; > VMULS read-advanced latency to VMLAS = 0
 ; CHECK-SAME:  Latency=0
 
-; CHECK-DEFAULT: VMLAS
-; CHECK-FAST:    VFMAS
+; CHECK:       VMLAS
 ; > VMLAS common latency = 9
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
@@ -24,8 +22,7 @@ define arm_aapcs_vfpcc float @Test1(float %f1, float %f2, float %f3, float %f4,
 ; > VMLAS read-advanced latency to the next VMLAS = 4
 ; CHECK-SAME:  Latency=4
 
-; CHECK-DEFAULT: VMLAS
-; CHECK-FAST:    VFMAS
+; CHECK:       VMLAS
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
 ; CHECK:       Data
@@ -41,6 +38,42 @@ define arm_aapcs_vfpcc float @Test1(float %f1, float %f2, float %f3, float %f4,
   ret float %add2
 }
 
+define arm_aapcs_vfpcc float @Test1_contract(float %f1, float %f2, float %f3, float %f4, float %f5, float %f6) {
+; CHECK:       Current Schedule Region
+; CHECK:       Test1_contract:%bb.0
+
+; CHECK:       VMULS
+; > VMULS common latency = 5
+; CHECK:       Latency            : 5
+; CHECK:       Successors:
+; CHECK:       Data
+; > VMULS read-advanced latency to VFMAS = 0
+; CHECK-SAME:  Latency=0
+
+; CHECK:       VFMAS
+; > VFMAS common latency = 9
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VFMAS read-advanced latency to the next VFMAS = 4
+; CHECK-SAME:  Latency=4
+
+; CHECK:       VFMAS
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VFMAS not-optimized latency to VMOVRS = 9
+; CHECK-SAME:  Latency=9
+
+; f1 * f2 + f3 * f4 + f5 * f6  ==>  VMULS, VFMAS, VFMAS
+  %mul1 = fmul contract float %f1, %f2
+  %mul2 = fmul contract float %f3, %f4
+  %mul3 = fmul contract float %f5, %f6
+  %add1 = fadd contract float %mul1, %mul2
+  %add2 = fadd contract float %add1, %mul3
+  ret float %add2
+}
+
 ; ASIMD form
 define arm_aapcs_vfpcc <2 x float> @Test2(<2 x float> %f1, <2 x float> %f2, <2 x float> %f3, <2 x float> %f4, <2 x float> %f5, <2 x float> %f6) {
 ; CHECK:       Current Schedule Region
@@ -54,8 +87,7 @@ define arm_aapcs_vfpcc <2 x float> @Test2(<2 x float> %f1, <2 x float> %f2, <2 x
 ; VMULfd read-advanced latency to VMLAfd = 0
 ; CHECK-SAME:  Latency=0
 
-; CHECK-DEFAULT: VMLAfd
-; CHECK-FAST:    VFMAfd
+; CHECK:       VMLAfd
 ; > VMLAfd common latency = 9
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
@@ -63,15 +95,14 @@ define arm_aapcs_vfpcc <2 x float> @Test2(<2 x float> %f1, <2 x float> %f2, <2 x
 ; > VMLAfd read-advanced latency to the next VMLAfd = 4
 ; CHECK-SAME:  Latency=4
 
-; CHECK-DEFAULT: VMLAfd
-; CHECK-FAST:    VFMAfd
+; CHECK:       VMLAfd
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
 ; CHECK:       Data
 ; > VMLAfd not-optimized latency to VMOVRRD = 9
 ; CHECK-SAME:  Latency=9
 
-; f1 * f2 + f3 * f4 + f5 * f6  ==>  VMULS, VMLAS, VMLAS
+; f1 * f2 + f3 * f4 + f5 * f6  ==>  VMULfd, VMLAfd, VMLAfd
   %mul1 = fmul <2 x float> %f1, %f2
   %mul2 = fmul <2 x float> %f3, %f4
   %mul3 = fmul <2 x float> %f5, %f6
@@ -80,6 +111,44 @@ define arm_aapcs_vfpcc <2 x float> @Test2(<2 x float> %f1, <2 x float> %f2, <2 x
   ret <2 x float> %add2
 }
 
+; ASIMD form. The 'contract' flag does not fuse NEON <2 x float> macs, so this
+; still selects the unfused VMLAfd form.
+define arm_aapcs_vfpcc <2 x float> @Test2_contract(<2 x float> %f1, <2 x float> %f2, <2 x float> %f3, <2 x float> %f4, <2 x float> %f5, <2 x float> %f6) {
+; CHECK:       Current Schedule Region
+; CHECK:       Test2_contract:%bb.0
+
+; CHECK:       VMULfd
+; > VMULfd common latency = 5
+; CHECK:       Latency            : 5
+; CHECK:       Successors:
+; CHECK:       Data
+; VMULfd read-advanced latency to VMLAfd = 0
+; CHECK-SAME:  Latency=0
+
+; CHECK:       VMLAfd
+; > VMLAfd common latency = 9
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VMLAfd read-advanced latency to the next VMLAfd = 4
+; CHECK-SAME:  Latency=4
+
+; CHECK:       VMLAfd
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VMLAfd not-optimized latency to VMOVRRD = 9
+; CHECK-SAME:  Latency=9
+
+; f1 * f2 + f3 * f4 + f5 * f6  ==>  VMULfd, VMLAfd, VMLAfd
+  %mul1 = fmul contract <2 x float> %f1, %f2
+  %mul2 = fmul contract <2 x float> %f3, %f4
+  %mul3 = fmul contract <2 x float> %f5, %f6
+  %add1 = fadd contract <2 x float> %mul1, %mul2
+  %add2 = fadd contract <2 x float> %add1, %mul3
+  ret <2 x float> %add2
+}
+
 define arm_aapcs_vfpcc float @Test3(float %f1, float %f2, float %f3, float %f4, float %f5, float %f6) {
 ; CHECK:       Current Schedule Region
 ; CHECK:       Test3:%bb.0
@@ -92,24 +161,22 @@ define arm_aapcs_vfpcc float @Test3(float %f1, float %f2, float %f3, float %f4,
 ; > VMULS read-advanced latency to VMLSS = 0
 ; CHECK-SAME:  Latency=0
 
-; CHECK-DEFAULT: VMLSS
-; CHECK-FAST:    VFNMSS
-; > VFNMSS common latency = 9
+; CHECK:       VMLSS
+; > VMLSS common latency = 9
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
 ; CHECK:       Data
-; > VFNMSS read-advanced latency to the next VMLSS = 4
+; > VMLSS read-advanced latency to the next VMLSS = 4
 ; CHECK-SAME:  Latency=4
 
-; CHECK-DEFAULT: VMLSS
-; CHECK-FAST:    VFMSS
+; CHECK:       VMLSS
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
 ; CHECK:       Data
 ; > VMLSS not-optimized latency to VMOVRS = 9
 ; CHECK-SAME:  Latency=9
 
-; f1 * f2 + f3 * f4 + f5 * f6  ==>  VMULS, VMLSS, VMLSS
+; f1 * f2 - f3 * f4 - f5 * f6  ==>  VMULS, VMLSS, VMLSS
   %mul1 = fmul float %f1, %f2
   %mul2 = fmul float %f3, %f4
   %mul3 = fmul float %f5, %f6
@@ -118,6 +185,42 @@ define arm_aapcs_vfpcc float @Test3(float %f1, float %f2, float %f3, float %f4,
   ret float %sub2
 }
 
+define arm_aapcs_vfpcc float @Test3_contract(float %f1, float %f2, float %f3, float %f4, float %f5, float %f6) {
+; CHECK:       Current Schedule Region
+; CHECK:       Test3_contract:%bb.0
+
+; CHECK:       VMULS
+; > VMULS common latency = 5
+; CHECK:       Latency            : 5
+; CHECK:       Successors:
+; CHECK:       Data
+; > VMULS read-advanced latency to VFNMSS = 0
+; CHECK-SAME:  Latency=0
+
+; CHECK:       VFNMSS
+; > VFNMSS common latency = 9
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VFNMSS read-advanced latency to the next VFMSS = 4
+; CHECK-SAME:  Latency=4
+
+; CHECK:       VFMSS
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VFMSS not-optimized latency to VMOVRS = 9
+; CHECK-SAME:  Latency=9
+
+; f1 * f2 - f3 * f4 - f5 * f6  ==>  VMULS, VFNMSS, VFMSS
+  %mul1 = fmul contract float %f1, %f2
+  %mul2 = fmul contract float %f3, %f4
+  %mul3 = fmul contract float %f5, %f6
+  %sub1 = fsub contract float %mul1, %mul2
+  %sub2 = fsub contract float %sub1, %mul3
+  ret float %sub2
+}
+
 ; ASIMD form
 define arm_aapcs_vfpcc <2 x float> @Test4(<2 x float> %f1, <2 x float> %f2, <2 x float> %f3, <2 x float> %f4, <2 x float> %f5, <2 x float> %f6) {
 ; CHECK:       Current Schedule Region
@@ -131,8 +234,7 @@ define arm_aapcs_vfpcc <2 x float> @Test4(<2 x float> %f1, <2 x float> %f2, <2 x
 ; VMULfd read-advanced latency to VMLSfd = 0
 ; CHECK-SAME:  Latency=0
 
-; CHECK-DEFAULT: VMLSfd
-; CHECK-FAST:    VFMSfd
+; CHECK:       VMLSfd
 ; > VMLSfd common latency = 9
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
@@ -140,15 +242,14 @@ define arm_aapcs_vfpcc <2 x float> @Test4(<2 x float> %f1, <2 x float> %f2, <2 x
 ; > VMLSfd read-advanced latency to the next VMLSfd = 4
 ; CHECK-SAME:  Latency=4
 
-; CHECK-DEFAULT: VMLSfd
-; CHECK-FAST:    VFMSfd
+; CHECK:       VMLSfd
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
 ; CHECK:       Data
 ; > VMLSfd not-optimized latency to VMOVRRD = 9
 ; CHECK-SAME:  Latency=9
 
-; f1 * f2 + f3 * f4 + f5 * f6  ==>  VMULS, VMLSS, VMLSS
+; f1 * f2 - f3 * f4 - f5 * f6  ==>  VMULfd, VMLSfd, VMLSfd
   %mul1 = fmul <2 x float> %f1, %f2
   %mul2 = fmul <2 x float> %f3, %f4
   %mul3 = fmul <2 x float> %f5, %f6
@@ -157,40 +258,111 @@ define arm_aapcs_vfpcc <2 x float> @Test4(<2 x float> %f1, <2 x float> %f2, <2 x
   ret <2 x float> %sub2
 }
 
+; ASIMD form. The 'contract' flag does not fuse NEON <2 x float> macs, so this
+; still selects the unfused VMLSfd form.
+define arm_aapcs_vfpcc <2 x float> @Test4_contract(<2 x float> %f1, <2 x float> %f2, <2 x float> %f3, <2 x float> %f4, <2 x float> %f5, <2 x float> %f6) {
+; CHECK:       Current Schedule Region
+; CHECK:       Test4_contract:%bb.0
+
+; CHECK:       VMULfd
+; > VMULfd common latency = 5
+; CHECK:       Latency            : 5
+; CHECK:       Successors:
+; CHECK:       Data
+; VMULfd read-advanced latency to VMLSfd = 0
+; CHECK-SAME:  Latency=0
+
+; CHECK:       VMLSfd
+; > VMLSfd common latency = 9
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VMLSfd read-advanced latency to the next VMLSfd = 4
+; CHECK-SAME:  Latency=4
+
+; CHECK:       VMLSfd
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VMLSfd not-optimized latency to VMOVRRD = 9
+; CHECK-SAME:  Latency=9
+
+; f1 * f2 - f3 * f4 - f5 * f6  ==>  VMULfd, VMLSfd, VMLSfd
+  %mul1 = fmul contract <2 x float> %f1, %f2
+  %mul2 = fmul contract <2 x float> %f3, %f4
+  %mul3 = fmul contract <2 x float> %f5, %f6
+  %sub1 = fsub contract <2 x float> %mul1, %mul2
+  %sub2 = fsub contract <2 x float> %sub1, %mul3
+  ret <2 x float> %sub2
+}
+
 define arm_aapcs_vfpcc float @Test5(float %f1, float %f2, float %f3) {
 ; CHECK:       Current Schedule Region
 ; CHECK:       Test5:%bb.0
 
-; CHECK-DEFAULT: VNMLS
-; CHECK-FAST:    VFNMS
+; CHECK:       VNMLSS
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
 ; CHECK:       Data
-; > VMLAS not-optimized latency to VMOVRS = 9
+; > VNMLSS not-optimized latency to VMOVRS = 9
 ; CHECK-SAME:  Latency=9
 
-; f1 * f2 - f3  ==>  VNMLS/VFNMS
+; f1 * f2 - f3  ==>  VNMLSS
   %mul = fmul float %f1, %f2
   %sub = fsub float %mul, %f3
   ret float %sub
 }
 
+define arm_aapcs_vfpcc float @Test5_contract(float %f1, float %f2, float %f3) {
+; CHECK:       Current Schedule Region
+; CHECK:       Test5_contract:%bb.0
+
+; CHECK:       VFNMSS
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VFNMSS not-optimized latency to VMOVRS = 9
+; CHECK-SAME:  Latency=9
+
+; f1 * f2 - f3  ==>  VFNMSS
+  %mul = fmul contract float %f1, %f2
+  %sub = fsub contract float %mul, %f3
+  ret float %sub
+}
+
 
 define arm_aapcs_vfpcc float @Test6(float %f1, float %f2, float %f3) {
 ; CHECK:       Current Schedule Region
 ; CHECK:       Test6:%bb.0
 
-; CHECK-DEFAULT: VNMLA
-; CHECK-FAST:    VFNMA
+; CHECK:       VNMLAS
 ; CHECK:       Latency            : 9
 ; CHECK:       Successors:
 ; CHECK:       Data
-; > VMLAS not-optimized latency to VMOVRS = 9
+; > VNMLAS not-optimized latency to VMOVRS = 9
 ; CHECK-SAME:  Latency=9
 
-; f1 * f2 - f3  ==>  VNMLA/VFNMA
+; -(f1 * f2) - f2  ==>  VNMLAS
   %mul = fmul float %f1, %f2
   %sub1 = fsub float -0.0, %mul
   %sub2 = fsub float %sub1, %f2
   ret float %sub2
 }
+
+define arm_aapcs_vfpcc float @Test6_contract(float %f1, float %f2, float %f3) {
+; CHECK:       Current Schedule Region
+; CHECK:       Test6_contract:%bb.0
+
+; CHECK:       VFNMAS
+; CHECK:       Latency            : 9
+; CHECK:       Successors:
+; CHECK:       Data
+; > VFNMAS not-optimized latency to VMOVRS = 9
+; CHECK-SAME:  Latency=9
+
+; -(f1 * f2) - f2  ==>  VFNMAS
+  %mul = fmul contract float %f1, %f2
+  %sub1 = fsub contract float -0.0, %mul
+  %sub2 = fsub contract float %sub1, %f2
+  ret float %sub2
+}
diff --git a/llvm/test/CodeGen/Hexagon/sffms.ll b/llvm/test/CodeGen/Hexagon/sffms.ll
index 577cad8aa9d31..a65a6f59507fc 100644
--- a/llvm/test/CodeGen/Hexagon/sffms.ll
+++ b/llvm/test/CodeGen/Hexagon/sffms.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple=hexagon -fp-contract=fast < %s | FileCheck %s
+; RUN: llc -mtriple=hexagon < %s | FileCheck %s
 
 ; Check that "Rx-=sfmpy(Rs,Rt)" is being generated for "fsub(fmul(..))"
 
@@ -16,8 +16,8 @@ entry:
   %arrayidx3 = getelementptr inbounds ptr, ptr %0, i32 %col1
   %3 = load ptr, ptr %arrayidx3, align 4
   %4 = load float, ptr %3, align 4
-  %mul = fmul float %2, %4
-  %sub = fsub float %2, %mul
+  %mul = fmul contract float %2, %4
+  %sub = fsub contract float %2, %mul
   %arrayidx10 = getelementptr inbounds float, ptr %3, i32 %col1
   store float %sub, ptr %arrayidx10, align 4
   ret void



More information about the llvm-branch-commits mailing list