[llvm] 51a9052 - [X86] Extract select to min/max combining into separate function (NFC)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 9 07:30:55 PDT 2026


Author: Nikita Popov
Date: 2026-03-09T15:30:42+01:00
New Revision: 51a9052f1cc1c0c6120ea646239cbf3e5e21b0ed

URL: https://github.com/llvm/llvm-project/commit/51a9052f1cc1c0c6120ea646239cbf3e5e21b0ed
DIFF: https://github.com/llvm/llvm-project/commit/51a9052f1cc1c0c6120ea646239cbf3e5e21b0ed.diff

LOG: [X86] Extract select to min/max combining into separate function (NFC)

Added: 
    

Modified: 
    llvm/lib/Target/X86/X86ISelLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index c7dd6c76c18f5..4ce343922a02e 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -48139,6 +48139,182 @@ static SDValue commuteSelect(SDNode *N, SelectionDAG &DAG, const SDLoc &DL,
   return DAG.getSelect(DL, LHS.getValueType(), Cond, RHS, LHS);
 }
 
+// If we have SSE[12] support, try to form min/max nodes. SSE min/max
+// instructions match the semantics of the common C idiom x<y?x:y but not
+// x<=y?x:y, because of how they handle negative zero (which can be
+// ignored in unsafe-math mode).
+// We also try to create v2f32 min/max nodes, which we later widen to v4f32.
+static SDValue combineSelectToMinMax(SelectionDAG &DAG,
+                                     const X86Subtarget &Subtarget, SDNode *N) {
+  SDLoc DL(N);
+  SDValue Cond = N->getOperand(0);
+  SDValue LHS = N->getOperand(1);
+  SDValue RHS = N->getOperand(2);
+  EVT VT = LHS.getValueType();
+  const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+  if ((Cond.getOpcode() != ISD::SETCC &&
+       Cond.getOpcode() != ISD::STRICT_FSETCCS) ||
+      !VT.isFloatingPoint() || VT == MVT::f80 || VT == MVT::f128 ||
+      isSoftF16(VT, Subtarget) || (!TLI.isTypeLegal(VT) && VT != MVT::v2f32) ||
+      ((VT == MVT::v8f16 || VT == MVT::v16f16) && !Subtarget.hasVLX()) ||
+      (!Subtarget.hasSSE2() &&
+       (!Subtarget.hasSSE1() || VT.getScalarType() != MVT::f32)))
+    return SDValue();
+
+  bool IsStrict = Cond->isStrictFPOpcode();
+  ISD::CondCode CC =
+      cast<CondCodeSDNode>(Cond.getOperand(IsStrict ? 3 : 2))->get();
+  SDValue Op0 = Cond.getOperand(IsStrict ? 1 : 0);
+  SDValue Op1 = Cond.getOperand(IsStrict ? 2 : 1);
+
+  unsigned Opcode = 0;
+  // Check for x CC y ? x : y.
+  if (DAG.isEqualTo(LHS, Op0) && DAG.isEqualTo(RHS, Op1)) {
+    switch (CC) {
+    default:
+      break;
+    case ISD::SETULT:
+      // Converting this to a min would handle NaNs incorrectly, and swapping
+      // the operands would cause it to handle comparisons between positive
+      // and negative zero incorrectly.
+      if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) {
+        if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
+            !(DAG.isKnownNeverZeroFloat(LHS) || DAG.isKnownNeverZeroFloat(RHS)))
+          break;
+        std::swap(LHS, RHS);
+      }
+      Opcode = X86ISD::FMIN;
+      break;
+    case ISD::SETOLE:
+      // Converting this to a min would handle comparisons between positive
+      // and negative zero incorrectly.
+      if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
+          !DAG.isKnownNeverZeroFloat(LHS) && !DAG.isKnownNeverZeroFloat(RHS))
+        break;
+      Opcode = X86ISD::FMIN;
+      break;
+    case ISD::SETULE:
+      // Converting this to a min would handle both negative zeros and NaNs
+      // incorrectly, but we can swap the operands to fix both.
+      std::swap(LHS, RHS);
+      [[fallthrough]];
+    case ISD::SETOLT:
+    case ISD::SETLT:
+    case ISD::SETLE:
+      Opcode = X86ISD::FMIN;
+      break;
+
+    case ISD::SETOGE:
+      // Converting this to a max would handle comparisons between positive
+      // and negative zero incorrectly.
+      if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
+          !DAG.isKnownNeverZeroFloat(LHS) && !DAG.isKnownNeverZeroFloat(RHS))
+        break;
+      Opcode = X86ISD::FMAX;
+      break;
+    case ISD::SETUGT:
+      // Converting this to a max would handle NaNs incorrectly, and swapping
+      // the operands would cause it to handle comparisons between positive
+      // and negative zero incorrectly.
+      if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) {
+        if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
+            !(DAG.isKnownNeverZeroFloat(LHS) || DAG.isKnownNeverZeroFloat(RHS)))
+          break;
+        std::swap(LHS, RHS);
+      }
+      Opcode = X86ISD::FMAX;
+      break;
+    case ISD::SETUGE:
+      // Converting this to a max would handle both negative zeros and NaNs
+      // incorrectly, but we can swap the operands to fix both.
+      std::swap(LHS, RHS);
+      [[fallthrough]];
+    case ISD::SETOGT:
+    case ISD::SETGT:
+    case ISD::SETGE:
+      Opcode = X86ISD::FMAX;
+      break;
+    }
+    // Check for x CC y ? y : x -- a min/max with reversed arms.
+  } else if (DAG.isEqualTo(LHS, Op1) && DAG.isEqualTo(RHS, Op0)) {
+    switch (CC) {
+    default:
+      break;
+    case ISD::SETOGE:
+      // Converting this to a min would handle comparisons between positive
+      // and negative zero incorrectly, and swapping the operands would
+      // cause it to handle NaNs incorrectly.
+      if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
+          !(DAG.isKnownNeverZeroFloat(LHS) || DAG.isKnownNeverZeroFloat(RHS))) {
+        if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))
+          break;
+        std::swap(LHS, RHS);
+      }
+      Opcode = X86ISD::FMIN;
+      break;
+    case ISD::SETUGT:
+      // Converting this to a min would handle NaNs incorrectly.
+      if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))
+        break;
+      Opcode = X86ISD::FMIN;
+      break;
+    case ISD::SETUGE:
+      // Converting this to a min would handle both negative zeros and NaNs
+      // incorrectly, but we can swap the operands to fix both.
+      std::swap(LHS, RHS);
+      [[fallthrough]];
+    case ISD::SETOGT:
+    case ISD::SETGT:
+    case ISD::SETGE:
+      Opcode = X86ISD::FMIN;
+      break;
+
+    case ISD::SETULT:
+      // Converting this to a max would handle NaNs incorrectly.
+      if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))
+        break;
+      Opcode = X86ISD::FMAX;
+      break;
+    case ISD::SETOLE:
+      // Converting this to a max would handle comparisons between positive
+      // and negative zero incorrectly, and swapping the operands would
+      // cause it to handle NaNs incorrectly.
+      if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
+          !DAG.isKnownNeverZeroFloat(LHS) && !DAG.isKnownNeverZeroFloat(RHS)) {
+        if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))
+          break;
+        std::swap(LHS, RHS);
+      }
+      Opcode = X86ISD::FMAX;
+      break;
+    case ISD::SETULE:
+      // Converting this to a max would handle both negative zeros and NaNs
+      // incorrectly, but we can swap the operands to fix both.
+      std::swap(LHS, RHS);
+      [[fallthrough]];
+    case ISD::SETOLT:
+    case ISD::SETLT:
+    case ISD::SETLE:
+      Opcode = X86ISD::FMAX;
+      break;
+    }
+  }
+
+  if (!Opcode)
+    return SDValue();
+
+  // Propagate fast-math-flags.
+  SelectionDAG::FlagInserter FlagsInserter(DAG, N->getFlags());
+  if (IsStrict) {
+    SDValue Ret = DAG.getNode(
+        Opcode == X86ISD::FMIN ? X86ISD::STRICT_FMIN : X86ISD::STRICT_FMAX, DL,
+        {N->getValueType(0), MVT::Other}, {Cond.getOperand(0), LHS, RHS});
+    DAG.ReplaceAllUsesOfValueWith(Cond.getValue(1), Ret.getValue(1));
+    return Ret;
+  }
+  return DAG.getNode(Opcode, DL, N->getValueType(0), LHS, RHS);
+}
+
 /// Do target-specific dag combines on SELECT and VSELECT nodes.
 static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
                              TargetLowering::DAGCombinerInfo &DCI,
