On Wed, May 20, 2026 at 3:12 AM Andrew Pinski < [email protected]> wrote:
> On Tue, May 19, 2026 at 2:42 AM 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". > > > > PR tree-optimization/112533 > > > > Changes since v1: > > * 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-eq-simplify.c: New test for > > narrowing integral eq/ne simplification. > > > > Signed-off-by: Shivam Gupta <[email protected]> > > --- > > gcc/match.pd | 14 ++- > > .../gcc.dg/tree-ssa/narrow-eq-simplify.c | 95 +++++++++++++++++++ > > 2 files changed, 108 insertions(+), 1 deletion(-) > > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/narrow-eq-simplify.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-eq-simplify.c > b/gcc/testsuite/gcc.dg/tree-ssa/narrow-eq-simplify.c > > new file mode 100644 > > index 00000000000..6e48e40dd3a > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/tree-ssa/narrow-eq-simplify.c > > @@ -0,0 +1,95 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -fdump-tree-optimized" } */ > > + > > +/* Verify the fix for PR112533 at -O2. > > + (~a & 1) == (~a & 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); > > +} > > Split this testcase into 4 files. The first will have the > same_evenness/diff_evenness related ones and then the second testcase > will have the eq_*/ne_* functions. > > > + > > +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; > > +} > > This requires `sizeof(int) != sizeof(short)` so the testcase needs to > run on targets which is `!int16`. > So it might make sense to split out short also from char. > And the short case for the dg-do have it as: > /* { dg-do compile { target ! int16 } */ > > Thank you for the suggestions. Thanks, Shivam > + > > +unsigned char > > +eq_uchar (unsigned int a, unsigned int b) > > +{ > > + unsigned char sa = a; > > + unsigned char sb = b; > > + return sa == sb; > > +} > > + > > +signed char > > +ne_schar (int a, int b) > > +{ > > + signed char sa = a; > > + signed char sb = b; > > + return sa != sb; > > +} > > + > > +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; > > +} > > + > > +int > > +eq_float_no_xor (double a, double b) > > +{ > > + float fa = a; > > + float fb = b; > > + return fa == fb; > > +} > > And then the 3rd would be the eq_float_no_xor which uses > scan-tree-dump-not there. > > > + > > +/* Verify the XOR form is produced for integral narrowing comparisons. > */ > > +/* { dg-final { scan-tree-dump-times "\\\^" 7 "optimized" } } */ > > > Thanks, > Andrea > > > -- > > 2.34.1 > > >
