[PATCH] match.pd: merge two masked equality tests of one value
<[email protected]> Tue, 4 Aug 2026 12:37:43 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
From: Kyrylo Tkachov <[email protected]> Two masked tests of the same value examine one set of bits, so one mask and one comparison do the whole job: ((X & C1) == C2) & ((X & C3) == C4) -> (X & (C1 | C3)) == (C2 | C4) when C2 and C4 agree on the bits both masks select -> false when they disagree and the inclusive or of the two inequalities is the De Morgan dual. int f (unsigned x) { return ((x & 5) == 5) & ((x & 24) == 24); } aarch64 -O2 before: and w1, w0, 5 and w0, w0, 24 cmp w1, 5 cset w1, eq cmp w0, 24 cset w0, eq and w0, w0, w1 after: and w0, w0, 29 cmp w0, 29 cset w0, eq A test whose constant has a bit outside its own mask is decided already and is left to the rules that decide it. Bootstrapped and tested on aarch64-none-linux-gnu. Ok for trunk? Thanks, Kyrill gcc/ChangeLog: * match.pd (((X & C1) == C2) &/| ((X & C3) == C4)): New simplification. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/maskcmp-merge-1.c: New test. Signed-off-by: Kyrylo Tkachov <[email protected]> --- gcc/match.pd | 28 +++++++++++++++++++ .../gcc.dg/tree-ssa/maskcmp-merge-1.c | 26 +++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/maskcmp-merge-1.c diff --git a/gcc/match.pd b/gcc/match.pd index 41acf869f9c..fa3856fc50e 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -3939,6 +3939,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) { constant_boolean_node (true, type); }) )))))) +/* Merge two masked equality tests of the same value. + + ((X & C1) == C2) & ((X & C3) == C4) + -> (X & (C1 | C3)) == (C2 | C4) when C2 and C4 agree on the bits + both masks select + -> false when they disagree + + and the inclusive or of the two inequalities is the De Morgan dual. Two + masked tests of one value examine one set of bits, so one mask and one + comparison do the whole job. */ +(for cmp (eq ne) + bitop (bit_and bit_ior) + (simplify + (bitop (cmp:s (bit_and:s @0 INTEGER_CST@1) INTEGER_CST@2) + (cmp:s (bit_and:s @0 INTEGER_CST@3) INTEGER_CST@4)) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))) + (with { wide_int m1 = wi::to_wide (@1), v1 = wi::to_wide (@2); + wide_int m2 = wi::to_wide (@3), v2 = wi::to_wide (@4); + tree t0 = TREE_TYPE (@0); } + /* A test whose constant has a bit outside its mask is decided already + and is left to the rules that decide it. */ + (if (wi::bit_and_not (v1, m1) == 0 + && wi::bit_and_not (v2, m2) == 0) + (if ((m1 & m2 & (v1 ^ v2)) == 0) + (cmp (bit_and @0 { wide_int_to_tree (t0, m1 | m2); }) + { wide_int_to_tree (t0, v1 | v2); }) + { constant_boolean_node (cmp == NE_EXPR, type); })))))) + /* Combine two vector comparisons against zero into one: (A == 0) & (B == 0) --> (A | B) == 0 (A != 0) | (B != 0) --> (A | B) != 0 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/maskcmp-merge-1.c b/gcc/testsuite/gcc.dg/tree-ssa/maskcmp-merge-1.c new file mode 100644 index 00000000000..9509afce27e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/maskcmp-merge-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +typedef unsigned int u; + +/* Two masked tests of one value examine one set of bits, so one mask and + one comparison do the whole job. */ + +int a1 (u x) { return ((x & 5) == 5) & ((x & 24) == 24); } +int a2 (u x) { return ((x & 5) == 1) & ((x & 24) == 16); } +int a3 (u x) { return ((x & 5) == 0) & ((x & 24) == 24); } +int a4 (u x) { return ((x & 12) == 12) & ((x & 20) == 4); } + +/* The De Morgan dual. */ +int b1 (u x) { return ((x & 5) != 5) | ((x & 24) != 24); } +int b2 (u x) { return ((x & 5) != 1) | ((x & 24) != 16); } + +/* Bit 2 is selected by both masks and the two tests disagree on it, so the + conjunction is false and the disjunction is true. */ +int c1 (u x) { return ((x & 6) == 6) & ((x & 12) == 8); } +int c2 (u x) { return ((x & 6) != 6) | ((x & 12) != 8); } + +/* { dg-final { scan-tree-dump-times " & 29" 5 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " & 28" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "return 0;" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "return 1;" 1 "optimized" } } */ -- 2.50.1 (Apple Git-155)