[llvm] SelectionDAG: Improve expandFMINIMUM_FMAXIMUM (PR #137367)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 23 01:59:40 PST 2025


================
@@ -8745,54 +8767,62 @@ SDValue TargetLowering::expandFMINIMUM_FMAXIMUM(SDNode *N,
   // First, implement comparison not propagating NaN. If no native fmin or fmax
   // available, use plain select with setcc instead.
   SDValue MinMax;
-  unsigned CompOpcIeee = IsMax ? ISD::FMAXNUM_IEEE : ISD::FMINNUM_IEEE;
-  unsigned CompOpc = IsMax ? ISD::FMAXNUM : ISD::FMINNUM;
-
-  // FIXME: We should probably define fminnum/fmaxnum variants with correct
-  // signed zero behavior.
-  bool MinMaxMustRespectOrderedZero = false;
-
-  if (isOperationLegalOrCustom(CompOpcIeee, VT)) {
-    MinMax = DAG.getNode(CompOpcIeee, DL, VT, LHS, RHS, Flags);
-    MinMaxMustRespectOrderedZero = true;
-  } else if (isOperationLegalOrCustom(CompOpc, VT)) {
-    MinMax = DAG.getNode(CompOpc, DL, VT, LHS, RHS, Flags);
+  unsigned MinMaxOpcIeee = IsMax ? ISD::FMAXNUM_IEEE : ISD::FMINNUM_IEEE;
+  // TODO: Add ISD::FMAXNUM or ISD::FMINNUM when we are sure that they have
+  // the same behavior on all platforms.
+  unsigned MinMaxOpcNum2019 = IsMax ? ISD::FMAXIMUMNUM : ISD::FMINIMUMNUM;
+  unsigned MinMaxOpc = ISD::DELETED_NODE;
+
+  bool IsZeroOrdered = true;
+
+  if (isOperationLegal(MinMaxOpcIeee, VT))
+    MinMaxOpc = MinMaxOpcIeee;
+  else if (isOperationLegal(MinMaxOpcNum2019, VT))
+    MinMaxOpc = MinMaxOpcNum2019;
+  else if (isOperationCustom(MinMaxOpcIeee, VT))
+    MinMaxOpc = MinMaxOpcIeee;
+  else if (isOperationCustom(MinMaxOpcNum2019, VT))
+    MinMaxOpc = MinMaxOpcNum2019;
+  if (MinMaxOpc != ISD::DELETED_NODE) {
+    // TODO: we can also move NaN from RHS to LHS
+    // and LHS to RHS, so that we can keep payloads of NaNs.
+    //
+    MinMax = DAG.getNode(MinMaxOpc, DL, VT, LHS, RHS, Flags);
+    if (!N->getFlags().hasNoNaNs() &&
+        (!DAG.isKnownNeverNaN(RHS) || !DAG.isKnownNeverNaN(LHS))) {
+      ConstantFP *FPNaN = ConstantFP::get(
+          *DAG.getContext(), APFloat::getNaN(VT.getFltSemantics()));
+      MinMax =
+          DAG.getSelect(DL, VT, DAG.getSetCC(DL, CCVT, LHS, RHS, ISD::SETUO),
+                        DAG.getConstantFP(*FPNaN, DL, VT), MinMax, Flags);
+    }
   } else {
     if (VT.isVector() && !isOperationLegalOrCustom(ISD::VSELECT, VT))
       return DAG.UnrollVectorOp(N);
 
-    // NaN (if exists) will be propagated later, so orderness doesn't matter.
-    SDValue Compare =
-        DAG.getSetCC(DL, CCVT, LHS, RHS, IsMax ? ISD::SETOGT : ISD::SETOLT);
-    MinMax = DAG.getSelect(DL, VT, Compare, LHS, RHS, Flags);
+    if (!Flags.hasNoNaNs() && !DAG.isKnownNeverNaN(RHS))
+      LHS = DAG.getSelect(DL, VT, DAG.getSetCC(DL, CCVT, RHS, RHS, ISD::SETUO),
+                          RHS, LHS, Flags);
+    MinMax = DAG.getSelectCC(DL, LHS, RHS, LHS, RHS,
+                             IsMax ? ISD::SETUGT : ISD::SETULT);
+    IsZeroOrdered = false;
   }
 
-  // Propagate any NaN of both operands
-  if (!N->getFlags().hasNoNaNs() &&
-      (!DAG.isKnownNeverNaN(RHS) || !DAG.isKnownNeverNaN(LHS))) {
-    ConstantFP *FPNaN = ConstantFP::get(*DAG.getContext(),
-                                        APFloat::getNaN(VT.getFltSemantics()));
-    MinMax = DAG.getSelect(DL, VT, DAG.getSetCC(DL, CCVT, LHS, RHS, ISD::SETUO),
-                           DAG.getConstantFP(*FPNaN, DL, VT), MinMax, Flags);
-  }
+  // TODO: We need quiet sNaN if strictfp.
 
   // fminimum/fmaximum requires -0.0 less than +0.0
-  if (!MinMaxMustRespectOrderedZero && !N->getFlags().hasNoSignedZeros() &&
-      !DAG.isKnownNeverZeroFloat(RHS) && !DAG.isKnownNeverZeroFloat(LHS)) {
-    SDValue IsZero = DAG.getSetCC(DL, CCVT, MinMax,
-                                  DAG.getConstantFP(0.0, DL, VT), ISD::SETOEQ);
-    SDValue TestZero =
-        DAG.getTargetConstant(IsMax ? fcPosZero : fcNegZero, DL, MVT::i32);
-    SDValue LCmp = DAG.getSelect(
-        DL, VT, DAG.getNode(ISD::IS_FPCLASS, DL, CCVT, LHS, TestZero), LHS,
-        MinMax, Flags);
-    SDValue RCmp = DAG.getSelect(
-        DL, VT, DAG.getNode(ISD::IS_FPCLASS, DL, CCVT, RHS, TestZero), RHS,
-        LCmp, Flags);
-    MinMax = DAG.getSelect(DL, VT, IsZero, RCmp, MinMax, Flags);
-  }
-
-  return MinMax;
+  bool LHSNotZero = DAG.isKnownNeverZeroFloat(LHS);
+  bool RHSNotZero = DAG.isKnownNeverZeroFloat(RHS);
+  if (IsZeroOrdered || Flags.hasNoSignedZeros() || LHSNotZero || RHSNotZero) {
----------------
nikic wrote:

What I mean is this:
```
if (MinMaxOpc != ISD::DELETED_NODE) {
    // ...
    return MinMax;
}

// Code for select + zero handling.
```

https://github.com/llvm/llvm-project/pull/137367


More information about the llvm-commits mailing list