[llvm] [DAGCombiner] Fold smax(X, -1) to or(X, ashr(X, BW-1)) for code size (PR #206242)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 27 14:16:52 PDT 2026


================
@@ -6307,6 +6307,41 @@ 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)) {
+    SDValue ShiftAmt =
+        DAG.getShiftAmountConstant(VT.getScalarSizeInBits() - 1, VT, DL);
+    if (Opcode == ISD::SMAX && TLI.isOperationExpand(ISD::SMAX, VT) &&
+        N0.getOpcode() != ISD::SMIN) {
+      if (auto *N1C = isConstOrConstSplat(N1)) {
----------------
RKSimon wrote:

Use isAllOnesConstant

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


More information about the llvm-commits mailing list