[llvm] 5be66d0 - [NFC][AMDGPU] Let IR level callers query the FMA/FMAD predicates (#213310)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 6 17:52:05 PDT 2026
Author: Dmitry Sidorov
Date: 2026-08-07T00:52:00Z
New Revision: 5be66d0a9afe1268bf7ff75c69a32b141d4f0096
URL: https://github.com/llvm/llvm-project/commit/5be66d0a9afe1268bf7ff75c69a32b141d4f0096
DIFF: https://github.com/llvm/llvm-project/commit/5be66d0a9afe1268bf7ff75c69a32b141d4f0096.diff
LOG: [NFC][AMDGPU] Let IR level callers query the FMA/FMAD predicates (#213310)
isFMADLegal and isFMAFasterThanFMulAndFAdd read the denormal mode out of
the MachineFunction, so nothing before instruction selection can ask
them whether an fmul/fadd pair will be fused. Take an explicit
DenormalFPEnv instead, and make the existing MachineFunction /
SelectionDAG / MachineInstr entry points thin wrappers over it.
Also override the IR level isFMAFasterThanFMulAndFAdd hook. The two
views agree by construction, since SIModeRegisterDefaults copies its
denormal fields out of getDenormalFPEnv.
isFMADLegal uses VT as written and does not look through vectors, so a
vector type reports false, as in the SelectionDAG overload it was
extracted from.
The patch is preparation for querying these from getArithmeticInstrCost
and a revived isProfitableToSinkOperands.
Contributes to #211092
Assisted-By: Claude Opus 5
Added:
Modified:
llvm/lib/Target/AMDGPU/SIISelLowering.cpp
llvm/lib/Target/AMDGPU/SIISelLowering.h
llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index f53fd0d74e48e..9b35b24663a58 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -69,6 +69,10 @@ static cl::opt<bool> UseDivergentRegisterIndexing(
cl::desc("Use indirect register addressing for divergent indexes"),
cl::init(false));
+static DenormalFPEnv getDenormalFPEnv(const MachineFunction &MF) {
+ return MF.getInfo<SIMachineFunctionInfo>()->getMode().getDenormalFPEnv();
+}
+
static bool denormalModeIsFlushAllF32(const MachineFunction &MF) {
const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
return Info->getMode().FP32Denormals == DenormalMode::getPreserveSign();
@@ -7438,9 +7442,11 @@ 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,
+ DenormalFPEnv FPEnv) const {
VT = VT.getScalarType();
+ if (!VT.isSimple())
+ return false;
switch (VT.getSimpleVT().SimpleTy) {
case MVT::f32: {
@@ -7451,7 +7457,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 (FPEnv.F32Mode != DenormalMode::getPreserveSign())
return Subtarget->hasFastFMAF32() || Subtarget->hasDLInsts();
// If the subtarget has v_fmac_f32, that's just as good as v_mac_f32.
@@ -7461,7 +7467,8 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
return true;
case MVT::f16:
case MVT::bf16:
- return Subtarget->has16BitInsts() && !denormalModeIsFlushAllF64F16(MF);
+ return Subtarget->has16BitInsts() &&
+ FPEnv.DefaultMode != DenormalMode::getPreserveSign();
default:
break;
}
@@ -7469,6 +7476,18 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
return false;
}
+bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
+ EVT VT) const {
+ return isFMAFasterThanFMulAndFAdd(VT, getDenormalFPEnv(MF));
+}
+
+bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const Function &F,
+ Type *Ty) const {
+ return isFMAFasterThanFMulAndFAdd(
+ getValueType(F.getDataLayout(), Ty, /*AllowUnknown=*/true),
+ F.getDenormalFPEnv());
+}
+
bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
LLT Ty) const {
switch (Ty.getScalarSizeInBits()) {
@@ -7485,33 +7504,36 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
return false;
}
+bool SITargetLowering::isFMADLegal(EVT VT, DenormalFPEnv FPEnv) const {
+ // TODO: Check future ftz flag
+ // v_mad_f32/v_mac_f32 do not support denormals.
+ if (VT == MVT::f32)
+ return Subtarget->hasMadMacF32Insts() &&
+ FPEnv.F32Mode == DenormalMode::getPreserveSign();
+ if (VT == MVT::f16)
+ return Subtarget->hasMadF16() &&
+ FPEnv.DefaultMode == DenormalMode::getPreserveSign();
+
+ return false;
+}
+
bool SITargetLowering::isFMADLegal(const MachineInstr &MI, LLT Ty) const {
if (!Ty.isScalar())
return false;
+ DenormalFPEnv FPEnv = getDenormalFPEnv(*MI.getMF());
if (Ty.getScalarSizeInBits() == 16)
- return Subtarget->hasMadF16() && denormalModeIsFlushAllF64F16(*MI.getMF());
+ return isFMADLegal(MVT::f16, FPEnv);
if (Ty.getScalarSizeInBits() == 32)
- return Subtarget->hasMadMacF32Insts() &&
- denormalModeIsFlushAllF32(*MI.getMF());
+ return isFMADLegal(MVT::f32, FPEnv);
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;
+ return isFMADLegal(N->getValueType(0),
+ getDenormalFPEnv(DAG.getMachineFunction()));
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index 3e0e5da94471f..b2f5d70194567 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -17,6 +17,7 @@
#include "AMDGPUArgumentUsageInfo.h"
#include "AMDGPUISelLowering.h"
#include "SIDefines.h"
+#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/CodeGen/MachineFunction.h"
namespace llvm {
@@ -506,6 +507,15 @@ 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 for IR level callers, which have no MachineFunction to read the
+ /// denormal mode from and must pass \p FPEnv explicitly.
+ bool isFMAFasterThanFMulAndFAdd(EVT VT, DenormalFPEnv FPEnv) const;
+
+ /// \p VT is used as written, so a vector type reports false.
+ bool isFMADLegal(EVT VT, DenormalFPEnv FPEnv) const;
+
+ bool isFMAFasterThanFMulAndFAdd(const Function &F, Type *Ty) const override;
+
SDValue splitUnaryVectorOp(SDValue Op, SelectionDAG &DAG) const;
SDValue splitBinaryVectorOp(SDValue Op, SelectionDAG &DAG) const;
SDValue splitTernaryVectorOp(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h b/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h
index c86678a732535..f98c60a51e379 100644
--- a/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h
+++ b/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h
@@ -56,6 +56,11 @@ struct SIModeRegisterDefaults {
FP64FP16Denormals == Other.FP64FP16Denormals;
}
+ /// Get the denormal handling described by this mode.
+ DenormalFPEnv getDenormalFPEnv() const {
+ return DenormalFPEnv(FP64FP16Denormals, FP32Denormals);
+ }
+
/// Get the encoding value for the FP_DENORM bits of the mode register for the
/// FP32 denormal mode.
uint32_t fpDenormModeSPValue() const {
More information about the llvm-commits
mailing list