re PR tree-optimization/64910 (tree reassociation results in poor code)
authorJeff Law <law@redhat.com>
Mon, 4 Sep 2017 14:00:29 +0000 (08:00 -0600)
committerJeff Law <law@gcc.gnu.org>
Mon, 4 Sep 2017 14:00:29 +0000 (08:00 -0600)
2017-09-03  Jeff Law  <law@redhat.com>

PR tree-optimization/64910
* tree-ssa-reassoc.c (reassociate_bb): For bitwise binary ops,
swap the first and last operand if the last is a constant.

PR tree-optimization/64910
* gcc.dg/tree-ssa/pr64910-2.c: New test.

From-SVN: r251659

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c [new file with mode: 0644]
gcc/tree-ssa-reassoc.c

index 0bc8b4b9b1815aaf5e5a76146b4b1fa7a7dae383..5170417bbb025008b620b4b8046bd9195af0a33d 100644 (file)
@@ -1,3 +1,9 @@
+2017-09-04  Jeff Law  <law@redhat.com>
+
+       PR tree-optimization/64910
+       * tree-ssa-reassoc.c (reassociate_bb): For bitwise binary ops,
+       swap the first and last operand if the last is a constant.
+
 2017-09-04  Marek Polacek  <polacek@redhat.com>
 
        PR sanitizer/82072
index 45cee1fe463ffe71bcbf3941d7014bb2b85ffa5a..8920c76f8c5d94aec0e62d0ebc9557ff94ec9f6c 100644 (file)
@@ -1,3 +1,8 @@
+2017-09-04  Jeff Law  <law@redhat.com>
+
+       PR tree-optimization/64910
+       * gcc.dg/tree-ssa/pr64910-2.c: New test.
+
 2017-09-04  Marek Polacek  <polacek@redhat.com>
 
        PR sanitizer/82072
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c
new file mode 100644 (file)
index 0000000..2e3d679
--- /dev/null
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-reassoc1" } */
+
+/* We want to make sure that we reassociate in a way that has the
+   constant last.  With the constant last, it's more likely to result
+   in a bitfield test on targets with such capabilities.  */
+
+extern void boo ();
+
+int b2b_uc (unsigned char u, unsigned char w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+
+int b2b_us (unsigned short u, unsigned short w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+
+int b2b_ui (unsigned int u, unsigned int w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+int b2b_ul (unsigned long u, unsigned long w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+int b2b_ull (unsigned long long u, unsigned long long w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+
+int b2b_sc (signed char u, signed char w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+
+int b2b_ss (signed short u, signed short w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+
+int b2b_si (signed int u, signed int w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+int b2b_sl (signed long u, signed long w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+int b2b_sll (signed long long u, signed long long w)
+{
+  if ((u & w) & 0x20)
+    boo ();
+}
+
+/* The AND of U & W should go into a temporary, when is then ANDed
+   with the constant.
+
+   First verify that we have the right number of ANDs between U and W.  */
+/* { dg-final { scan-tree-dump-times "\[uw\]_\[0-9\]+.D. \& \[uw\]_\[0-9\]+.D.;" 10 "reassoc1"} } */
+
+/* Then verify that we have the right number of ANDS between a temporary
+   and the constant.  */
+/* { dg-final { scan-tree-dump-times "_\[0-9]+ \& 32;" 10 "reassoc1"} } */
+
+/* Each function has one AND.  It will have either a second AND or TEST.  So
+   we can count the number of AND and TEST instructions.  They must be 2X
+   the number of test functions in this file.  */
+/* { dg-final { scan-assembler-times "and|test" 20 { target { i?86-*-* x86_64-*-*} } } } */
+
+/* Similarly on the m68k.  The code for the long long tests is suboptimal,
+   which catch via the second pattern and xfail.  */
+/* { dg-final { scan-assembler-times "and|btst" 20 { target { m68k-*-* } } } } */
+/* { dg-final { scan-assembler-not "or" { target { m68k-*-* } xfail { *-*-* } } } } */
+
index 561acea4dcc14d6bc25e0c6812ffdefdd630aa14..76048196b277804f937984e9dbe850e24e42b723 100644 (file)
@@ -5762,6 +5762,18 @@ reassociate_bb (basic_block bb)
                    fprintf (dump_file,
                             "Width = %d was chosen for reassociation\n", width);
 
+
+                 /* For binary bit operations, if the last operand in
+                    OPS is a constant, move it to the front.  This
+                    helps ensure that we generate (X & Y) & C rather
+                    than (X & C) & Y.  The former will often match
+                    a canonical bit test when we get to RTL.  */
+                 if ((rhs_code == BIT_AND_EXPR
+                      || rhs_code == BIT_IOR_EXPR
+                      || rhs_code == BIT_XOR_EXPR)
+                     && TREE_CODE (ops.last ()->op) == INTEGER_CST)
+                   std::swap (*ops[0], *ops[ops_num - 1]);
+
                  if (width > 1
                      && ops.length () > 3)
                    rewrite_expr_tree_parallel (as_a <gassign *> (stmt),