re PR tree-optimization/59597 (Performance degradation on Coremark after r205074)
authorJeff Law <law@redhat.com>
Wed, 22 Jan 2014 21:27:38 +0000 (14:27 -0700)
committerJeff Law <law@gcc.gnu.org>
Wed, 22 Jan 2014 21:27:38 +0000 (14:27 -0700)
PR tree-optimization/59597
* tree-ssa-threadupdate.c (dump_jump_thread_path): Move to earlier
in file.  Accept new argument REGISTERING and use it to modify
dump output appropriately.
(register_jump_thread): Corresponding changes.
(mark_threaded_blocks): Reinstate code to cancel unprofitable
thread paths involving joiner blocks.  Add code to dump cancelled
jump threading paths.

PR tree-optimization/59597
* gcc.dg/tree-ssa/pr59597.c: New test.

From-SVN: r206941

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr59597.c [new file with mode: 0644]
gcc/tree-ssa-threadupdate.c

index 8e0997743a301a3514136bb115f9af0171b4f885..f6df113dc00689e4abf9e6a6439e1a31111f7437 100644 (file)
@@ -1,3 +1,14 @@
+2014-01-22  Jeff Law  <law@redhat.com>
+
+       PR tree-optimization/59597
+       * tree-ssa-threadupdate.c (dump_jump_thread_path): Move to earlier
+       in file.  Accept new argument REGISTERING and use it to modify
+       dump output appropriately.
+       (register_jump_thread): Corresponding changes.
+       (mark_threaded_blocks): Reinstate code to cancel unprofitable
+       thread paths involving joiner blocks.  Add code to dump cancelled
+       jump threading paths.
+
 2014-01-22  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR rtl-optimization/59477
index 6b49a1270b6f975ba430a4479c2f434c1e87badd..6f26f7fe744117df5ef6b94f3e0d601fa2fa2629 100644 (file)
@@ -1,3 +1,8 @@
+2014-01-22  Jeff Law  <law@redhat.com>
+
+       PR tree-optimization/59597
+       * gcc.dg/tree-ssa/pr59597.c: New test.
+
 2014-01-22  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR rtl-optimization/59477
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr59597.c b/gcc/testsuite/gcc.dg/tree-ssa/pr59597.c
new file mode 100644 (file)
index 0000000..814d299
--- /dev/null
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-Ofast -fdump-tree-vrp1-details" } */
+
+typedef unsigned short u16;
+typedef unsigned char u8;
+typedef unsigned int u32;
+#define NNN 10
+
+u32 f[NNN], t[NNN];
+
+u16 Calc_crc8(u8 data, u16 crc )
+{
+  u8 i=0,x16=0,carry=0;
+  for (i = 0; i < 8; i++)
+    {
+      x16 = (u8)((data & 1) ^ ((u8)crc & 1));
+      data >>= 1;
+      if (x16 == 1)
+       {
+         crc ^= 0x4002;
+         carry = 1;
+       }
+      else
+       carry = 0;
+      crc >>= 1;
+      if (carry)
+       crc |= 0x8000;
+      else
+       crc &= 0x7fff;
+    }
+  return crc;
+}
+int main (int argc, char argv[])
+{
+  int i, j; u16 crc;
+  for (j = 0; j < 10000000; j++)
+    {
+      for (i = 0; i < NNN; i++)
+       {
+         f[i] = random(i);
+         t[i] = random(NNN - i - 1);
+       }
+      for (i=0; i<NNN; i++) 
+       {
+         crc=Calc_crc8(f[i],(u16)argc);
+         crc=Calc_crc8(t[i],crc);
+       }
+    }
+  return crc;
+}
+
+/* { dg-final { scan-tree-dump "Cancelling" "vrp1" } } */
+/* { dg-final { cleanup-tree-dump "vrp1" } } */
+
index c0476b48a1c0e843e7649217db63d350a175331f..f458d6a99856f917ce81ed098e8800e57a44ed38 100644 (file)
@@ -148,6 +148,40 @@ struct redirection_data : typed_free_remove<redirection_data>
   static inline int equal (const value_type *, const compare_type *);
 };
 
+/* Dump a jump threading path, including annotations about each
+   edge in the path.  */
+
+static void
+dump_jump_thread_path (FILE *dump_file, vec<jump_thread_edge *> path,
+                      bool registering)
+{
+  fprintf (dump_file,
+          "  %s jump thread: (%d, %d) incoming edge; ",
+          (registering ? "Registering" : "Cancelling"),
+          path[0]->e->src->index, path[0]->e->dest->index);
+
+  for (unsigned int i = 1; i < path.length (); i++)
+    {
+      /* We can get paths with a NULL edge when the final destination
+        of a jump thread turns out to be a constant address.  We dump
+        those paths when debugging, so we have to be prepared for that
+        possibility here.  */
+      if (path[i]->e == NULL)
+       continue;
+
+      if (path[i]->type == EDGE_COPY_SRC_JOINER_BLOCK)
+       fprintf (dump_file, " (%d, %d) joiner; ",
+                path[i]->e->src->index, path[i]->e->dest->index);
+      if (path[i]->type == EDGE_COPY_SRC_BLOCK)
+       fprintf (dump_file, " (%d, %d) normal;",
+                path[i]->e->src->index, path[i]->e->dest->index);
+      if (path[i]->type == EDGE_NO_COPY_SRC_BLOCK)
+       fprintf (dump_file, " (%d, %d) nocopy;",
+                path[i]->e->src->index, path[i]->e->dest->index);
+    }
+  fputc ('\n', dump_file);
+}
+
 /* Simple hashing function.  For any given incoming edge E, we're going
    to be most concerned with the final destination of its jump thread
    path.  So hash on the block index of the final edge in the path.  */
