[llvm] [DAGCombiner] Fold smax(X, -1)/smin(X, 0) to bitwise shift forms (PR #206242)

Aayush Shrivastava via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 29 04:02:42 PDT 2026


================
@@ -6307,6 +6307,35 @@ SDValue DAGCombiner::visitIMINMAX(SDNode *N) {
   if (SDValue RMINMAX = reassociateOps(Opcode, DL, N0, N1, N->getFlags()))
     return RMINMAX;
 
+  // Fold sign-extension masks using arithmetic shift:
+  //   smax(X, -1) -> or(X,  ashr(X, BW-1))
+  //   smin(X,  0) -> and(X, ashr(X, BW-1))
+  // ashr(X, BW-1) sign-extends the sign bit: 0 for X>=0, -1 for X<0.
+  // OR with X yields X (non-negative) or -1 (negative) = smax(X,-1).
+  // AND with X yields 0 (non-negative) or X (negative)  = smin(X, 0).
+  // Both reduce to two instructions vs. a compare+cmov on x86-64.
+  // Only fold when the target has no native SMAX/SMIN instruction for this
+  // type (isOperationExpand), the type is legal (not needing splitting), and
+  // the operand is not a min/max chain (preserving saturation patterns such as
+  // RISCV-P sati which combine smin+smax into a single instruction).
+  if (TLI.isTypeLegal(VT) &&
+      !TLI.shouldAvoidTransformToShift(VT, VT.getScalarSizeInBits() - 1)) {
+    if (Opcode == ISD::SMAX && TLI.isOperationExpand(ISD::SMAX, VT) &&
+        N0.getOpcode() != ISD::SMIN && isAllOnesConstant(N1)) {
----------------
iamaayushrivastava wrote:

Done. Switched to `sd_match(N1, m_AllOnes())` and `sd_match(N1, m_Zero())` for both patterns.

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


More information about the llvm-commits mailing list