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

Aayush Shrivastava via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 27 11:32:59 PDT 2026


================
@@ -0,0 +1,74 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=x86_64-linux -O2 | FileCheck %s
+;
+; Verify smax(X, -1) folds to or(X, ashr(X, BW-1)) under minsize.
+; This saves a byte vs compare+cmov on x86-64 (-Oz / minsize attribute).
+; GCC PR 125921, LLVM issue #206153.
+
+; Without minsize: keep as compare+cmov
+define i32 @smax_allones_i32_normal(i32 %x) {
+; CHECK-LABEL: smax_allones_i32_normal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    testl %edi, %edi
+; CHECK-NEXT:    movl $-1, %eax
+; CHECK-NEXT:    cmovnsl %edi, %eax
+; CHECK-NEXT:    retq
+  %r = call i32 @llvm.smax.i32(i32 %x, i32 -1)
+  ret i32 %r
+}
+
+; With minsize: fold to or(X, ashr(X, 31))
+define i32 @smax_allones_i32(i32 %x) minsize {
+; CHECK-LABEL: smax_allones_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    sarl $31, %eax
+; CHECK-NEXT:    orl %edi, %eax
+; CHECK-NEXT:    retq
+  %r = call i32 @llvm.smax.i32(i32 %x, i32 -1)
+  ret i32 %r
+}
+
+; i64 variant with minsize
+define i64 @smax_allones_i64(i64 %x) minsize {
+; CHECK-LABEL: smax_allones_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq %rdi, %rax
+; CHECK-NEXT:    sarq $63, %rax
+; CHECK-NEXT:    orq %rdi, %rax
+; CHECK-NEXT:    retq
+  %r = call i64 @llvm.smax.i64(i64 %x, i64 -1)
+  ret i64 %r
+}
+
+; smax(X, 0) with minsize should NOT transform (no 2-instruction bitwise form)
+define i32 @smax_zero_minsize(i32 %x) minsize {
+; CHECK-LABEL: smax_zero_minsize:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    xorl %eax, %eax
+; CHECK-NEXT:    testl %edi, %edi
+; CHECK-NEXT:    cmovgl %edi, %eax
+; CHECK-NEXT:    retq
+  %r = call i32 @llvm.smax.i32(i32 %x, i32 0)
+  ret i32 %r
+}
+
+; smin(X, -1) with minsize should NOT transform (no 2-instruction bitwise form)
+define i32 @smin_allones_minsize(i32 %x) minsize {
+; CHECK-LABEL: smin_allones_minsize:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cmpl $-1, %edi
+; CHECK-NEXT:    pushq $-1
+; CHECK-NEXT:    .cfi_adjust_cfa_offset 8
+; CHECK-NEXT:    popq %rax
+; CHECK-NEXT:    .cfi_adjust_cfa_offset -8
+; CHECK-NEXT:    cmovll %edi, %eax
+; CHECK-NEXT:    retq
+  %r = call i32 @llvm.smin.i32(i32 %x, i32 -1)
+  ret i32 %r
+}
+
+declare i32 @llvm.smax.i32(i32, i32)
+declare i64 @llvm.smax.i64(i64, i64)
+declare i16 @llvm.smax.i16(i16, i16)
+declare i32 @llvm.smin.i32(i32, i32)
----------------
iamaayushrivastava wrote:

Thanks for the review! Removed the unnecessary declare lines for the built-in intrinsics.

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


More information about the llvm-commits mailing list