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

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 29 02:11:35 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) &&
----------------
Andarwinux wrote:

Please add [FEAT_CSSC](https://www.corsix.org/content/arm-cssc) coverage to AArch64/smax-allones.ll‎
to actually test this.

https://godbolt.org/z/zMqGa6rsz

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


More information about the llvm-commits mailing list