* tree-cfg.c (thread_jumps): Speed up by using a worklist.
authorKazu Hirata <kazu@cs.umass.edu>
Thu, 21 Oct 2004 16:06:31 +0000 (16:06 +0000)
committerKazu Hirata <kazu@gcc.gnu.org>
Thu, 21 Oct 2004 16:06:31 +0000 (16:06 +0000)
From-SVN: r89381

gcc/ChangeLog
gcc/tree-cfg.c

index f04bff45e933f68709131d0df53731909315da16..c46f5e43bfbbf9adf27bbd05bf825164a98539a9 100644 (file)
@@ -1,3 +1,7 @@
+2004-10-21  Kazu Hirata  <kazu@cs.umass.edu>
+
+       * tree-cfg.c (thread_jumps): Speed up by using a worklist.
+
 2004-10-21  Kazu Hirata  <kazu@cs.umass.edu>
 
        * tree-cfg.c (thread_jumps): Move a part of it to ...
index 3c4cd713146e51ee16d465aaa1d85608971b04ae..d58bb13d9dd7dcd62c0ac2240234a3b47e1b13ba 100644 (file)
@@ -3942,35 +3942,102 @@ thread_jumps (void)
 {
   basic_block bb;
   bool retval = false;
-  bool rerun;
+  int *worklist = xmalloc (sizeof (int) * last_basic_block);
+  unsigned int size = 0;
 
   FOR_EACH_BB (bb)
-    bb_ann (bb)->forwardable = tree_forwarder_block_p (bb);
+    {
+      bb_ann (bb)->forwardable = tree_forwarder_block_p (bb);
+      bb->flags &= ~BB_VISITED;
+    }
 
-  do
+  /* Initialize WORKLIST by putting the indexes of non-forwarder
+     blocks that immediately precede forwarder blocks because those
+     are the ones that we know we can thread jumps from.  We use
+     BB_VISITED to indicate that whether a given basic block is in
+     WORKLIST or not, thereby avoiding duplicates in WORKLIST.  */
+  FOR_EACH_BB (bb)
     {
-      rerun = false;
-      FOR_EACH_BB (bb)
+      edge_iterator ei;
+      edge e;
+
+      /* We are not interested in finding non-forwarder blocks
+        directly.  We want to find non-forwarder blocks as
+        predecessors of a forwarder block.  */
+      if (!bb_ann (bb)->forwardable)
+       continue;
+
+      /* Now we know BB is a forwarder block.  Visit each of its
+        incoming edges and add to WORKLIST all non-forwarder blocks
+        among BB's predecessors.  */
+      FOR_EACH_EDGE (e, ei, bb->preds)
        {
-         /* Don't waste time on forwarders.  */
-         if (bb_ann (bb)->forwardable)
-           continue;
+         /* We are not interested in threading jumps from a forwarder
+            block.  */
+         if (!bb_ann (e->src)->forwardable
+             /* We don't want to visit ENTRY_BLOCK_PTR.  */
+             && e->src->index >= 0
+             /* We don't want to put a duplicate into WORKLIST.  */
+             && (e->src->flags & BB_VISITED) == 0)
+           {
+             e->src->flags |= BB_VISITED;
+             worklist[size] = e->src->index;
+             size++;
+           }
+       }
+    }
 
-         if (thread_jumps_from_bb (bb))
+  /* Now let's drain WORKLIST.  */
+  while (size > 0)
+    {
+      size--;
+      bb = BASIC_BLOCK (worklist[size]);
+
+      /* Check if BB is NULL because BB may have been deleted.  This
+        could happen if BB is originally a non-forwarder block, later
+        becomes a forwarder block, and it is deleted when a jump is
+        threaded through it.  */
+      if (!bb)
+       continue;
+
+      /* BB->INDEX is not longer in WORKLIST, so clear BB_VISITED.  */
+      bb->flags &= ~BB_VISITED;
+
+      if (thread_jumps_from_bb (bb))
+       {
+         retval = true;
+
+         if (tree_forwarder_block_p (bb))
            {
-             retval = true;
+             edge_iterator ej;
+             edge f;
+
+             bb_ann (bb)->forwardable = true;
 
-             /* If we succeeded in threading a jump at BB, update the
-                forwardable mark as BB may have become a new
-                forwarder block.  This could happen if we have a
-                useless "if" statement whose two arms eventually
-                merge without any intervening statements.  */
-             if (tree_forwarder_block_p (bb))
-               bb_ann (bb)->forwardable = rerun = true;
+             /* Attempts to thread through BB may have been blocked
+                because BB was not a forwarder block before.  Now
+                that BB is a forwarder block, we should revisit BB's
+                predecessors.  */
+             FOR_EACH_EDGE (f, ej, bb->preds)
+               {
+                 /* We are not interested in threading jumps from a
+                    forwarder block.  */
+                 if (!bb_ann (f->src)->forwardable
+                     /* We don't want to visit ENTRY_BLOCK_PTR.  */
+                     && f->src->index >= 0
+                     /* We don't want to put a duplicate into WORKLIST.  */
+                     && (f->src->flags & BB_VISITED) == 0)
+                   {
+                     f->src->flags |= BB_VISITED;
+                     worklist[size] = f->src->index;
+                     size++;
+                   }
+               }
            }
        }
     }
-  while (rerun);
+
+  free (worklist);
 
   return retval;
 }