[llvm] [AArch64] Fold SMax and SMin with -1 (PR #208264)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 8 09:52:40 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: AZero13 (AZero13)

<details>
<summary>Changes</summary>

Use orn to fold smax with -1.

---
Full diff: https://github.com/llvm/llvm-project/pull/208264.diff


6 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+18) 
- (modified) llvm/test/CodeGen/AArch64/aarch64-saturating-arithmetic.ll (+2-4) 
- (modified) llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll (+8-8) 
- (modified) llvm/test/CodeGen/AArch64/fptosi-sat-vector.ll (+8-8) 
- (modified) llvm/test/CodeGen/AArch64/smax-allones.ll (+56) 
- (modified) llvm/test/CodeGen/AArch64/win64_vararg.ll (+2-4) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 86670e136355f..a39d4a63a22b7 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -12646,6 +12646,24 @@ SDValue AArch64TargetLowering::LowerSELECT_CC(
       return DAG.getNode(ISD::AND, DL, VT, LHS, Shift);
     }
 
+    // Check for SMAX(lhs, -1) and SMIN(lhs, -1) patterns.
+    // (SELECT_CC setgt, lhs, -1, lhs, -1) -> (OR lhs, (SRA lhs, typesize-1))
+    // (SELECT_CC setlt, lhs, -1, lhs, -1) -> (ORN lhs, (SRA lhs, typesize-1))
+    // Both require less instructions than compare and conditional select.
+    if ((CC == ISD::SETGT || CC == ISD::SETLT) && LHS == TVal &&
+        RHSC && RHSC->isAllOnes() && CFVal && CFVal->isAllOnes() &&
+        LHS.getValueType() == RHS.getValueType()) {
+      EVT VT = LHS.getValueType();
+      SDValue Shift =
+          DAG.getNode(ISD::SRA, DL, VT, LHS,
+                      DAG.getConstant(VT.getSizeInBits() - 1, DL, VT));
+
+      if (CC == ISD::SETLT)
+        Shift = DAG.getNOT(DL, Shift, VT);
+
+      return DAG.getNode(ISD::OR, DL, VT, LHS, Shift);
+    }
+
     // Check for sign bit test patterns that can use TST optimization.
     // (SELECT_CC setlt, sign_extend_inreg, 0, tval, fval)
     //                          -> TST %operand, sign_bit; CSEL
