https://gcc.gnu.org/g:ff133b4cd2202fc7a5be5cd9dc935c0a75fb6b68

commit r17-5264-gff133b4cd2202fc7a5be5cd9dc935c0a75fb6b68
Author: Uttam Bhadauriya <[email protected]>
Date:   Fri Oct 16 09:44:17 2026 -0600

    [PATCH v4] tree-optimization: Simplify (a & -a) < 0 to a == INT_MIN 
[PR126627]
    
    Hello,
    apologies for the formatting and rebase issue, I am sending v4 of the
    patch to address the same.
    
    From 987b64d5230398390f926a91612ea5c0a5dcb781 Mon Sep 17 00:00:00 2001
    From: Uttam Singh Bhadauriya <[email protected]>
    Date: Fri, 16 Oct 2026 17:58:52 +0530
    Subject: [PATCH v4] tree-optimization: Simplify (a & -a) < 0 to a == INT_MIN
     [PR126627]
    
    The expression (a & -a) < 0 on a signed integer (or an unsigned integer cast
    to a signed integer) is equivalent to checking if a is the minimum signed
    value for its type. The only value where the lowest set bit is the sign bit
    is INT_MIN. This patch introduces a simplification in match.pd to optimize
    this pattern into a direct equality check.
    
    It also handles the negate-in-unsigned form which avoids UB on negation,
    matching it using the new negate_maybe_without_ud predicate.
    
    It guards the transformation with !TYPE_OVERFLOW_TRAPS since -a could
    otherwise trap for INT_MIN, which would incorrectly be removed.
    
    ---
    v4:
    - Replaced scan counts and regexes in the testcases with exact counts.
    - Dropped precision > 1 requirement to also support 1-bit signed types.
    - Added '/* { dg-require-effective-target int32 } */' to both testcases.
    - Added INTEGRAL_TYPE_P guards to prevent matching pointer conversions.
    - Introduced negate_maybe_without_ud predicate to handle unsigned negation.
    - Guarded with !TYPE_OVERFLOW_TRAPS to prevent dropping traps under -ftrapv.
    - Fixed (short) cast in pr126627-2.c and changed -fdump-tree-all to
    -fdump-tree-optimized.
    - Formatted comments according to GNU style guidelines.
    
    Bootstrapped and regression tested on x86_64-pc-linux-gnu, Windows 11
    Version 23H2 with WSL Ubuntu 22.04.05 LTS:
    - pr126627.c and pr126627-2.c: 12 passes in DejaGnu.
    - tree-ssa.exp: 9,194 passes, no regressions.
    - Verified behavior under -ftrapv (no folds) and -fwrapv (folded).
    
            PR tree-optimization/126627
    gcc/ChangeLog:
    
            * match.pd: Simplify (a & -a) < 0 to a == INT_MIN and
            (a & -a) >= 0 to a != INT_MIN, using the negate_maybe_without_ud
            predicate to support both signed and unsigned negation.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/pr126627.c: New test.
            * gcc.dg/tree-ssa/pr126627-2.c: New test.
    
    Signed-off-by: Uttam Singh Bhadauriya <[email protected]>

Diff:
---
 gcc/match.pd                               | 20 ++++++++++++++++
 gcc/testsuite/gcc.dg/pr127916.c            | 38 ++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr126627-2.c | 15 ++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr126627.c   | 24 +++++++++++++++++++
 4 files changed, 97 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index a28d307c819c..629114591a2b 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -9268,6 +9268,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)))
    (cmp @0 (convert @1)))))
 
+/* (a & -a) < 0 -> a == INT_MIN
+   (a & -a) >= 0 -> a != INT_MIN.  */
+(match (negate_maybe_without_ud @0)
+ (negate @0))
+(match (negate_maybe_without_ud @0)
+ (convert (negate (nop_convert @0)))
+ (if (types_match (type, @0))))
+
+(for cmp (lt ge)
+     eqcmp (eq ne)
+ (simplify
+  (cmp (nop_convert?@0 (bit_and:c (negate_maybe_without_ud @1) @1))
+       integer_zerop)
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && !TYPE_UNSIGNED (TREE_TYPE (@0))
+       && !TYPE_OVERFLOW_TRAPS (TREE_TYPE (@1)))
+   (eqcmp @1 { wide_int_to_tree (TREE_TYPE (@1),
+ wi::min_value (TYPE_PRECISION (TREE_TYPE (@1)), SIGNED)); }))))
+
 /* Non-equality compare simplifications from fold_binary  */
 (for cmp (lt gt le ge)
  /* Comparisons with the highest or lowest possible integer of
diff --git a/gcc/testsuite/gcc.dg/pr127916.c b/gcc/testsuite/gcc.dg/pr127916.c
new file mode 100644
index 000000000000..e4229946408e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr127916.c
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+
+#include <limits.h>
+
+__attribute__((noipa)) int
+s_sat (int x)
+{
+  int sum = (int) ((unsigned) x + 1u);
+  if (((x ^ sum) & (x ^ 2)) < 0)
+    return -(int) (x < 0) ^ INT_MAX;
+  return sum;
+}
+
+__attribute__((noipa)) signed char
+another_sat (int a, int b)
+{
+  signed char r;
+  if (__builtin_add_overflow (a, b, &r))
+    return a < 0 ? SCHAR_MIN : SCHAR_MAX;
+  return r;
+}
+
+int main (void)
+{
+  if (s_sat (INT_MAX) != INT_MIN)
+    __builtin_abort ();
+
+  if (s_sat (-1) != INT_MIN)
+    __builtin_abort ();
+
+  if (another_sat (-1, 200) != -128)
+    __builtin_abort ();
+
+  if (another_sat (100, 100) != 127)
+    __builtin_abort ();
+
+  __builtin_exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126627-2.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr126627-2.c
new file mode 100644
index 000000000000..ea68b8897be8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126627-2.c
@@ -0,0 +1,15 @@
+/* PR tree-optimization/126627 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-require-effective-target int32 } */
+
+int test_ss (short a) { return (short)(a & -a) < 0; }
+int test_ss2 (short a) { return (short)(a & -a) >= 0; }
+int test_us (unsigned short a) { return (short)(a & -a) < 0; }
+int test_us2 (unsigned short a) { return (short)(a & -a) >= 0; }
+
+/* { dg-final { scan-tree-dump-not " & " "optimized" } } */
+/* { dg-final { scan-tree-dump-times " == -32768" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " != -32768" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " == 32768" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " != 32768" 1 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126627.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr126627.c
new file mode 100644
index 000000000000..d11f5312baf2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126627.c
@@ -0,0 +1,24 @@
+/* PR tree-optimization/126627 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-require-effective-target int32 } */
+
+int test1 (int a) { return (a & -a) < 0; }
+int test2 (int a) { return (a & -a) >= 0; }
+int test3 (unsigned a) { return (int)(a & -a) < 0; }
+int test4 (unsigned a) { return (int)(a & -a) >= 0; }
+
+/* Negation done in unsigned to avoid UB.  */
+int test_si (signed a)
+{
+  unsigned b = a;
+  b = -b;
+  signed t = b;
+  return (a & t) >= 0;
+}
+
+/* { dg-final { scan-tree-dump-not " & " "optimized" } } */
+/* { dg-final { scan-tree-dump-times " == -2147483648" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " != -2147483648" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " == 2147483648" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " != 2147483648" 1 "optimized" } } */

Reply via email to