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)