Re: [PATCH v3] match.pd: Simplify XORs of zero_one_valued comparisons
Shivam Gupta <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CAHX=PX-Ln1EA1nF=6E6CNpdMVV=EUddAZnHUhtsJOymqa9zjmg@mail.gmail.com> |
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. 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 >> > >> >