@@ -48236,173 +48412,8 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
     }
   }
 
-  // If we have SSE[12] support, try to form min/max nodes. SSE min/max
-  // instructions match the semantics of the common C idiom x<y?x:y but not
-  // x<=y?x:y, because of how they handle negative zero (which can be
-  // ignored in unsafe-math mode).
-  // We also try to create v2f32 min/max nodes, which we later widen to v4f32.
-  if ((Cond.getOpcode() == ISD::SETCC ||
-       Cond.getOpcode() == ISD::STRICT_FSETCCS) &&
-      VT.isFloatingPoint() && VT != MVT::f80 && VT != MVT::f128 &&
-      !isSoftF16(VT, Subtarget) && (TLI.isTypeLegal(VT) || VT == MVT::v2f32) &&
-      ((VT != MVT::v8f16 && VT != MVT::v16f16) || Subtarget.hasVLX()) &&
-      (Subtarget.hasSSE2() ||
-       (Subtarget.hasSSE1() && VT.getScalarType() == MVT::f32))) {
-    bool IsStrict = Cond->isStrictFPOpcode();
-    ISD::CondCode CC =
-        cast<CondCodeSDNode>(Cond.getOperand(IsStrict ? 3 : 2))->get();
-    SDValue Op0 = Cond.getOperand(IsStrict ? 1 : 0);
-    SDValue Op1 = Cond.getOperand(IsStrict ? 2 : 1);
-
-    unsigned Opcode = 0;
-    // Check for x CC y ? x : y.
-    if (DAG.isEqualTo(LHS, Op0) && DAG.isEqualTo(RHS, Op1)) {
-      switch (CC) {
-      default: break;
-      case ISD::SETULT:
-        // Converting this to a min would handle NaNs incorrectly, and swapping
-        // the operands would cause it to handle comparisons between positive
-        // and negative zero incorrectly.
-        if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) {
-          if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
-              !(DAG.isKnownNeverZeroFloat(LHS) ||
-                DAG.isKnownNeverZeroFloat(RHS)))
-            break;
-          std::swap(LHS, RHS);
-        }
-        Opcode = X86ISD::FMIN;
-        break;
-      case ISD::SETOLE:
-        // Converting this to a min would handle comparisons between positive
-        // and negative zero incorrectly.
-        if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
-            !DAG.isKnownNeverZeroFloat(LHS) && !DAG.isKnownNeverZeroFloat(RHS))
-          break;
-        Opcode = X86ISD::FMIN;
-        break;
-      case ISD::SETULE:
-        // Converting this to a min would handle both negative zeros and NaNs
-        // incorrectly, but we can swap the operands to fix both.
-        std::swap(LHS, RHS);
-        [[fallthrough]];
-      case ISD::SETOLT:
-      case ISD::SETLT:
-      case ISD::SETLE:
-        Opcode = X86ISD::FMIN;
-        break;
-
-      case ISD::SETOGE:
-        // Converting this to a max would handle comparisons between positive
-        // and negative zero incorrectly.
-        if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
-            !DAG.isKnownNeverZeroFloat(LHS) && !DAG.isKnownNeverZeroFloat(RHS))
-          break;
-        Opcode = X86ISD::FMAX;
-        break;
-      case ISD::SETUGT:
-        // Converting this to a max would handle NaNs incorrectly, and swapping
-        // the operands would cause it to handle comparisons between positive
-        // and negative zero incorrectly.
-        if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) {
-          if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
-              !(DAG.isKnownNeverZeroFloat(LHS) ||
-                DAG.isKnownNeverZeroFloat(RHS)))
-            break;
-          std::swap(LHS, RHS);
-        }
-        Opcode = X86ISD::FMAX;
-        break;
-      case ISD::SETUGE:
-        // Converting this to a max would handle both negative zeros and NaNs
-        // incorrectly, but we can swap the operands to fix both.
-        std::swap(LHS, RHS);
-        [[fallthrough]];
-      case ISD::SETOGT:
-      case ISD::SETGT:
-      case ISD::SETGE:
-        Opcode = X86ISD::FMAX;
-        break;
-      }
-    // Check for x CC y ? y : x -- a min/max with reversed arms.
-    } else if (DAG.isEqualTo(LHS, Op1) && DAG.isEqualTo(RHS, Op0)) {
-      switch (CC) {
-      default: break;
-      case ISD::SETOGE:
-        // Converting this to a min would handle comparisons between positive
-        // and negative zero incorrectly, and swapping the operands would
-        // cause it to handle NaNs incorrectly.
-        if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
-            !(DAG.isKnownNeverZeroFloat(LHS) ||
-              DAG.isKnownNeverZeroFloat(RHS))) {
-          if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))
-            break;
-          std::swap(LHS, RHS);
-        }
-        Opcode = X86ISD::FMIN;
-        break;
-      case ISD::SETUGT:
-        // Converting this to a min would handle NaNs incorrectly.
-        if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))
-          break;
-        Opcode = X86ISD::FMIN;
-        break;
-      case ISD::SETUGE:
-        // Converting this to a min would handle both negative zeros and NaNs
-        // incorrectly, but we can swap the operands to fix both.
-        std::swap(LHS, RHS);
-        [[fallthrough]];
-      case ISD::SETOGT:
-      case ISD::SETGT:
-      case ISD::SETGE:
-        Opcode = X86ISD::FMIN;
-        break;
-
-      case ISD::SETULT:
-        // Converting this to a max would handle NaNs incorrectly.
-        if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))
-          break;
-        Opcode = X86ISD::FMAX;
-        break;
-      case ISD::SETOLE:
-        // Converting this to a max would handle comparisons between positive
-        // and negative zero incorrectly, and swapping the operands would
-        // cause it to handle NaNs incorrectly.
-        if (!DAG.getTarget().Options.NoSignedZerosFPMath &&
-            !DAG.isKnownNeverZeroFloat(LHS) &&
-            !DAG.isKnownNeverZeroFloat(RHS)) {
-          if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))
-            break;
-          std::swap(LHS, RHS);
-        }
-        Opcode = X86ISD::FMAX;
-        break;
-      case ISD::SETULE:
-        // Converting this to a max would handle both negative zeros and NaNs
-        // incorrectly, but we can swap the operands to fix both.
-        std::swap(LHS, RHS);
-        [[fallthrough]];
-      case ISD::SETOLT:
-      case ISD::SETLT:
-      case ISD::SETLE:
-        Opcode = X86ISD::FMAX;
-        break;
-      }
-    }
-
-    if (Opcode) {
-      // Propagate fast-math-flags.
-      SelectionDAG::FlagInserter FlagsInserter(DAG, N->getFlags());
-      if (IsStrict) {
-        SDValue Ret = DAG.getNode(Opcode == X86ISD::FMIN ? X86ISD::STRICT_FMIN
-                                                         : X86ISD::STRICT_FMAX,
-                                  DL, {N->getValueType(0), MVT::Other},
-                                  {Cond.getOperand(0), LHS, RHS});
-        DAG.ReplaceAllUsesOfValueWith(Cond.getValue(1), Ret.getValue(1));
-        return Ret;
-      }
-      return DAG.getNode(Opcode, DL, N->getValueType(0), LHS, RHS);
-    }
-  }
+  if (SDValue Res = combineSelectToMinMax(DAG, Subtarget, N))
+    return Res;
 
   // Some mask scalar intrinsics rely on checking if only one bit is set
   // and implement it in C code like this:


        


More information about the llvm-commits mailing list