re PR tree-optimization/81396 (Optimization of reading Little-Endian 64-bit number...
authorJakub Jelinek <jakub@redhat.com>
Mon, 17 Jul 2017 08:14:16 +0000 (10:14 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 17 Jul 2017 08:14:16 +0000 (10:14 +0200)
PR tree-optimization/81396
* tree-ssa-math-opts.c (struct symbolic_number): Add n_ops field.
(init_symbolic_number): Initialize it to 1.
(perform_symbolic_merge): Add n_ops from both operands into the new
n_ops.
(find_bswap_or_nop): Don't consider n->n == cmpnop computations
without base_addr as useless if they need more than one operation.
(bswap_replace): Handle !bswap case for NULL base_addr.

* gcc.dg/tree-ssa/pr81396.c: New test.

From-SVN: r250257

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr81396.c [new file with mode: 0644]
gcc/tree-ssa-math-opts.c

index 67b7ff1..f57ef04 100644 (file)
@@ -1,3 +1,14 @@
+2017-07-17  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/81396
+       * tree-ssa-math-opts.c (struct symbolic_number): Add n_ops field.
+       (init_symbolic_number): Initialize it to 1.
+       (perform_symbolic_merge): Add n_ops from both operands into the new
+       n_ops.
+       (find_bswap_or_nop): Don't consider n->n == cmpnop computations
+       without base_addr as useless if they need more than one operation.
+       (bswap_replace): Handle !bswap case for NULL base_addr.
+
 2017-07-17  Tom de Vries  <tom@codesourcery.com>
 
        PR target/81069
index 872d24e..67ffc3e 100644 (file)
@@ -1,3 +1,8 @@
+2017-07-17  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/81396
+       * gcc.dg/tree-ssa/pr81396.c: New test.
+
 2017-07-16  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gnat.dg/opt65.adb: New test.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81396.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81396.c
new file mode 100644 (file)
index 0000000..9f4a08d
--- /dev/null
@@ -0,0 +1,25 @@
+/* PR tree-optimization/81396 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+typedef unsigned long long uint64_t;
+
+uint64_t
+foo (uint64_t word)
+{
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_LONG_LONG__ == 8
+  const unsigned char *const ptr = (const unsigned char *) &word;
+  return ((uint64_t) ptr[0]
+         | ((uint64_t) ptr[1] << 8)
+         | ((uint64_t) ptr[2] << (8 * 2))
+         | ((uint64_t) ptr[3] << (8 * 3))
+         | ((uint64_t) ptr[4] << (8 * 4))
+         | ((uint64_t) ptr[5] << (8 * 5))
+         | ((uint64_t) ptr[6] << (8 * 6))
+         | ((uint64_t) ptr[7] << (8 * 7)));
+#else
+  return word;
+#endif
+}
+
+/* { dg-final { scan-tree-dump "return word_\[0-9]*\\(D\\);" "optimized" } } */
index c59dce0..7ac1659 100644 (file)
@@ -1946,7 +1946,9 @@ make_pass_cse_sincos (gcc::context *ctxt)
    - a range which gives the difference between the highest and lowest accessed
      memory location to make such a symbolic number;
    - the address SRC of the source element of lowest address as a convenience
-     to easily get BASE_ADDR + offset + lowest bytepos.
+     to easily get BASE_ADDR + offset + lowest bytepos;
+   - number of expressions N_OPS bitwise ored together to represent
+     approximate cost of the computation.
 
    Note 1: the range is different from size as size reflects the size of the
    type of the current expression.  For instance, for an array char a[],
@@ -1968,6 +1970,7 @@ struct symbolic_number {
   tree alias_set;
   tree vuse;
   unsigned HOST_WIDE_INT range;
+  int n_ops;
 };
 
 #define BITS_PER_MARKER 8
@@ -2083,6 +2086,7 @@ init_symbolic_number (struct symbolic_number *n, tree src)
     return false;
   n->range = size;
   n->n = CMPNOP;
+  n->n_ops = 1;
 
   if (size < 64 / BITS_PER_MARKER)
     n->n &= ((uint64_t) 1 << (size * BITS_PER_MARKER)) - 1;
@@ -2293,6 +2297,7 @@ perform_symbolic_merge (gimple *source_stmt1, struct symbolic_number *n1,
        return NULL;
     }
   n->n = n1->n | n2->n;
+  n->n_ops = n1->n_ops + n2->n_ops;
 
   return source_stmt;
 }
@@ -2588,7 +2593,7 @@ find_bswap_or_nop (gimple *stmt, struct symbolic_number *n, bool *bswap)
     return NULL;
 
   /* Useless bit manipulation performed by code.  */
-  if (!n->base_addr && n->n == cmpnop)
+  if (!n->base_addr && n->n == cmpnop && n->n_ops == 1)
     return NULL;
 
   n->range *= BITS_PER_UNIT;
@@ -2747,6 +2752,36 @@ bswap_replace (gimple *cur_stmt, gimple *ins_stmt, tree fndecl,
        }
       src = val_tmp;
     }
+  else if (!bswap)
+    {
+      gimple *g;
+      if (!useless_type_conversion_p (TREE_TYPE (tgt), TREE_TYPE (src)))
+       {
+         if (!is_gimple_val (src))
+           return false;
+         g = gimple_build_assign (tgt, NOP_EXPR, src);
+       }
+      else
+       g = gimple_build_assign (tgt, src);
+      if (n->range == 16)
+       nop_stats.found_16bit++;
+      else if (n->range == 32)
+       nop_stats.found_32bit++;
+      else
+       {
+         gcc_assert (n->range == 64);
+         nop_stats.found_64bit++;
+       }
+      if (dump_file)
+       {
+         fprintf (dump_file,
+                  "%d bit reshuffle in target endianness found at: ",
+                  (int) n->range);
+         print_gimple_stmt (dump_file, cur_stmt, 0);
+       }
+      gsi_replace (&gsi, g, true);
+      return true;
+    }
   else if (TREE_CODE (src) == BIT_FIELD_REF)
     src = TREE_OPERAND (src, 0);