diff --git a/llvm/test/CodeGen/AArch64/aarch64-saturating-arithmetic.ll b/llvm/test/CodeGen/AArch64/aarch64-saturating-arithmetic.ll
index db79b672d6f03..9546512fc4230 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-saturating-arithmetic.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-saturating-arithmetic.ll
@@ -106,9 +106,8 @@ define i64 @test_ssub_nonneg_rhs_nonconst(i64 %x) {
 define i64 @test_ssub_neg_rhs_nonconst(i64 %x) {
 ; CHECK-LABEL: test_ssub_neg_rhs_nonconst:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    cmn x0, #1
+; CHECK-NEXT:    orn x9, x0, x0, asr #63
 ; CHECK-NEXT:    mov x8, #9223372036854775807 // =0x7fffffffffffffff
-; CHECK-NEXT:    csinv x9, x0, xzr, lt
 ; CHECK-NEXT:    subs x9, x0, x9
 ; CHECK-NEXT:    csel x0, x8, x9, vs
 ; CHECK-NEXT:    ret
@@ -162,9 +161,8 @@ define i64 @test_ssub_nonneg_lhs_nonconst(i64 %x) {
 define i64 @test_ssub_neg_lhs_nonconst(i64 %x) {
 ; CHECK-LABEL: test_ssub_neg_lhs_nonconst:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    cmn x0, #1
+; CHECK-NEXT:    orn x9, x0, x0, asr #63
 ; CHECK-NEXT:    mov x8, #-9223372036854775808 // =0x8000000000000000
-; CHECK-NEXT:    csinv x9, x0, xzr, lt
 ; CHECK-NEXT:    subs x9, x9, x0
 ; CHECK-NEXT:    csel x0, x8, x9, vs
 ; CHECK-NEXT:    ret
diff --git a/llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll b/llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll
index f95d338198c4d..67f598727a032 100644
--- a/llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll
+++ b/llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll
@@ -23,8 +23,8 @@ define i1 @test_signed_i1_f32(float %f) nounwind {
 ; CHECK-SD-LABEL: test_signed_i1_f32:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzs w8, s0
-; CHECK-SD-NEXT:    ands w8, w8, w8, asr #31
-; CHECK-SD-NEXT:    csinv w8, w8, wzr, pl
+; CHECK-SD-NEXT:    and w8, w8, w8, asr #31
+; CHECK-SD-NEXT:    orr w8, w8, w8, lsr #31
 ; CHECK-SD-NEXT:    and w0, w8, #0x1
 ; CHECK-SD-NEXT:    ret
 ;
@@ -268,8 +268,8 @@ define i1 @test_signed_i1_f64(double %f) nounwind {
 ; CHECK-SD-LABEL: test_signed_i1_f64:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    fcvtzs w8, d0
-; CHECK-SD-NEXT:    ands w8, w8, w8, asr #31
-; CHECK-SD-NEXT:    csinv w8, w8, wzr, pl
+; CHECK-SD-NEXT:    and w8, w8, w8, asr #31
+; CHECK-SD-NEXT:    orr w8, w8, w8, lsr #31
 ; CHECK-SD-NEXT:    and w0, w8, #0x1
 ; CHECK-SD-NEXT:    ret
 ;
@@ -518,16 +518,16 @@ define i1 @test_signed_i1_f16(half %f) nounwind {
 ; CHECK-SD-CVT:       // %bb.0:
 ; CHECK-SD-CVT-NEXT:    fcvt s0, h0
 ; CHECK-SD-CVT-NEXT:    fcvtzs w8, s0
-; CHECK-SD-CVT-NEXT:    ands w8, w8, w8, asr #31
-; CHECK-SD-CVT-NEXT:    csinv w8, w8, wzr, pl
+; CHECK-SD-CVT-NEXT:    and w8, w8, w8, asr #31
+; CHECK-SD-CVT-NEXT:    orr w8, w8, w8, lsr #31
 ; CHECK-SD-CVT-NEXT:    and w0, w8, #0x1
 ; CHECK-SD-CVT-NEXT:    ret
 ;
 ; CHECK-SD-FP16-LABEL: test_signed_i1_f16:
 ; CHECK-SD-FP16:       // %bb.0:
 ; CHECK-SD-FP16-NEXT:    fcvtzs w8, h0
-; CHECK-SD-FP16-NEXT:    ands w8, w8, w8, asr #31
-; CHECK-SD-FP16-NEXT:    csinv w8, w8, wzr, pl
+; CHECK-SD-FP16-NEXT:    and w8, w8, w8, asr #31
+; CHECK-SD-FP16-NEXT:    orr w8, w8, w8, lsr #31
 ; CHECK-SD-FP16-NEXT:    and w0, w8, #0x1
 ; CHECK-SD-FP16-NEXT:    ret
 ;
diff --git a/llvm/test/CodeGen/AArch64/fptosi-sat-vector.ll b/llvm/test/CodeGen/AArch64/fptosi-sat-vector.ll
index 145aef9123a4e..892af7852e1bc 100644
--- a/llvm/test/CodeGen/AArch64/fptosi-sat-vector.ll
+++ b/llvm/test/CodeGen/AArch64/fptosi-sat-vector.ll
@@ -2350,14 +2350,14 @@ define <2 x i1> @test_signed_v2f64_v2i1(<2 x double> %f) {
 ; CHECK-SD-LABEL: test_signed_v2f64_v2i1:
 ; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    mov d1, v0.d[1]
-; CHECK-SD-NEXT:    fcvtzs w9, d0
-; CHECK-SD-NEXT:    fcvtzs w8, d1
-; CHECK-SD-NEXT:    ands w8, w8, w8, asr #31
-; CHECK-SD-NEXT:    csinv w8, w8, wzr, pl
-; CHECK-SD-NEXT:    ands w9, w9, w9, asr #31
-; CHECK-SD-NEXT:    csinv w9, w9, wzr, pl
-; CHECK-SD-NEXT:    fmov s0, w9
-; CHECK-SD-NEXT:    mov v0.s[1], w8
+; CHECK-SD-NEXT:    fcvtzs w8, d0
+; CHECK-SD-NEXT:    fcvtzs w9, d1
+; CHECK-SD-NEXT:    and w8, w8, w8, asr #31
+; CHECK-SD-NEXT:    orr w8, w8, w8, asr #31
+; CHECK-SD-NEXT:    and w9, w9, w9, asr #31
+; CHECK-SD-NEXT:    fmov s0, w8
+; CHECK-SD-NEXT:    orr w9, w9, w9, asr #31
+; CHECK-SD-NEXT:    mov v0.s[1], w9
 ; CHECK-SD-NEXT:    // kill: def $d0 killed $d0 killed $q0
 ; CHECK-SD-NEXT:    ret
 ;
diff --git a/llvm/test/CodeGen/AArch64/smax-allones.ll b/llvm/test/CodeGen/AArch64/smax-allones.ll
index f22af8756a866..75ae53ab3a9fc 100644
--- a/llvm/test/CodeGen/AArch64/smax-allones.ll
+++ b/llvm/test/CodeGen/AArch64/smax-allones.ll
@@ -61,3 +61,59 @@ define i64 @smin_zero_i64(i64 %x) {
   %r = call i64 @llvm.smin.i64(i64 %x, i64 0)
   ret i64 %r
 }
+
+define i32 @smax_zero_i32(i32 %x) {
+; NOCSSC-LABEL: smax_zero_i32:
+; NOCSSC:       // %bb.0:
+; NOCSSC-NEXT:    bic w0, w0, w0, asr #31
+; NOCSSC-NEXT:    ret
+;
+; CSSC-LABEL: smax_zero_i32:
+; CSSC:       // %bb.0:
+; CSSC-NEXT:    smax w0, w0, #0
+; CSSC-NEXT:    ret
+  %r = call i32 @llvm.smax.i32(i32 %x, i32 0)
+  ret i32 %r
+}
+
+define i64 @smax_zero_i64(i64 %x) {
+; NOCSSC-LABEL: smax_zero_i64:
+; NOCSSC:       // %bb.0:
+; NOCSSC-NEXT:    bic x0, x0, x0, asr #63
+; NOCSSC-NEXT:    ret
+;
+; CSSC-LABEL: smax_zero_i64:
+; CSSC:       // %bb.0:
+; CSSC-NEXT:    smax x0, x0, #0
+; CSSC-NEXT:    ret
+  %r = call i64 @llvm.smax.i64(i64 %x, i64 0)
+  ret i64 %r
+}
+
+define i32 @smin_allones_i32(i32 %x) {
+; NOCSSC-LABEL: smin_allones_i32:
+; NOCSSC:       // %bb.0:
+; NOCSSC-NEXT:    orn w0, w0, w0, asr #31
+; NOCSSC-NEXT:    ret
+;
+; CSSC-LABEL: smin_allones_i32:
+; CSSC:       // %bb.0:
+; CSSC-NEXT:    smin w0, w0, #-1
+; CSSC-NEXT:    ret
+  %r = call i32 @llvm.smin.i32(i32 %x, i32 -1)
+  ret i32 %r
+}
+
+define i64 @smin_allones_i64(i64 %x) {
+; NOCSSC-LABEL: smin_allones_i64:
+; NOCSSC:       // %bb.0:
+; NOCSSC-NEXT:    orn x0, x0, x0, asr #63
+; NOCSSC-NEXT:    ret
+;
+; CSSC-LABEL: smin_allones_i64:
+; CSSC:       // %bb.0:
+; CSSC-NEXT:    smin x0, x0, #-1
+; CSSC-NEXT:    ret
+  %r = call i64 @llvm.smin.i64(i64 %x, i64 -1)
+  ret i64 %r
+}
diff --git a/llvm/test/CodeGen/AArch64/win64_vararg.ll b/llvm/test/CodeGen/AArch64/win64_vararg.ll
index 0f4cb44a6f73b..6b845c6163882 100644
--- a/llvm/test/CodeGen/AArch64/win64_vararg.ll
+++ b/llvm/test/CodeGen/AArch64/win64_vararg.ll
@@ -133,8 +133,7 @@ define i32 @fp(ptr, i64, ptr, ...) local_unnamed_addr #6 {
 ; CHECK-NEXT:    mov x4, xzr
 ; CHECK-NEXT:    orr x0, x8, #0x2
 ; CHECK-NEXT:    bl __stdio_common_vsprintf
-; CHECK-NEXT:    cmn w0, #1
-; CHECK-NEXT:    csinv w0, w0, wzr, gt
+; CHECK-NEXT:    orr w0, w0, w0, asr #31
 ; CHECK-NEXT:    .seh_startepilogue
 ; CHECK-NEXT:    ldp x29, x30, [sp, #24] // 16-byte Folded Reload
 ; CHECK-NEXT:    .seh_save_fplr 24
@@ -268,8 +267,7 @@ define i32 @snprintf(ptr, i64, ptr, ...) local_unnamed_addr #5 {
 ; CHECK-NEXT:    mov x4, xzr
 ; CHECK-NEXT:    orr x0, x8, #0x2
 ; CHECK-NEXT:    bl __stdio_common_vsprintf
-; CHECK-NEXT:    cmn w0, #1
-; CHECK-NEXT:    csinv w0, w0, wzr, gt
+; CHECK-NEXT:    orr w0, w0, w0, asr #31
 ; CHECK-NEXT:    .seh_startepilogue
 ; CHECK-NEXT:    ldp x21, x30, [sp, #32] // 16-byte Folded Reload
 ; CHECK-NEXT:    .seh_save_lrpair x21, 32

``````````

</details>


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


More information about the llvm-commits mailing list