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. 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 >
