* tree-ssa-threadupdate.c: Include ssa-iterators.h
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 19 Nov 2013 03:47:40 +0000 (03:47 +0000)
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 19 Nov 2013 03:47:40 +0000 (03:47 +0000)
(copy_phi_arg_into_existing_phi): New function.
(any_remaining_duplicated_blocks): Likewise.
(ssa_fix_duplicate_block_edges): Handle multiple duplicated
blocks on a jump threading path.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205004 138bc75d-0d04-0410-961f-82ee72b054a4

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

index 841fd6c..d759d4c 100644 (file)
@@ -1,5 +1,11 @@
 2013-11-19  Jeff Law  <law@redhat.com>
 
+       * tree-ssa-threadupdate.c: Include ssa-iterators.h
+       (copy_phi_arg_into_existing_phi): New function.
+       (any_remaining_duplicated_blocks): Likewise.
+       (ssa_fix_duplicate_block_edges): Handle multiple duplicated
+       blocks on a jump threading path.
+       
        * tree-ssa-threadupdate.c (thread_through_loop_header):  Do not
        thread through a joiner which has the latch edge.
 
index bc23f4c..3fba848 100644 (file)
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-phinodes.h"
 #include "tree-ssa.h"
 #include "tree-ssa-threadupdate.h"
+#include "ssa-iterators.h"
 #include "dumpfile.h"
 #include "cfgloop.h"
 #include "hash-table.h"
@@ -337,6 +338,31 @@ lookup_redirection_data (edge e, enum insert_option insert)
     }
 }
 
+/* Similar to copy_phi_args, except that the PHI arg exists, it just
+   does not have a value associated with it.  */
+
+static void
+copy_phi_arg_into_existing_phi (edge src_e, edge tgt_e)
+{
+  int src_idx = src_e->dest_idx;
+  int tgt_idx = tgt_e->dest_idx;
+
+  /* Iterate over each PHI in e->dest.  */
+  for (gimple_stmt_iterator gsi = gsi_start_phis (src_e->dest),
+                           gsi2 = gsi_start_phis (tgt_e->dest);
+       !gsi_end_p (gsi);
+       gsi_next (&gsi), gsi_next (&gsi2))
+    {
+      gimple src_phi = gsi_stmt (gsi);
+      gimple dest_phi = gsi_stmt (gsi2);
+      tree val = gimple_phi_arg_def (src_phi, src_idx);
+      source_location locus = gimple_phi_arg_location (src_phi, src_idx);
+
+      SET_PHI_ARG_DEF (dest_phi, tgt_idx, val);
+      gimple_phi_arg_set_location (dest_phi, tgt_idx, locus);
+    }
+}
+
 /* For each PHI in BB, copy the argument associated with SRC_E to TGT_E.  */
 
 static void
@@ -418,7 +444,23 @@ create_edge_and_update_destination_phis (struct redirection_data *rd,
   copy_phi_args (e->dest, rd->path->last ()->e, e);
 }
 
