On Wed, Aug 19, 2026 at 9:12 PM Shivam Gupta <[email protected]> wrote: > > > > On Mon, 17 Aug 2026 at 3:09 PM, Shivam Gupta <[email protected]> wrote: >> >> >> On Mon, 17 Aug 2026 at 2:16 PM, Richard Biener <[email protected]> >> wrote: >>> >>> On Sat, Aug 15, 2026 at 8:44 PM Shivam Gupta <[email protected]> wrote: >>> > >>> > Recognize XOR patterns involving zero_one_valued operands compared >>> > against zero and simplify them to direct equality or inequality tests. >>> > >>> > Specifically: >>> > >>> > (a == 0) ^ (b != 0) -> a == b >>> > (a != 0) ^ (b == 0) -> a == b >>> > (a == 0) ^ (b == 0) -> a != b >>> > (a != 0) ^ (b != 0) -> a != b >>> > >>> > Also handle a specific case: >>> > (a == 0) ^ b -> a == b >>> > >>> > Extend the simplifications to handle the corresponding boolean >>> > equality forms as well: >>> > (a == 0) == (b != 0) -> a != b >>> > (a != 0) == (b == 0) -> a != b >>> > (a == 0) == (b == 0) -> a == b >>> > (a != 0) == (b != 0) -> a == b >>> > >>> > Regression tested on aarch64-linux-gnu with RUNTESTFLAGS="tree-ssa.exp". >>> >>> Note you need to bootstrap and run all regression tests. >>> >>> OK if you did and this showed no errors. >> >> >> No, I have not had a bootstrap build. I can have it in few hours and will >> ping the thread. >> >> Thanks for reviewing and pointing that out. >> >> Regards, >> Shivam > > > Took a little longer time to get back. There is no regression with bootstrap > build too. > > Please help me commit the change.
Pushed. Richard. > Thanks, > Shivam >>> >>> >>> Thanks, >>> Richard. >>> >>> > Changes since v1: >>> > * v3: Merge the op1 == op2 and op1 != op2 comparison patterns into a >>> > single pattern using out_cmp. >>> > Wrap the pattern inside (if (INTEGRAL_TYPE_P (type))) to explicitly >>> > guard >>> > against vector types instead of relying on zero_one_valued_p >>> > internals. >>> > Drop unnecessary ':s' tree flags and remove outer convert. >>> > Update the regression test to check for the expected canonical >>> > XOR form rather than the absence of comparisons against zero. >>> > >>> > * v2: Simplify (a == 0) ^ b to a == b. >>> > Handle outer EQ as well as outer NE forms. >>> > Use convert:type to handle differing operand types. >>> > >>> > gcc/ChangeLog: >>> > * match.pd: Add simplifications for XORs and boolean >>> > comparisons of zero_one_valued comparisons against zero. >>> > >>> > gcc/testsuite/ChangeLog: >>> > * gcc.dg/tree-ssa/bool-eq-bitxor.c: Update expected number >>> > of optimized XOR forms. >>> > * gcc.dg/tree-ssa/bool-xor-zero-one-valued.c: New test. >>> > >>> > Signed-off-by: Shivam Gupta <[email protected]> >>> > --- >>> > gcc/match.pd | 21 +++++++++++ >>> > .../gcc.dg/tree-ssa/bool-eq-bitxor.c | 5 +-- >>> > .../tree-ssa/bool-xor-zero-one-valued.c | 36 +++++++++++++++++++ >>> > 3 files changed, 58 insertions(+), 4 deletions(-) >>> > create mode 100644 >>> > gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c >>> > >>> > diff --git a/gcc/match.pd b/gcc/match.pd >>> > index 6addf8fee..edd6cd6a3 100644 >>> > --- a/gcc/match.pd >>> > +++ b/gcc/match.pd >>> > @@ -3989,6 +3989,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) >>> > (if (types_match (type, TREE_TYPE (@0))) >>> > (bit_xor @0 { build_one_cst (type); } )))))) >>> > >>> > +/* For zero_one_valued operands: >>> > + (a == 0) != b -> a == b. */ >>> > +(simplify >>> > + (ne:c (convert (eq zero_one_valued_p@0 integer_zerop)) >>> > + (convert zero_one_valued_p@1)) >>> > + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) >>> > + && types_match (TREE_TYPE (@0), TREE_TYPE (@1))) >>> > + (eq @0 @1))) >>> > + >>> > +/* For zero_one_valued operands: >>> > + (a op1 0) cmp (b op2 0) -> a out_cmp b >>> > + where out_cmp is cmp if op1 == op2, and the inverse of cmp otherwise. >>> > */ >>> > +(if (INTEGRAL_TYPE_P (type)) >>> > + (for cmp (ne ne eq eq ne ne eq eq) >>> > + op1 (eq ne eq ne eq ne eq ne) >>> > + op2 (eq ne eq ne ne eq ne eq) >>> > + out_cmp (ne ne eq eq eq eq ne ne) >>> > + (simplify >>> > + (cmp:c (op1 zero_one_valued_p@0 integer_zerop) >>> > + (op2 zero_one_valued_p@1 integer_zerop)) >>> > + (out_cmp (convert:type @0) (convert:type @1))))) >>> > >>> > /* ((a ^ b) & c) cmp d || a != b --> (0 cmp d || a != b). */ >>> > /* ((a ^ b) & c) cmp d && a == b --> (0 cmp d && a == b). */ >>> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c >>> > b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c >>> > index bc263e809..bfb3fe06b 100644 >>> > --- a/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c >>> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c >>> > @@ -36,7 +36,4 @@ xor_ne_ne (u32 a, u32 b) >>> > } >>> > >>> > /* Verify all functions canonicalize to xor-mask tests. */ >>> > -/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^ >>> > b_\[0-9\]+\\(D\\)" 3 "optimized" } } */ >>> > - >>> > -/* xor_eq_ne not optimized yet due to zero_one_valued_p >>> > canonicalization. */ >>> > -/* { dg-final { scan-tree-dump-times "& 1" 2 "optimized" { xfail *-*-* } >>> > } } */ >>> > +/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^ >>> > b_\[0-9\]+\\(D\\)" 4 "optimized" } } */ >>> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c >>> > b/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c >>> > new file mode 100644 >>> > index 000000000..95b369299 >>> > --- /dev/null >>> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c >>> > @@ -0,0 +1,36 @@ >>> > +/* { dg-do compile } */ >>> > +/* { dg-options "-O1 -fdump-tree-optimized" } */ >>> > + >>> > +_Bool >>> > +f1 (unsigned a, unsigned b) >>> > +{ >>> > + if (a != 0 && a != 1) __builtin_unreachable(); >>> > + if (b != 0 && b != 1) __builtin_unreachable(); >>> > + return (a == 0) ^ (b != 0); >>> > +} >>> > + >>> > +_Bool >>> > +f2 (unsigned a, unsigned b) >>> > +{ >>> > + if (a != 0 && a != 1) __builtin_unreachable(); >>> > + if (b != 0 && b != 1) __builtin_unreachable(); >>> > + return (a != 0) ^ (b == 0); >>> > +} >>> > + >>> > +_Bool >>> > +f3 (unsigned a, unsigned b) >>> > +{ >>> > + if (a != 0 && a != 1) __builtin_unreachable(); >>> > + if (b != 0 && b != 1) __builtin_unreachable(); >>> > + return (a == 0) ^ (b == 0); >>> > +} >>> > + >>> > +_Bool >>> > +f4 (unsigned a, unsigned b) >>> > +{ >>> > + if (a != 0 && a != 1) __builtin_unreachable(); >>> > + if (b != 0 && b != 1) __builtin_unreachable(); >>> > + return (a != 0) ^ (b != 0); >>> > +} >>> > + >>> > +/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^ >>> > b_\[0-9\]+\\(D\\)" 4 "optimized" } } */ >>> > -- >>> > 2.43.0 >>> >
