[PATCH] match.pd: add the inclusive or dual of the masked comparison rule
<[email protected]> Tue, 4 Aug 2026 12:03:43 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
From: Kyrylo Tkachov <[email protected]> (X & C) == (Y & C) already folds to ((X ^ Y) & C) == 0. The dual was missing: two values ored with the same constant agree on the bits that constant forces, so only the bits outside it can differ. int f (unsigned char a, unsigned char b) { return (a | 32) == (b | 32); } aarch64 -O2 before: orr w1, w1, 32 orr w0, w0, 32 cmp w1, w0 cset w0, eq after: eor w0, w0, w1 tst w0, 223 cset w0, eq This is the case insensitive ASCII comparison, and any equality of two values on a masked field. The rule sits directly beside its bit_and dual, inside the same eq and ne iterator. Bootstrapped and tested on aarch64-none-linux-gnu. Ok for trunk? Thanks, Kyrill gcc/ChangeLog: * match.pd ((X | C) ==/!= (Y | C)): New simplification. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/ior-cmp-xor-1.c: New test. Signed-off-by: Kyrylo Tkachov <[email protected]> --- gcc/match.pd | 11 ++++++++++- gcc/testsuite/gcc.dg/tree-ssa/ior-cmp-xor-1.c | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ior-cmp-xor-1.c diff --git a/gcc/match.pd b/gcc/match.pd index 85fea9fa18f..d5b5924d41f 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -8555,7 +8555,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* (X & C) op (Y & C) into (X ^ Y) & C op 0. */ (simplify (cmp (bit_and:cs @0 @2) (bit_and:cs @1 @2)) - (cmp (bit_and (bit_xor @0 @1) @2) { build_zero_cst (TREE_TYPE (@2)); }))) + (cmp (bit_and (bit_xor @0 @1) @2) + { build_zero_cst (TREE_TYPE (@2)); })) + + /* (X | C) op (Y | C) into (X ^ Y) & ~C op 0, the dual of the rule above. + The two values agree on the bits C forces, so only the bits outside C + can differ. */ + (simplify + (cmp (bit_ior:cs @0 @2) (bit_ior:cs @1 @2)) + (cmp (bit_and (bit_xor @0 @1) (bit_not! @2)) + { build_zero_cst (TREE_TYPE (@2)); }))) /* (X < 0) != (Y < 0) into (X ^ Y) < 0. (X >= 0) != (Y >= 0) into (X ^ Y) < 0. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ior-cmp-xor-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ior-cmp-xor-1.c new file mode 100644 index 00000000000..0abd54049c3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ior-cmp-xor-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +/* Two values ored with the same constant agree on the bits that constant + forces, so only the bits outside it can differ. The dual of the existing + (X & C) == (Y & C) rule. */ + +int f1 (unsigned char a, unsigned char b) { return (a | 32) == (b | 32); } +int f2 (unsigned a, unsigned b) { return (a | 32) != (b | 32); } +int f3 (unsigned a, unsigned b) { return (a | 0xff000000u) == (b | 0xff000000u); } + +/* { dg-final { scan-tree-dump-not " \\| 32" "optimized" } } */ +/* { dg-final { scan-tree-dump-not " \\| 4278190080" "optimized" } } */ +/* { dg-final { scan-tree-dump-times " \\^ " 3 "optimized" } } */ -- 2.50.1 (Apple Git-155)