-/* Wire up the outgoing edges from the duplicate block and
+/* Look through PATH beginning at START and return TRUE if there are
+   any additional blocks that need to be duplicated.  Otherwise,
+   return FALSE.  */
+static bool
+any_remaining_duplicated_blocks (vec<jump_thread_edge *> *path,
+                                unsigned int start)
+{
+  for (unsigned int i = start + 1; i < path->length (); i++)
+    {
+      if ((*path)[i]->type == EDGE_COPY_SRC_JOINER_BLOCK
+         || (*path)[i]->type == EDGE_COPY_SRC_BLOCK)
+       return true;
+    }
+  return false;
+}
+
+/* Wire up the outgoing edges from the duplicate blocks and
    update any PHIs as needed.  */
 void
 ssa_fix_duplicate_block_edges (struct redirection_data *rd,
@@ -427,37 +469,77 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd,
   edge e = rd->incoming_edges->e;
   vec<jump_thread_edge *> *path = THREAD_PATH (e);
 
-  /* If we were threading through an joiner block, then we want
-     to keep its control statement and redirect an outgoing edge.
-     Else we want to remove the control statement & edges, then create
-     a new outgoing edge.  In both cases we may need to update PHIs.  */
-  if ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK)
-    {
-      edge victim;
-      edge e2;
-
-      /* This updates the PHIs at the destination of the duplicate
-        block.  */
-      update_destination_phis (local_info->bb, rd->dup_blocks[0]);
-
-      /* Find the edge from the duplicate block to the block we're
-        threading through.  That's the edge we want to redirect.  */
-      victim = find_edge (rd->dup_blocks[0], (*path)[1]->e->dest);
-      e2 = redirect_edge_and_branch (victim, path->last ()->e->dest);
-      e2->count = path->last ()->e->count;
-
-      /* If we redirected the edge, then we need to copy PHI arguments
-        at the target.  If the edge already existed (e2 != victim case),
-        then the PHIs in the target already have the correct arguments.  */
-      if (e2 == victim)
-       copy_phi_args (e2->dest, path->last ()->e, e2);
-    }
-  else
-    {
-      remove_ctrl_stmt_and_useless_edges (rd->dup_blocks[0], NULL);
-      create_edge_and_update_destination_phis (rd, rd->dup_blocks[0]);
+  for (unsigned int count = 0, i = 1; i < path->length (); i++)
+    { 
+      /* If we were threading through an joiner block, then we want
+        to keep its control statement and redirect an outgoing edge.
+        Else we want to remove the control statement & edges, then create
+        a new outgoing edge.  In both cases we may need to update PHIs.  */
+      if ((*path)[i]->type == EDGE_COPY_SRC_JOINER_BLOCK)
+       {
+         edge victim;
+         edge e2;
+
+         /* This updates the PHIs at the destination of the duplicate
+            block.  */
+         update_destination_phis (local_info->bb, rd->dup_blocks[count]);
+
+         /* Find the edge from the duplicate block to the block we're
+            threading through.  That's the edge we want to redirect.  */
+         victim = find_edge (rd->dup_blocks[count], (*path)[i]->e->dest);
+
+         /* If there are no remaining blocks on the path to duplicate,
+            then redirect VICTIM to the final destination of the jump
+            threading path.  */
+         if (!any_remaining_duplicated_blocks (path, i))
+           {
+             e2 = redirect_edge_and_branch (victim, path->last ()->e->dest);
+             e2->count = path->last ()->e->count;
+             /* If we redirected the edge, then we need to copy PHI arguments
+                at the target.  If the edge already existed (e2 != victim
+                case), then the PHIs in the target already have the correct
+                arguments.  */
+             if (e2 == victim)
+               copy_phi_args (e2->dest, path->last ()->e, e2);
+           }
+         else
+           {
+             /* Redirect VICTIM to the next duplicated block in the path.  */
+             e2 = redirect_edge_and_branch (victim, rd->dup_blocks[count + 1]);
+
+             /* We need to update the PHIs in the next duplicated block.  We
+                want the new PHI args to have the same value as they had
+                in the source of the next duplicate block.
+
+                Thus, we need to know which edge we traversed into the
+                source of the duplicate.  Furthermore, we may have
+                traversed many edges to reach the source of the duplicate.
+
+                Walk through the path starting at element I until we
+                hit an edge marked with EDGE_COPY_SRC_BLOCK.  We want
+                the edge from the prior element.  */
+             for (unsigned int j = i + 1; j < path->length (); j++)
+               {
+                 if ((*path)[j]->type == EDGE_COPY_SRC_BLOCK)
+                   {
+                     copy_phi_arg_into_existing_phi ((*path)[j - 1]->e, e2);
+                     break;
+                   }
+               }
+           }
+         count++;
+       }
+      else if ((*path)[i]->type == EDGE_COPY_SRC_BLOCK)
+       {
+         remove_ctrl_stmt_and_useless_edges (rd->dup_blocks[count], NULL);
+         create_edge_and_update_destination_phis (rd, rd->dup_blocks[count]);
+         if (count == 1)
+           single_succ_edge (rd->dup_blocks[1])->aux = NULL;
+         count++;
+       }
     }
 }
+
 /* Hash table traversal callback routine to create duplicate blocks.  */
 
 int