aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-threadupdate.c
diff options
context:
space:
mode:
authorJeff Law <law@redhat.com>2011-06-16 21:52:00 +0000
committerJeff Law <law@redhat.com>2011-06-16 21:52:00 +0000
commit27d48a8e7d91a719bb62eef44c258f6e05bed992 (patch)
tree3d01a6665a2ef3a33f6ed1eb847b76b1948a165d /gcc/tree-ssa-threadupdate.c
parent12e92eff7742500432a6a9aa6063c02efb074d91 (diff)
* tree-ssa-threadupdate.c (struct redirection_data): New field
intermediate_edge. (THREAD_TARGET2): Define. (redirection_data_eq): Also check that the intermediate edge is equal. (lookup_redirection_data): Drop useless argument. Extract the outgoing_edge and intermediate edge from E. Callers updated. (copy_phi_args, update_destination_phis): New functions. (fix_duplicate_block_edges): Likewise. (create_edge_and_update_destination_phis): Duplicate all the edges hung off e->aux. Use copy_phi_args. (create_duplicates): Use fix_duplicate_block_edges. (fixup_template_block): Likewise. (redirect_edges): If necessary, redirect the joiner block's incoming edge to the duplicate of the joiner block. (thread_block): Don't muck up loops when threading through a joiner block. (thread_through_loop_header): Handle threading through a joiner block. (mark_threaded_blocks, register_jump_thread): Likewise. * tree-flow.h (register_jump_thread): Add new argument. Callers updated. * tree-ssa-threadedge.c (phi_args_equal_on_edges): New function. (thread_across_edge): Handle threading through a joiner block. * gcc.dg/builtin-object-size-1.c: Update to handle changes from improved jump threading. * gcc.dg/builtin-object-size-2.c: Likewise. * gcc.dg/tree-ssa/20030728-1.c: Likewise. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@175114 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-threadupdate.c')
-rw-r--r--gcc/tree-ssa-threadupdate.c151
1 files changed, 121 insertions, 30 deletions
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
index c6e34051c9c..e0335dc8c10 100644
--- a/gcc/tree-ssa-threadupdate.c
+++ b/gcc/tree-ssa-threadupdate.c
@@ -1,6 +1,6 @@
/* Thread edges through blocks and update the control flow and SSA graphs.
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Free Software Foundation,
- Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 201
+ Free Software Foundation, Inc.
This file is part of GCC.
@@ -121,6 +121,8 @@ struct redirection_data
its single successor. */
edge outgoing_edge;
+ edge intermediate_edge;
+
/* A list of incoming edges which we want to thread to
OUTGOING_EDGE->dest. */
struct el *incoming_edges;
@@ -153,6 +155,7 @@ static VEC(edge,heap) *threaded_edges;
threading is attached to the AUX field for the incoming edge. Use these
macros to access the underlying structure attached to the AUX field. */
#define THREAD_TARGET(E) ((edge *)(E)->aux)[0]
+#define THREAD_TARGET2(E) ((edge *)(E)->aux)[1]
/* Jump threading statistics. */
@@ -231,8 +234,10 @@ redirection_data_eq (const void *p1, const void *p2)
{
edge e1 = ((const struct redirection_data *)p1)->outgoing_edge;
edge e2 = ((const struct redirection_data *)p2)->outgoing_edge;
+ edge e3 = ((const struct redirection_data *)p1)->intermediate_edge;
+ edge e4 = ((const struct redirection_data *)p2)->intermediate_edge;
- return e1 == e2;
+ return e1 == e2 && e3 == e4;
}
/* Given an outgoing edge E lookup and return its entry in our hash table.
@@ -242,7 +247,7 @@ redirection_data_eq (const void *p1, const void *p2)
edges associated with E in the hash table. */
static struct redirection_data *
-lookup_redirection_data (edge e, edge incoming_edge, enum insert_option insert)
+lookup_redirection_data (edge e, enum insert_option insert)
{
void **slot;
struct redirection_data *elt;
@@ -250,7 +255,9 @@ lookup_redirection_data (edge e, edge incoming_edge, enum insert_option insert)
/* Build a hash table element so we can see if E is already
in the table. */
elt = XNEW (struct redirection_data);
- elt->outgoing_edge = e;
+ elt->intermediate_edge = THREAD_TARGET2 (e) ? THREAD_TARGET (e) : NULL;
+ elt->outgoing_edge = THREAD_TARGET2 (e) ? THREAD_TARGET2 (e)
+ : THREAD_TARGET (e);
elt->dup_block = NULL;
elt->incoming_edges = NULL;
@@ -270,7 +277,7 @@ lookup_redirection_data (edge e, edge incoming_edge, enum insert_option insert)
{
*slot = (void *)elt;
elt->incoming_edges = XNEW (struct el);
- elt->incoming_edges->e = incoming_edge;
+ elt->incoming_edges->e = e;
elt->incoming_edges->next = NULL;
return elt;
}
@@ -290,7 +297,7 @@ lookup_redirection_data (edge e, edge incoming_edge, enum insert_option insert)
{
struct el *el = XNEW (struct el);
el->next = elt->incoming_edges;
- el->e = incoming_edge;
+ el->e = e;
elt->incoming_edges = el;
}
@@ -298,6 +305,41 @@ lookup_redirection_data (edge e, edge incoming_edge, enum insert_option insert)
}
}
+/* For each PHI in BB, copy the argument associated with SRC_E to TGT_E. */
+
+static void
+copy_phi_args (basic_block bb, edge src_e, edge tgt_e)
+{
+ gimple_stmt_iterator gsi;
+ int src_indx = src_e->dest_idx;
+
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple phi = gsi_stmt (gsi);
+ source_location locus = gimple_phi_arg_location (phi, src_indx);
+ add_phi_arg (phi, gimple_phi_arg_def (phi, src_indx), tgt_e, locus);
+ }
+}
+
+/* We have recently made a copy of ORIG_BB, including its outgoing
+ edges. The copy is NEW_BB. Every PHI node in every direct successor of
+ ORIG_BB has a new argument associated with edge from NEW_BB to the
+ successor. Initialize the PHI argument so that it is equal to the PHI
+ argument associated with the edge from ORIG_BB to the successor. */
+
+static void
+update_destination_phis (basic_block orig_bb, basic_block new_bb)
+{
+ edge_iterator ei;
+ edge e;
+
+ FOR_EACH_EDGE (e, ei, orig_bb->succs)
+ {
+ edge e2 = find_edge (new_bb, e->dest);
+ copy_phi_args (e->dest, e, e2);
+ }
+}
+
/* Given a duplicate block and its single destination (both stored
in RD). Create an edge between the duplicate and its single
destination.
@@ -310,7 +352,6 @@ create_edge_and_update_destination_phis (struct redirection_data *rd,
basic_block bb)
{
edge e = make_edge (bb, rd->outgoing_edge->dest, EDGE_FALLTHRU);
- gimple_stmt_iterator gsi;
rescan_loop_exit (e, true, false);
e->probability = REG_BR_PROB_BASE;
@@ -318,8 +359,9 @@ create_edge_and_update_destination_phis (struct redirection_data *rd,
if (rd->outgoing_edge->aux)
{
- e->aux = (edge *) XNEWVEC (edge, 1);
+ e->aux = (edge *) XNEWVEC (edge, 2);
THREAD_TARGET(e) = THREAD_TARGET (rd->outgoing_edge);
+ THREAD_TARGET2(e) = THREAD_TARGET2 (rd->outgoing_edge);
}
else
{
@@ -330,17 +372,43 @@ create_edge_and_update_destination_phis (struct redirection_data *rd,
from the duplicate block, then we will need to add a new argument
to them. The argument should have the same value as the argument
associated with the outgoing edge stored in RD. */
- for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
+ copy_phi_args (e->dest, rd->outgoing_edge, e);
+}
+
+/* Wire up the outgoing edges from the duplicate block and
+ update any PHIs as needed. */
+static void
+fix_duplicate_block_edges (struct redirection_data *rd,
+ struct local_info *local_info)
+{
+ /* 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 (THREAD_TARGET2 (rd->incoming_edges->e) == rd->outgoing_edge)
{
- gimple phi = gsi_stmt (gsi);
- source_location locus;
- int indx = rd->outgoing_edge->dest_idx;
+ edge victim;
+ edge e2;
+ edge e = rd->incoming_edges->e;
+
+ /* This updates the PHIs at the destination of the duplicate
+ block. */
+ update_destination_phis (local_info->bb, rd->dup_block);
- locus = gimple_phi_arg_location (phi, indx);
- add_phi_arg (phi, gimple_phi_arg_def (phi, indx), e, locus);
+ /* 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_block, THREAD_TARGET (e)->dest);
+ e2 = redirect_edge_and_branch (victim, THREAD_TARGET2 (e)->dest);
+
+ /* This updates the PHI at the target of the threaded edge. */
+ copy_phi_args (e2->dest, THREAD_TARGET2 (e), e2);
+ }
+ else
+ {
+ remove_ctrl_stmt_and_useless_edges (rd->dup_block, NULL);
+ create_edge_and_update_destination_phis (rd, rd->dup_block);
}
}
-
/* Hash table traversal callback routine to create duplicate blocks. */
static int
@@ -365,9 +433,8 @@ create_duplicates (void **slot, void *data)
create_block_for_threading (local_info->template_block, rd);
/* Go ahead and wire up outgoing edges and update PHIs for the duplicate
- block. */
- remove_ctrl_stmt_and_useless_edges (rd->dup_block, NULL);
- create_edge_and_update_destination_phis (rd, rd->dup_block);
+ block. */
+ fix_duplicate_block_edges (rd, local_info);
}
/* Keep walking the hash table. */
@@ -384,12 +451,16 @@ fixup_template_block (void **slot, void *data)
struct redirection_data *rd = (struct redirection_data *) *slot;
struct local_info *local_info = (struct local_info *)data;
- /* If this is the template block, then create its outgoing edges
- and halt the hash table traversal. */
+ /* If this is the template block halt the traversal after updating
+ it appropriately.
+
+ 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 (rd->dup_block && rd->dup_block == local_info->template_block)
{
- remove_ctrl_stmt_and_useless_edges (rd->dup_block, NULL);
- create_edge_and_update_destination_phis (rd, rd->dup_block);
+ fix_duplicate_block_edges (rd, local_info);
return 0;
}
@@ -419,8 +490,18 @@ redirect_edges (void **slot, void *data)
free (el);
thread_stats.num_threaded_edges++;
+ /* If we are threading through a joiner block, then we have to
+ find the edge we want to redirect and update some PHI nodes. */
+ if (THREAD_TARGET2 (e))
+ {
+ edge e2;
- if (rd->dup_block)
+ /* We want to redirect the incoming edge to the joiner block (E)
+ to instead reach the duplicate of the joiner block. */
+ e2 = redirect_edge_and_branch (e, rd->dup_block);
+ flush_pending_stmts (e2);
+ }
+ else if (rd->dup_block)
{
edge e2;
@@ -546,14 +627,18 @@ thread_block (basic_block bb, bool noloop_only)
if (e->aux == NULL)
continue;
- e2 = THREAD_TARGET (e);
+ if (THREAD_TARGET2 (e))
+ e2 = THREAD_TARGET2 (e);
+ else
+ e2 = THREAD_TARGET (e);
if (!e2
/* If NOLOOP_ONLY is true, we only allow threading through the
header of a loop to exit edges. */
|| (noloop_only
&& bb == bb->loop_father->header
- && (!loop_exit_edge_p (bb->loop_father, e2))))
+ && (!loop_exit_edge_p (bb->loop_father, e2)
+ || THREAD_TARGET2 (e))))
continue;
if (e->dest == e2->src)
@@ -562,7 +647,7 @@ thread_block (basic_block bb, bool noloop_only)
/* Insert the outgoing edge into the hash table if it is not
already in the hash table. */
- lookup_redirection_data (e2, e, INSERT);
+ lookup_redirection_data (e, INSERT);
}
/* We do not update dominance info. */
@@ -817,6 +902,8 @@ thread_through_loop_header (struct loop *loop, bool may_peel_loop_headers)
if (latch->aux)
{
+ if (THREAD_TARGET2 (latch))
+ goto fail;
tgt_edge = THREAD_TARGET (latch);
tgt_bb = tgt_edge->dest;
}
@@ -840,6 +927,8 @@ thread_through_loop_header (struct loop *loop, bool may_peel_loop_headers)
goto fail;
}
+ if (THREAD_TARGET2 (e))
+ goto fail;
tgt_edge = THREAD_TARGET (e);
atgt_bb = tgt_edge->dest;
if (!tgt_bb)
@@ -967,13 +1056,14 @@ mark_threaded_blocks (bitmap threaded_blocks)
edge e;
edge_iterator ei;
- for (i = 0; i < VEC_length (edge, threaded_edges); i += 2)
+ for (i = 0; i < VEC_length (edge, threaded_edges); i += 3)
{
edge e = VEC_index (edge, threaded_edges, i);
- edge *x = (edge *) XNEWVEC (edge, 1);
+ edge *x = (edge *) XNEWVEC (edge, 2);
e->aux = x;
THREAD_TARGET (e) = VEC_index (edge, threaded_edges, i + 1);
+ THREAD_TARGET2 (e) = VEC_index (edge, threaded_edges, i + 2);
bitmap_set_bit (tmp, e->dest->index);
}
@@ -1085,7 +1175,7 @@ thread_through_all_blocks (bool may_peel_loop_headers)
after fixing the SSA graph. */
void
-register_jump_thread (edge e, edge e2)
+register_jump_thread (edge e, edge e2, edge e3)
{
/* This can occur if we're jumping to a constant address or
or something similar. Just get out now. */
@@ -1102,4 +1192,5 @@ register_jump_thread (edge e, edge e2)
VEC_safe_push (edge, heap, threaded_edges, e);
VEC_safe_push (edge, heap, threaded_edges, e2);
+ VEC_safe_push (edge, heap, threaded_edges, e3);
}