Re: [PATCH v2] match.pd: Simplify XORs of zero_one_valued comparisons
Shivam Gupta <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CAHX=PX_CBUeHjf_amwBVd51h5j7zB9vbbRHsZyFaKcjjSpXOOw@mail.gmail.com> |
On Thu, Aug 13, 2026 at 5:58 PM Richard Biener <[email protected]> wrote: > > On Sun, May 31, 2026 at 5:33 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. > > > > Changes since v1: > > * 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 | 29 +++++++++++++++ > > .../gcc.dg/tree-ssa/bool-eq-bitxor.c | 4 +- > > .../tree-ssa/bool-xor-zero-one-valued.c | 37 +++++++++++++++++++ > > 3 files changed, 67 insertions(+), 3 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 228bab78428..bed3ca23c6c 100644 > > --- a/gcc/match.pd > > +++ b/gcc/match.pd > > @@ -3765,6 +3765,35 @@ 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 (convert:s (eq zero_one_valued_p@0 integer_zerop)) > > Don't you need :c on the 'ne'? > > > + (convert:s zero_one_valued_p@1)) > > I'd drop the :s everywhere. > > > + (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1))) > > + (convert (eq @0 @1)))) > > Why the outer (convert ...)? > > > + > > +/* For zero_one_valued operands: > > + (a op1 0) cmp (b op2 0) -> a icmp b > > + where op1 != op2. */ > > +(for cmp (ne eq) > > + icmp (eq ne) > > + (for op1 (eq ne) > > + op2 (ne eq) > > + (simplify > > + (cmp:c (op1 zero_one_valued_p@0 integer_zerop) > > + (op2 zero_one_valued_p@1 integer_zerop)) > > + (icmp (convert:type @0) (convert:type @1))))) > > + > > +/* For zero_one_valued operands: > > + (a op 0) cmp (b op 0) -> a cmp b. */ > > This coud be merged into the above by appending > cmp == icmp, op1 == op2 cases, no? > > All patterns are problematic for vector types I think, > zero_one_valued_p currently never fires for those > but I wonder if we should make this explicit in the > users rather relying on that never changing? > Thank you for the review. I have address all the comments in v3 of patch. Best regards, Shivam > Thanks, > Richard. > > > +(for cmp (ne eq) > > + (for op (eq ne) > > + (simplify > > + (cmp:c (op zero_one_valued_p@0 integer_zerop) > > + (op zero_one_valued_p@1 integer_zerop)) > > + (cmp (convert:type @0) (convert:type @1))))) > > + > > /* ((a ^ b) & c) cmp d || a != b --> (0 cmp d || a != b). */ > > (for cmp (simple_comparison) > > (simplify > > 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 bc263e80977..e39e82589b6 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,5 @@ 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" } } */ > > +/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^ b_\[0-9\]+\\(D\\)" 4 "optimized" } } */ > > > > -/* xor_eq_ne not optimized yet due to zero_one_valued_p canonicalization. */ > > -/* { dg-final { scan-tree-dump-times "& 1" 2 "optimized" { xfail *-*-* } } } */ > > 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 00000000000..2bc10db4e70 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c > > @@ -0,0 +1,37 @@ > > +/* { 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 "== 0" 0 "optimized" } } */ > > +/* { dg-final { scan-tree-dump-times "!= 0" 0 "optimized" } } */ > > -- > > 2.34.1 > >