https://gcc.gnu.org/g:1c9808a71207eb217f4e190c60f2755a796b90d4

commit r17-632-g1c9808a71207eb217f4e190c60f2755a796b90d4
Author: Shivam Gupta <[email protected]>
Date:   Wed May 20 09:16:32 2026 +0530

    match.pd: Simplify (T)(x) == (T)(y) -> (T)(x ^ y) == 0 [PR112533]
    
    This is a follow-up to the -O1 patch for PR112533.
    
    At -O2, GCC lowers (~x & 1) == (~y & 1) via inlining into:
      _14 = ~x;
      _12 = (bool) _14;
      _13 = ~y;
      _9  = (bool) _13;
      _8  = _9 == _12;
    
    The NOT cancellation (~x == ~y -> x == y) is handled by existing
    forwprop rules before this rule fires.
    
    Add match.pd rule for eq and ne:
    
      (T)(x) == (T)(y) -> (T)(x ^ y) == 0
      (T)(x) != (T)(y) -> (T)(x ^ y) != 0
    
    Bootstrapped and regression tested on aarch64-linux-gnu with
    RUNTESTFLAGS="tree-ssa.exp".
    
    Changes since v1:
    * v5: Split testcase into bool, integral, short and float-specific
          files.
    * v4: Moved match rule to right place alongside other
          simple_comparison narrowing cases.
    * v3: Simplify match rule.
          Add more cases in test file.
    * v2: Generalize the match rule to generic narrowing
          integral equality comparisons from bool equality.
    
            PR tree-optimization/112533
    
    gcc/ChangeLog:
            * match.pd: Add integral narrowing eq/ne to XOR-against-zero
            rule for (T)(x) == (T)(y) where precision(T) < precision(x).
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/tree-ssa/narrow-bool-eq.c: New test.
            * gcc.dg/tree-ssa/narrow-integral-eq.c: New test.
            * gcc.dg/tree-ssa/narrow-short-eq.c: New test.
            * gcc.dg/tree-ssa/narrow-float-eq.c: New test.
    
    Signed-off-by: Shivam Gupta <[email protected]>

Diff:
---
 gcc/match.pd                                       | 14 ++++++-
 gcc/testsuite/gcc.dg/tree-ssa/narrow-bool-eq.c     | 31 +++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/narrow-float-eq.c    | 13 ++++++
 gcc/testsuite/gcc.dg/tree-ssa/narrow-integral-eq.c | 46 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/narrow-short-eq.c    | 23 +++++++++++
 5 files changed, 126 insertions(+), 1 deletion(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index ff13a07ea94b..195d10c80c73 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7804,7 +7804,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
          (if (cmp == LT_EXPR || cmp == LE_EXPR)
           { constant_boolean_node (above ? true : false, type); }
           (if (cmp == GT_EXPR || cmp == GE_EXPR)
-           { constant_boolean_node (above ? false : true, type); })))))))))
+           { constant_boolean_node (above ? false : true, type); })))))))
+
+    /* For eq/ne with narrowing conversion:
+       (T)(X) == (T)(Y) -> (T)(X ^ Y) == 0  */
+    (if (TYPE_PRECISION (TREE_TYPE (@0))
+         < TYPE_PRECISION (TREE_TYPE (@00))
+         && (cmp == EQ_EXPR || cmp == NE_EXPR)
+         && types_match (TREE_TYPE (@00),
+                         TREE_TYPE (@10)))
+     (with { tree itype = TREE_TYPE (@0); }
+      (cmp (convert:itype (bit_xor @00 @10))
+           { build_zero_cst (itype); })))))
+
    /* Fold (double)float1 CMP (double)float2 into float1 CMP float2.  */
    (if (FLOAT_TYPE_P (TREE_TYPE (@00))
        && (DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@0))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/narrow-bool-eq.c 
b/gcc/testsuite/gcc.dg/tree-ssa/narrow-bool-eq.c
new file mode 100644
index 000000000000..217edf7a0414
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/narrow-bool-eq.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* Verify the fix for PR112533 at -O2.
+   (~a & 1) == (~b & 1) is lowered via inlining to
+   (bool)(~a) == (bool)(~b), then existing forwprop rules cancel
+   the NOTs giving (bool)(a) == (bool)(b), which this rule
+   simplifies to (bool)(a ^ b) == 0.  */
+
+typedef unsigned int u32;
+
+static _Bool
+is_even (u32 a)
+{
+  return a % 2 == 0;
+}
+
+_Bool
+same_evenness (u32 a, u32 b)
+{
+  return is_even (a) == is_even (b);
+}
+
+_Bool
+diff_evenness (u32 a, u32 b)
+{
+  return is_even (a) != is_even (b);
+}
+
+/* Verify XOR form is produced.  */
+/* { dg-final { scan-tree-dump-times "\\^" 2 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/narrow-float-eq.c 
b/gcc/testsuite/gcc.dg/tree-ssa/narrow-float-eq.c
new file mode 100644
index 000000000000..25a264a128ef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/narrow-float-eq.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+eq_float_no_xor (double a, double b)
+{
+  float fa = a;
+  float fb = b;
+  return fa == fb;
+}
+
+/* Floating-point narrowing should not use XOR form.  */
+/* { dg-final { scan-tree-dump-not "\\^" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/narrow-integral-eq.c 
b/gcc/testsuite/gcc.dg/tree-ssa/narrow-integral-eq.c
new file mode 100644
index 000000000000..1b08e38bdda8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/narrow-integral-eq.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+unsigned char
+eq_uchar (unsigned int a, unsigned int b)
+{
+  unsigned char ua = a;
+  unsigned char ub = b;
+  return ua == ub;
+}
+
+signed char
+ne_schar (int a, int b)
+{
+  signed char ca = a;
+  signed char cb = b;
+  return ca != cb;
+}
+
+int
+eq_int_from_ll (long long a, long long b)
+{
+  int ia = a;
+  int ib = b;
+  return ia == ib;
+}
+
+int
+eq_int_no_narrow (int a, int b)
+{
+  int ia = a;
+  int ib = b;
+  return ia == ib;
+}
+
+long long
+eq_widen (int a, int b)
+{
+  long long la = a;
+  long long lb = b;
+  return la == lb;
+}
+
+/* Only narrowing integral cases should produce XOR form.
+   eq_int_no_narrow and eq_widen should not match.  */
+/* { dg-final { scan-tree-dump-times "\\^" 3 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/narrow-short-eq.c 
b/gcc/testsuite/gcc.dg/tree-ssa/narrow-short-eq.c
new file mode 100644
index 000000000000..27df711f8036
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/narrow-short-eq.c
@@ -0,0 +1,23 @@
+/* { dg-do compile { target { ! int16 } } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* Requires sizeof(int) > sizeof(short).  */
+
+short
+eq_short_not (int a, int b)
+{
+  short sa = ~a;
+  short sb = ~b;
+  return sa == sb;
+}
+
+short
+ne_short_not (int a, int b)
+{
+  short sa = ~a;
+  short sb = ~b;
+  return sa != sb;
+}
+
+/* Verify XOR form is produced for narrowing short comparisons.  */
+/* { dg-final { scan-tree-dump-times "\\^" 2 "optimized" } } */

Reply via email to