On Thu, 21 May 2026 at 2:47 AM, Andrew Pinski <
[email protected]> wrote:

> On Tue, May 19, 2026 at 8:46 PM Shivam Gupta <[email protected]>
> wrote:
> >
> > 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".
>
> Pushed now after a full bootstrap/test has happened.  Also fixedup the
> commit message slighty; move the PR number down to above the changelog
> and use tabs rather than spaces for the changelog.
>

Thank you for this; I have noted it for next patches.

Thanks,
Shivam

>
> Thanks,
> Andrea
>
> >
> >         PR tree-optimization/112533
> >
> > 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.
> >
> > 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]>
> > ---
> >  gcc/match.pd                                  | 14 +++++-
> >  .../gcc.dg/tree-ssa/narrow-bool-eq.c          | 31 +++++++++++++
> >  .../gcc.dg/tree-ssa/narrow-float-eq.c         | 13 ++++++
> >  .../gcc.dg/tree-ssa/narrow-integral-eq.c      | 46 +++++++++++++++++++
> >  .../gcc.dg/tree-ssa/narrow-short-eq.c         | 23 ++++++++++
> >  5 files changed, 126 insertions(+), 1 deletion(-)
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/narrow-bool-eq.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/narrow-float-eq.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/narrow-integral-eq.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/narrow-short-eq.c
> >
> > diff --git a/gcc/match.pd b/gcc/match.pd
> > index ff13a07ea94..195d10c80c7 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 00000000000..217edf7a041
> > --- /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 00000000000..25a264a128e
> > --- /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 00000000000..1b08e38bdda
> > --- /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 00000000000..27df711f803
> > --- /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" } } */
> > --
> > 2.34.1
> >
>

Reply via email to