]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-ssa-threadedge.c (thread_across_edge): Do not allow threading through joiner...
authorJeff Law <law@redhat.com>
Wed, 23 Oct 2013 13:54:48 +0000 (07:54 -0600)
committerJeff Law <law@gcc.gnu.org>
Wed, 23 Oct 2013 13:54:48 +0000 (07:54 -0600)
* tree-ssa-threadedge.c (thread_across_edge): Do not allow threading
through joiner blocks with abnormal outgoing edges.

* tree-ssa-threadupdate.c (thread_block_1): Renamed from thread_block.
Add parameter JOINERS, to allow/disallow threading through joiner
blocks.
(thread_block): New.  Call thread_block_1.
(mark_threaded_blocks): Remove code to filter out certain cases
of threading through joiner blocks.
(thread_through_all_blocks): Document how we can have a dangling
edge AUX field and clear it.

From-SVN: r203975

gcc/ChangeLog
gcc/tree-ssa-threadedge.c
gcc/tree-ssa-threadupdate.c

index 613251571764990022631821cb8a5552d0a0a841..acd6620a048c0a31c645425666590f954afec850 100644 (file)
@@ -1,3 +1,17 @@
+2013-10-23  Jeff Law  <law@redhat.com>
+
+       * tree-ssa-threadedge.c (thread_across_edge): Do not allow threading
+       through joiner blocks with abnormal outgoing edges.
+
+       * tree-ssa-threadupdate.c (thread_block_1): Renamed from thread_block.
+       Add parameter JOINERS, to allow/disallow threading through joiner
+       blocks.
+       (thread_block): New.  Call thread_block_1.
+       (mark_threaded_blocks): Remove code to filter out certain cases
+       of threading through joiner blocks.
+       (thread_through_all_blocks): Document how we can have a dangling
+       edge AUX field and clear it.
+
 2013-10-23  Ian Lance Taylor  <iant@google.com>
 
        * doc/invoke.texi (Option Summary): Remove -fno-default-inline.
index bbc4f9b71c6b30f5f355397e45467b645d128670..810908b40dd1d40bf070c5d4eecf8863ae841d75 100644 (file)
@@ -1040,6 +1040,16 @@ thread_across_edge (gimple dummy_cond,
     edge_iterator ei;
     bool found;
 
+    /* If E->dest has abnormal outgoing edges, then there's no guarantee
+       we can safely redirect any of the edges.  Just punt those cases.  */
+    FOR_EACH_EDGE (taken_edge, ei, e->dest->succs)
+      if (taken_edge->flags & EDGE_ABNORMAL)
+       {
+         remove_temporary_equivalences (stack);
+         BITMAP_FREE (visited);
+         return;
+       }
+
     /* Look at each successor of E->dest to see if we can thread through it.  */
     FOR_EACH_EDGE (taken_edge, ei, e->dest->succs)
       {
index bde81a88c1908f6dc591eddbd25de110dc9011ca..10271919786b5f444a4a9f97f8ef021718746acb 100644 (file)
@@ -616,10 +616,12 @@ redirection_block_p (basic_block bb)
    the appropriate duplicate of BB.
 
    If NOLOOP_ONLY is true, we only perform the threading as long as it
-   does not affect the structure of the loops in a nontrivial way.  */
+   does not affect the structure of the loops in a nontrivial way. 
+
+   If JOINERS is true, then thread through joiner blocks as well.  */
 
 static bool
-thread_block (basic_block bb, bool noloop_only)
+thread_block_1 (basic_block bb, bool noloop_only, bool joiners)
 {
   /* E is an incoming edge into BB that we may or may not want to
      redirect to a duplicate of BB.  */
@@ -642,7 +644,9 @@ thread_block (basic_block bb, bool noloop_only)
       e = loop_latch_edge (loop);
       vec<jump_thread_edge *> *path = THREAD_PATH (e);
 
-      if (path)
+      if (path
+         && (((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK && joiners)
+             || ((*path)[1]->type == EDGE_COPY_SRC_BLOCK && !joiners)))
        {
          for (unsigned int i = 1; i < path->length (); i++)
            {
@@ -666,6 +670,11 @@ thread_block (basic_block bb, bool noloop_only)
        continue;
 
       vec<jump_thread_edge *> *path = THREAD_PATH (e);
+
+      if (((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK && !joiners)
+         || ((*path)[1]->type == EDGE_COPY_SRC_BLOCK && joiners))
+       continue;
+
       e2 = path->last ()->e;
       if (!e2 || noloop_only)
        {
@@ -762,6 +771,24 @@ thread_block (basic_block bb, bool noloop_only)
   return local_info.jumps_threaded;
 }
 
+/* Wrapper for thread_block_1 so that we can first handle jump
+   thread paths which do not involve copying joiner blocks, then
+   handle jump thread paths which have joiner blocks.
+
+   By doing things this way we can be as aggressive as possible and
+   not worry that copying a joiner block will create a jump threading
+   opportunity.  */
+  
+static bool
+thread_block (basic_block bb, bool noloop_only)
+{
+  bool retval;
+  retval = thread_block_1 (bb, noloop_only, false);
+  retval |= thread_block_1 (bb, noloop_only, true);
+  return retval;
+}
+
+
 /* Threads edge E through E->dest to the edge THREAD_TARGET (E).  Returns the
    copy of E->dest created during threading, or E->dest if it was not necessary
    to copy it (E is its single predecessor).  */
@@ -1240,57 +1267,14 @@ mark_threaded_blocks (bitmap threaded_blocks)
   edge e;
   edge_iterator ei;
 
-  /* 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.  */
+  /* Move the jump threading requests from PATHS to each edge
+     which starts a jump thread path.  */
   for (i = 0; i < paths.length (); i++)
     {
       vec<jump_thread_edge *> *path = paths[i];
-
-      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);
-           }
-       }
+      edge e = (*path)[0]->e;
+      e->aux = (void *)path;
+      bitmap_set_bit (tmp, e->dest->index);
     }
 
   /* If we have a joiner block (J) which has two successors S1 and S2 and
@@ -1488,6 +1472,39 @@ thread_through_all_blocks (bool may_peel_loop_headers)
       retval |= thread_through_loop_header (loop, may_peel_loop_headers);
     }
 
+  /* Assume we had a jump thread path which went from the latch to the exit
+     and a path which goes from outside to inside the same loop.  
+
+     If the latch to exit was handled first, we will thread it and clear
+     loop->header.
+
+     The second path will be ignored by thread_block because we're going
+     through a loop header.  It will also be ignored by the loop above
+     because loop->header is NULL.
+
+     This results in the second path never being threaded.  The failure
+     mode is a dangling AUX field.
+
+     This is inherently a bit of a pain to fix, so we just walk all the
+     blocks and all the incoming edges to those blocks and clear their
+     AUX fields.  */
+  basic_block bb;
+  edge_iterator ei;
+  edge e;
+  FOR_EACH_BB (bb)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+       if (e->aux)
+         {
+           vec<jump_thread_edge *> *path = THREAD_PATH (e);
+
+           for (unsigned int i = 0; i < path->length (); i++)
+             delete (*path)[i];
+           path->release ();
+           e->aux = NULL;
+         }
+    }
+
   statistics_counter_event (cfun, "Jumps threaded",
                            thread_stats.num_threaded_edges);