Hello, Gentle ping for this patch review.
Thank, Shivam On Sun, May 17, 2026 at 12:20 PM Shivam Gupta <[email protected]> wrote: > At -O1, GCC lowers (~a & 1) == (~b & 1) into two different GIMPLE > forms depending on whether the boolean values come from a function > return boundary or an inline expression: > > 1. Via function return (e.g. inlined is_even), GCC preserves the > eq/ne form because the function boundary hides the internal > structure from the gimplifier: > ((a&1)==0) == ((b&1)==0) outer node is eq/ne > > 2. Via inline expression (directly written), GCC sees the full > boolean expression tree at once and folds to bit_xor during > gimplification: > ((a&1)!=0) ^ ((b&1)==0) outer node is bit_xor > > Add two match.pd rules to handle both forms: > > 1. (cmp (eq (x&1) 0) (eq (y&1) 0)) -> (cmp (x&1) (y&1)) > 2. (bit_xor (eq (x&1) 0) (eq (y&1) 0)) -> (ne (x&1) (y&1)) > (bit_xor (ne (x&1) 0) (eq (y&1) 0)) -> (eq (x&1) (y&1)) > > Subsequent passes further simplify these to (x^y)&1 == 0. > > Bootstrapped and tested on aarch64-linux-gnu with > RUNTESTFLAGS="tree-ssa.exp". > > PR tree-optimization/112533 > > gcc/ChangeLog: > * match.pd: Simplify ((x&1)==0)==((y&1)==0) to (x&1)==(y&1) > and ((x&1) cmp 0)^((y&1)==0) to (x&1) icmp (y&1). > > gcc/testsuite/ChangeLog: > * gcc.dg/tree-ssa/bool-eq-simplify-O1.c: New test. > > Signed-off-by: Shivam Gupta <[email protected]> > --- > gcc/match.pd | 27 +++++++++++ > .../gcc.dg/tree-ssa/bool-eq-simplify-O1.c | 47 +++++++++++++++++++ > 2 files changed, 74 insertions(+) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bool-eq-simplify-O1.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index ff13a07ea94..7afa3b0d546 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -1464,6 +1464,33 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (if (TYPE_UNSIGNED (type)) > (bit_and @0 (bit_not (lshift { build_all_ones_cst (type); } @1))))) > > +/* ((x & 1) == 0) == ((y & 1) == 0) -> (x & 1) == (y & 1) */ > +/* ((x & 1) == 0) != ((y & 1) == 0) -> (x & 1) != (y & 1) */ > +(for cmp (eq ne) > + (simplify > + (cmp > + (eq (bit_and:c @0 INTEGER_CST@1) integer_zerop) > + (eq (bit_and:c @2 @1) integer_zerop)) > + (if (integer_onep (@1) > + && types_match (@0, @2)) > + (cmp > + (bit_and @0 @1) > + (bit_and @2 @1))))) > + > +/* ((x & 1) != 0) ^ ((y & 1) == 0) -> (x & 1) == (y & 1) */ > +/* ((x & 1) == 0) ^ ((y & 1) == 0) -> (x & 1) != (y & 1) */ > +(for cmp (eq ne) > + icmp (ne eq) > + (simplify > + (bit_xor:c > + (cmp (bit_and:c @0 INTEGER_CST@1) integer_zerop) > + (eq (bit_and:c @2 @1) integer_zerop)) > + (if (integer_onep (@1) > + && types_match (@0, @2)) > + (icmp > + (bit_and @0 @1) > + (bit_and @2 @1))))) > + > (for bitop (bit_and bit_ior) > cmp (eq ne) > /* PR35691: Transform > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-simplify-O1.c > b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-simplify-O1.c > new file mode 100644 > index 00000000000..3d4f5328c6e > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-simplify-O1.c > @@ -0,0 +1,47 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O1 -fdump-tree-optimized" } */ > + > +/* Verify the GIMPLE-level fix for PR112533: > + (~A & 1) == (~B & 1) is lowered by GCC to one of two GIMPLE forms > + which should both be simplified to (A ^ B) & 1 == 0. */ > + > +typedef unsigned int u32; > + > +/* Source-level form from the bug report. */ > +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); > +} > + > +/* GIMPLE-level form. */ > +_Bool > +same_evenness_o1 (u32 a, u32 b) > +{ > + u32 t1 = a & 1; > + u32 t2 = b & 1; > + return (t1 == 0) == (t2 == 0); > +} > + > +_Bool > +diff_evenness_o1 (u32 a, u32 b) > +{ > + u32 t1 = a & 1; > + u32 t2 = b & 1; > + return (t1 == 0) != (t2 == 0); > +} > + > +/* Verify all four functions are optimized to the canonical XOR form. */ > +/* { dg-final { scan-tree-dump-times "\\\^" 4 "optimized" } } */ > -- > 2.34.1 > >