@@ -1394,16 +1428,61 @@ mark_threaded_blocks (bitmap threaded_blocks)
   edge e;
   edge_iterator ei;
 
-  /* Move the jump threading requests from PATHS to each edge
-     which starts a jump thread path.  */
+  /* It is possible to have jump threads in which one is a subpath
+     of the other.  ie, (A, B), (B, C), (C, D) where B is a joiner
+     block and (B, C), (C, D) where no joiner block exists.
+
+     When this occurs ignore the jump thread request with the joiner
+     block.  It's totally subsumed by the simpler jump thread request.
+
+     This results in less block copying, simpler CFGs.  More importantly,
+     when we duplicate the joiner block, B, in this case we will create
+     a new threading opportunity that we wouldn't be able to optimize
+     until the next jump threading iteration.
+
+     So first convert the jump thread requests which do not require a
+     joiner block.  */
   for (i = 0; i < paths.length (); i++)
     {
       vec<jump_thread_edge *> *path = paths[i];
-      edge e = (*path)[0]->e;
-      e->aux = (void *)path;
-      bitmap_set_bit (tmp, e->dest->index);
+
+      if ((*path)[1]->type != EDGE_COPY_SRC_JOINER_BLOCK)
+       {
+         edge e = (*path)[0]->e;
+         e->aux = (void *)path;
+         bitmap_set_bit (tmp, e->dest->index);
+       }
     }
 
+  /* Now iterate again, converting cases where we want to thread
+     through a joiner block, but only if no other edge on the path
+     already has a jump thread attached to it.  */
+  for (i = 0; i < paths.length (); i++)
+    {
+      vec<jump_thread_edge *> *path = paths[i];
+
+      if ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK)
+       {
+         unsigned int j;
+
+         for (j = 0; j < path->length (); j++)
+           if ((*path)[j]->e->aux != NULL)
+             break;
+
+         /* If we iterated through the entire path without exiting the loop,
+            then we are good to go, attach the path to the starting edge.  */
+         if (j == path->length ())
+           {
+             edge e = (*path)[0]->e;
+             e->aux = path;
+             bitmap_set_bit (tmp, e->dest->index);
+           }
+         else if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             dump_jump_thread_path (dump_file, *path, false);
+           }
+       }
+    }
 
 
   /* If optimizing for size, only thread through block if we don't have
@@ -1712,38 +1791,6 @@ delete_jump_thread_path (vec<jump_thread_edge *> *path)
   path->release();
 }
 
-/* Dump a jump threading path, including annotations about each
-   edge in the path.  */
-
-static void
-dump_jump_thread_path (FILE *dump_file, vec<jump_thread_edge *> path)
-{
-  fprintf (dump_file,
-          "  Registering jump thread: (%d, %d) incoming edge; ",
-          path[0]->e->src->index, path[0]->e->dest->index);
-
-  for (unsigned int i = 1; i < path.length (); i++)
-    {
-      /* We can get paths with a NULL edge when the final destination
-        of a jump thread turns out to be a constant address.  We dump
-        those paths when debugging, so we have to be prepared for that
-        possibility here.  */
-      if (path[i]->e == NULL)
-       continue;
-
-      if (path[i]->type == EDGE_COPY_SRC_JOINER_BLOCK)
-       fprintf (dump_file, " (%d, %d) joiner; ",
-                path[i]->e->src->index, path[i]->e->dest->index);
-      if (path[i]->type == EDGE_COPY_SRC_BLOCK)
-       fprintf (dump_file, " (%d, %d) normal;",
-                path[i]->e->src->index, path[i]->e->dest->index);
-      if (path[i]->type == EDGE_NO_COPY_SRC_BLOCK)
-       fprintf (dump_file, " (%d, %d) nocopy;",
-                path[i]->e->src->index, path[i]->e->dest->index);
-    }
-  fputc ('\n', dump_file);
-}
-
 /* Register a jump threading opportunity.  We queue up all the jump
    threading opportunities discovered by a pass and update the CFG
    and SSA form all at once.
@@ -1770,7 +1817,7 @@ register_jump_thread (vec<jump_thread_edge *> *path)
          {
            fprintf (dump_file,
                     "Found NULL edge in jump threading path.  Cancelling jump thread:\n");
-           dump_jump_thread_path (dump_file, *path);
+           dump_jump_thread_path (dump_file, *path, false);
          }
 
        delete_jump_thread_path (path);
@@ -1778,7 +1825,7 @@ register_jump_thread (vec<jump_thread_edge *> *path)
       }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    dump_jump_thread_path (dump_file, *path);
+    dump_jump_thread_path (dump_file, *path, true);
 
   if (!paths.exists ())
     paths.create (5);