[llvm] [NFC][AMDGPU] NFC: Let IR level callers query the FMA/FMAD predicates (PR #213310)

Dmitry Sidorov via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 31 09:47:31 PDT 2026


https://github.com/MrSidims created https://github.com/llvm/llvm-project/pull/213310

isFMADLegal and isFMAFasterThanFMulAndFAdd read the denormal mode out of the MachineFunction, so nothing before instruction selection can ask them whether a given fmul/fadd pair will be fused. Split the denormal mode out into explicit arguments and make the existing entry points thin wrappers.

A small refactoring prior changes in getArithmeticInstrCost and isProfitableToSinkOperands.

Contributes to #211092

Assisted-By: Claude Opus 5

>From e2f3cd3d08702a97644e78e9c7eda85ccc8d06af Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Fri, 31 Jul 2026 17:07:25 +0200
Subject: [PATCH] [NFC][AMDGPU] NFC: Let IR level callers query the FMA/FMAD
 predicates

isFMADLegal and isFMAFasterThanFMulAndFAdd read the denormal mode out of
the MachineFunction, so nothing before instruction selection can ask them
whether a given fmul/fadd pair will be fused. Split the denormal mode out
into explicit arguments and make the existing entry points thin wrappers.

A small refactoring prior changes in getArithmeticInstrCost and
isProfitableToSinkOperands.

Contributes to #211092

Assisted-By: Claude Opus 5
---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 49 ++++++++++++++---------
 llvm/lib/Target/AMDGPU/SIISelLowering.h   |  8 ++++
 2 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index b5e2a36ad9f19..8614ffbd2d1fa 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -7420,8 +7420,8 @@ LLT SITargetLowering::getPreferredShiftAmountTy(LLT Ty) const {
 // however does not support denormals, so we do report fma as faster if we have
 // a fast fma device and require denormals.
 //
-bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
-                                                  EVT VT) const {
+bool SITargetLowering::isFMAFasterThanFMulAndFAdd(
+    EVT VT, bool FlushF32Denormals, bool FlushF64F16Denormals) const {
   VT = VT.getScalarType();
 
   switch (VT.getSimpleVT().SimpleTy) {
@@ -7433,7 +7433,7 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
     // Otherwise f32 mad is always full rate and returns the same result as
     // the separate operations so should be preferred over fma.
     // However does not support denormals.
-    if (!denormalModeIsFlushAllF32(MF))
+    if (!FlushF32Denormals)
       return Subtarget->hasFastFMAF32() || Subtarget->hasDLInsts();
 
     // If the subtarget has v_fmac_f32, that's just as good as v_mac_f32.
@@ -7443,7 +7443,7 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
     return true;
   case MVT::f16:
   case MVT::bf16:
-    return Subtarget->has16BitInsts() && !denormalModeIsFlushAllF64F16(MF);
+    return Subtarget->has16BitInsts() && !FlushF64F16Denormals;
   default:
     break;
   }
@@ -7451,6 +7451,12 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
   return false;
 }
 
+bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
+                                                  EVT VT) const {
+  return isFMAFasterThanFMulAndFAdd(VT, denormalModeIsFlushAllF32(MF),
+                                    denormalModeIsFlushAllF64F16(MF));
+}
+
 bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
                                                   LLT Ty) const {
   switch (Ty.getScalarSizeInBits()) {
@@ -7467,33 +7473,38 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
   return false;
 }
 
+bool SITargetLowering::isFMADLegal(EVT VT, bool FlushF32Denormals,
+                                   bool FlushF64F16Denormals) const {
+  // TODO: Check future ftz flag
+  // v_mad_f32/v_mac_f32 do not support denormals.
+  if (VT == MVT::f32)
+    return Subtarget->hasMadMacF32Insts() && FlushF32Denormals;
+  if (VT == MVT::f16)
+    return Subtarget->hasMadF16() && FlushF64F16Denormals;
+
+  return false;
+}
+
 bool SITargetLowering::isFMADLegal(const MachineInstr &MI, LLT Ty) const {
   if (!Ty.isScalar())
     return false;
 
+  const MachineFunction &MF = *MI.getMF();
   if (Ty.getScalarSizeInBits() == 16)
-    return Subtarget->hasMadF16() && denormalModeIsFlushAllF64F16(*MI.getMF());
+    return isFMADLegal(MVT::f16, denormalModeIsFlushAllF32(MF),
+                       denormalModeIsFlushAllF64F16(MF));
   if (Ty.getScalarSizeInBits() == 32)
-    return Subtarget->hasMadMacF32Insts() &&
-           denormalModeIsFlushAllF32(*MI.getMF());
+    return isFMADLegal(MVT::f32, denormalModeIsFlushAllF32(MF),
+                       denormalModeIsFlushAllF64F16(MF));
 
   return false;
 }
 
 bool SITargetLowering::isFMADLegal(const SelectionDAG &DAG,
                                    const SDNode *N) const {
-  // TODO: Check future ftz flag
-  // v_mad_f32/v_mac_f32 do not support denormals.
-  EVT VT = N->getValueType(0);
-  if (VT == MVT::f32)
-    return Subtarget->hasMadMacF32Insts() &&
-           denormalModeIsFlushAllF32(DAG.getMachineFunction());
-  if (VT == MVT::f16) {
-    return Subtarget->hasMadF16() &&
-           denormalModeIsFlushAllF64F16(DAG.getMachineFunction());
-  }
-
-  return false;
+  const MachineFunction &MF = DAG.getMachineFunction();
+  return isFMADLegal(N->getValueType(0), denormalModeIsFlushAllF32(MF),
+                     denormalModeIsFlushAllF64F16(MF));
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index be4bb6d825b46..c8f4c65e55193 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -503,6 +503,14 @@ class SITargetLowering final : public AMDGPUTargetLowering {
   bool isFMADLegal(const SelectionDAG &DAG, const SDNode *N) const override;
   bool isFMADLegal(const MachineInstr &MI, const LLT Ty) const override;
 
+  /// Variants taking the denormal mode directly, for IR level callers which
+  /// have no MachineFunction to read it from. \p VT is the legalized type of
+  /// the operation.
+  bool isFMAFasterThanFMulAndFAdd(EVT VT, bool FlushF32Denormals,
+                                  bool FlushF64F16Denormals) const;
+  bool isFMADLegal(EVT VT, bool FlushF32Denormals,
+                   bool FlushF64F16Denormals) const;
+
   SDValue splitUnaryVectorOp(SDValue Op, SelectionDAG &DAG) const;
   SDValue splitBinaryVectorOp(SDValue Op, SelectionDAG &DAG) const;
   SDValue splitTernaryVectorOp(SDValue Op, SelectionDAG &DAG) const;



More information about the llvm-commits mailing list