[gcc r17-3465] match.pd: Simplify XORs of zero_one_valued comparisons
Richard Biener via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:7f6a999da640a9d33fa8d572c805884eeaac2935 commit r17-3465-g7f6a999da640a9d33fa8d572c805884eeaac2935 Author: Shivam Gupta <[email protected]> Date: Sun Aug 16 00:13:44 2026 +0530 match.pd: Simplify XORs of zero_one_valued comparisons 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". 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]> Diff: --- gcc/match.pd | 21 +++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c | 5 +-- .../gcc.dg/tree-ssa/bool-xor-zero-one-valued.c | 36 ++++++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/gcc/match.pd b/gcc/match.pd index 3cb5cfbe6926..0d1a61321d49 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4037,6 +4037,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 bc263e809770..bfb3fe06bc9a 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 000000000000..95b369299398 --- /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" } } */