[llvm] DAGCombiner: Support fmaximum/fminimum and fmaximumnum/fminimumnum (PR #137318)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 26 00:32:16 PDT 2025


================
@@ -6333,60 +6333,70 @@ static bool arebothOperandsNotNan(SDValue Operand1, SDValue Operand2,
   return DAG.isKnownNeverNaN(Operand2) && DAG.isKnownNeverNaN(Operand1);
 }
 
-// FIXME: use FMINIMUMNUM if possible, such as for RISC-V.
-static unsigned getMinMaxOpcodeForFP(SDValue Operand1, SDValue Operand2,
-                                     ISD::CondCode CC, unsigned OrAndOpcode,
-                                     SelectionDAG &DAG,
-                                     bool isFMAXNUMFMINNUM_IEEE,
-                                     bool isFMAXNUMFMINNUM) {
-  // The optimization cannot be applied for all the predicates because
-  // of the way FMINNUM/FMAXNUM and FMINNUM_IEEE/FMAXNUM_IEEE handle
-  // NaNs. For FMINNUM_IEEE/FMAXNUM_IEEE, the optimization cannot be
-  // applied at all if one of the operands is a signaling NaN.
-
-  // It is safe to use FMINNUM_IEEE/FMAXNUM_IEEE if all the operands
-  // are non NaN values.
-  if (((CC == ISD::SETLT || CC == ISD::SETLE) && (OrAndOpcode == ISD::OR)) ||
-      ((CC == ISD::SETGT || CC == ISD::SETGE) && (OrAndOpcode == ISD::AND)))
-    return arebothOperandsNotNan(Operand1, Operand2, DAG) &&
-                   isFMAXNUMFMINNUM_IEEE
-               ? ISD::FMINNUM_IEEE
-               : ISD::DELETED_NODE;
-  else if (((CC == ISD::SETGT || CC == ISD::SETGE) &&
-            (OrAndOpcode == ISD::OR)) ||
-           ((CC == ISD::SETLT || CC == ISD::SETLE) &&
-            (OrAndOpcode == ISD::AND)))
-    return arebothOperandsNotNan(Operand1, Operand2, DAG) &&
-                   isFMAXNUMFMINNUM_IEEE
-               ? ISD::FMAXNUM_IEEE
-               : ISD::DELETED_NODE;
-  // Both FMINNUM/FMAXNUM and FMINNUM_IEEE/FMAXNUM_IEEE handle quiet
-  // NaNs in the same way. But, FMINNUM/FMAXNUM and FMINNUM_IEEE/
-  // FMAXNUM_IEEE handle signaling NaNs differently. If we cannot prove
-  // that there are not any sNaNs, then the optimization is not valid
-  // for FMINNUM_IEEE/FMAXNUM_IEEE. In the presence of sNaNs, we apply
-  // the optimization using FMINNUM/FMAXNUM for the following cases. If
-  // we can prove that we do not have any sNaNs, then we can do the
-  // optimization using FMINNUM_IEEE/FMAXNUM_IEEE for the following
-  // cases.
-  else if (((CC == ISD::SETOLT || CC == ISD::SETOLE) &&
-            (OrAndOpcode == ISD::OR)) ||
-           ((CC == ISD::SETUGT || CC == ISD::SETUGE) &&
-            (OrAndOpcode == ISD::AND)))
-    return isFMAXNUMFMINNUM ? ISD::FMINNUM
-                            : arebothOperandsNotSNan(Operand1, Operand2, DAG) &&
-                                      isFMAXNUMFMINNUM_IEEE
-                                  ? ISD::FMINNUM_IEEE
-                                  : ISD::DELETED_NODE;
-  else if (((CC == ISD::SETOGT || CC == ISD::SETOGE) &&
-            (OrAndOpcode == ISD::OR)) ||
-           ((CC == ISD::SETULT || CC == ISD::SETULE) &&
-            (OrAndOpcode == ISD::AND)))
-    return isFMAXNUMFMINNUM ? ISD::FMAXNUM
-                            : arebothOperandsNotSNan(Operand1, Operand2, DAG) &&
-                                      isFMAXNUMFMINNUM_IEEE
-                                  ? ISD::FMAXNUM_IEEE
-                                  : ISD::DELETED_NODE;
+static unsigned
+getMinMaxOpcodeForFP(SDValue Operand1, SDValue Operand2, ISD::CondCode CC,
+                     unsigned OrAndOpcode, SelectionDAG &DAG,
+                     bool isFMAXNUMFMINNUM_IEEE, bool isFMAXNUMFMINNUM,
+                     bool isFMAXIMUMFMINIMUM, bool isFMAXIMUMNUMFMINIMUMNUM) {
+  bool isMax = true;
+  // SETLT/SETLE/SETGT/SETGE are undefined if any Operand is NaN. We
+  // treat them as SETOLT/SETOLE/SETOGT/SETOGE.
+  if (((CC == ISD::SETLT || CC == ISD::SETLE || CC == ISD::SETOLT ||
+        CC == ISD::SETOLE) &&
+       (OrAndOpcode == ISD::OR)) ||
+      ((CC == ISD::SETUGT || CC == ISD::SETUGE) && (OrAndOpcode == ISD::AND))) {
+    isMax = false;
+    if (arebothOperandsNotSNan(Operand1, Operand2, DAG) &&
+        isFMAXNUMFMINNUM_IEEE)
+      return ISD::FMINNUM_IEEE;
+    if (arebothOperandsNotSNan(Operand1, Operand2, DAG) && isFMAXNUMFMINNUM)
+      return ISD::FMINNUM;
+    if (isFMAXIMUMNUMFMINIMUMNUM)
+      return ISD::FMINIMUMNUM;
+  } else if (((CC == ISD::SETLT || CC == ISD::SETLE || CC == ISD::SETOLT ||
+               CC == ISD::SETOLE) &&
+              (OrAndOpcode == ISD::AND)) ||
+             ((CC == ISD::SETUGT || CC == ISD::SETUGE) &&
+              (OrAndOpcode == ISD::OR))) {
+    isMax = true;
+    if (isFMAXIMUMFMINIMUM)
+      return ISD::FMAXIMUM;
+  } else if (((CC == ISD::SETGT || CC == ISD::SETGE || CC == ISD::SETOGT ||
+               CC == ISD::SETOGE) &&
+              (OrAndOpcode == ISD::OR)) ||
+             ((CC == ISD::SETULT || CC == ISD::SETULE) &&
+              (OrAndOpcode == ISD::AND))) {
+    isMax = true;
+    if (arebothOperandsNotSNan(Operand1, Operand2, DAG) &&
+        isFMAXNUMFMINNUM_IEEE)
----------------
arsenm wrote:

I think this would be easier if we completed the migration away from the IEEE opcodes first 

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


More information about the llvm-commits mailing list