Commit 2c2af141 by Jeff Law Committed by Jeff Law

tree-ssa-threadupdate.c (redirection_data): Record two duplicated blocks instead of just one.

	* tree-ssa-threadupdate.c (redirection_data): Record two
	duplicated blocks instead of just one.
	(local_info): Explain why we don't create a template for the
	second duplicated block in a thread path.
	(create_block_for_threading): Accept argument indicating array
	index into redirection_data to store its result.
	(lookup_redirection_data): Initialize both duplicate blocks.
	(ssa_create_duplicates): If a jump threading path needs multiple
	blocks duplicated, then duplicate them.
	(ssa_fix_duplicate_block_edges): Corresponding changes.
	(ssa_fixup_template_block, thread_single_edge):  Likewise.

From-SVN: r204982
parent fc78704b
2013-11-18 Jeff Law <law@redhat.com>
* tree-ssa-threadupdate.c (redirection_data): Record two
duplicated blocks instead of just one.
(local_info): Explain why we don't create a template for the
second duplicated block in a thread path.
(create_block_for_threading): Accept argument indicating array
index into redirection_data to store its result.
(lookup_redirection_data): Initialize both duplicate blocks.
(ssa_create_duplicates): If a jump threading path needs multiple
blocks duplicated, then duplicate them.
(ssa_fix_duplicate_block_edges): Corresponding changes.
(ssa_fixup_template_block, thread_single_edge): Likewise.
2013-11-18 Marek Polacek <polacek@redhat.com> 2013-11-18 Marek Polacek <polacek@redhat.com>
* doc/invoke.texi: Extend -fsanitize=undefined documentation. * doc/invoke.texi: Extend -fsanitize=undefined documentation.
...@@ -112,9 +112,20 @@ struct el ...@@ -112,9 +112,20 @@ struct el
struct redirection_data : typed_free_remove<redirection_data> struct redirection_data : typed_free_remove<redirection_data>
{ {
/* A duplicate of B with the trailing control statement removed and which /* We support wiring up two block duplicates in a jump threading path.
targets a single successor of B. */
basic_block dup_block; One is a normal block copy where we remove the control statement
and wire up its single remaining outgoing edge to the thread path.
The other is a joiner block where we leave the control statement
in place, but wire one of the outgoing edges to a thread path.
In theory we could have multiple block duplicates in a jump
threading path, but I haven't tried that.
The duplicate blocks appear in this array in the same order in
which they appear in the jump thread path. */
basic_block dup_blocks[2];
/* The jump threading path. */ /* The jump threading path. */
vec<jump_thread_edge *> *path; vec<jump_thread_edge *> *path;
...@@ -168,8 +179,11 @@ struct ssa_local_info_t ...@@ -168,8 +179,11 @@ struct ssa_local_info_t
/* The current block we are working on. */ /* The current block we are working on. */
basic_block bb; basic_block bb;
/* A template copy of BB with no outgoing edges or control statement that /* We only create a template block for the first duplicated block in a
we use for creating copies. */ jump threading path as we may need many duplicates of that block.
The second duplicate block in a path is specific to that path. Creating
and sharing a template for that block is considerably more difficult. */
basic_block template_block; basic_block template_block;
/* TRUE if we thread one or more jumps, FALSE otherwise. */ /* TRUE if we thread one or more jumps, FALSE otherwise. */
...@@ -231,24 +245,27 @@ remove_ctrl_stmt_and_useless_edges (basic_block bb, basic_block dest_bb) ...@@ -231,24 +245,27 @@ remove_ctrl_stmt_and_useless_edges (basic_block bb, basic_block dest_bb)
} }
} }
/* Create a duplicate of BB. Record the duplicate block in RD. */ /* Create a duplicate of BB. Record the duplicate block in an array
indexed by COUNT stored in RD. */
static void static void
create_block_for_threading (basic_block bb, struct redirection_data *rd) create_block_for_threading (basic_block bb,
struct redirection_data *rd,
unsigned int count)
{ {
edge_iterator ei; edge_iterator ei;
edge e; edge e;
/* We can use the generic block duplication code and simply remove /* We can use the generic block duplication code and simply remove
the stuff we do not need. */ the stuff we do not need. */
rd->dup_block = duplicate_block (bb, NULL, NULL); rd->dup_blocks[count] = duplicate_block (bb, NULL, NULL);
FOR_EACH_EDGE (e, ei, rd->dup_block->succs) FOR_EACH_EDGE (e, ei, rd->dup_blocks[count]->succs)
e->aux = NULL; e->aux = NULL;
/* Zero out the profile, since the block is unreachable for now. */ /* Zero out the profile, since the block is unreachable for now. */
rd->dup_block->frequency = 0; rd->dup_blocks[count]->frequency = 0;
rd->dup_block->count = 0; rd->dup_blocks[count]->count = 0;
} }
/* Main data structure to hold information for duplicates of BB. */ /* Main data structure to hold information for duplicates of BB. */
...@@ -272,7 +289,8 @@ lookup_redirection_data (edge e, enum insert_option insert) ...@@ -272,7 +289,8 @@ lookup_redirection_data (edge e, enum insert_option insert)
in the table. */ in the table. */
elt = XNEW (struct redirection_data); elt = XNEW (struct redirection_data);
elt->path = path; elt->path = path;
elt->dup_block = NULL; elt->dup_blocks[0] = NULL;
elt->dup_blocks[1] = NULL;
elt->incoming_edges = NULL; elt->incoming_edges = NULL;
slot = redirection_data.find_slot (elt, insert); slot = redirection_data.find_slot (elt, insert);
...@@ -420,11 +438,11 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd, ...@@ -420,11 +438,11 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd,
/* This updates the PHIs at the destination of the duplicate /* This updates the PHIs at the destination of the duplicate
block. */ block. */
update_destination_phis (local_info->bb, rd->dup_block); update_destination_phis (local_info->bb, rd->dup_blocks[0]);
/* Find the edge from the duplicate block to the block we're /* Find the edge from the duplicate block to the block we're
threading through. That's the edge we want to redirect. */ threading through. That's the edge we want to redirect. */
victim = find_edge (rd->dup_block, (*path)[1]->e->dest); victim = find_edge (rd->dup_blocks[0], (*path)[1]->e->dest);
e2 = redirect_edge_and_branch (victim, path->last ()->e->dest); e2 = redirect_edge_and_branch (victim, path->last ()->e->dest);
e2->count = path->last ()->e->count; e2->count = path->last ()->e->count;
...@@ -436,8 +454,8 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd, ...@@ -436,8 +454,8 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd,
} }
else else
{ {
remove_ctrl_stmt_and_useless_edges (rd->dup_block, NULL); remove_ctrl_stmt_and_useless_edges (rd->dup_blocks[0], NULL);
create_edge_and_update_destination_phis (rd, rd->dup_block); create_edge_and_update_destination_phis (rd, rd->dup_blocks[0]);
} }
} }
/* Hash table traversal callback routine to create duplicate blocks. */ /* Hash table traversal callback routine to create duplicate blocks. */
...@@ -448,12 +466,32 @@ ssa_create_duplicates (struct redirection_data **slot, ...@@ -448,12 +466,32 @@ ssa_create_duplicates (struct redirection_data **slot,
{ {
struct redirection_data *rd = *slot; struct redirection_data *rd = *slot;
/* The second duplicated block in a jump threading path is specific
to the path. So it gets stored in RD rather than in LOCAL_DATA.
Each time we're called, we have to look through the path and see
if a second block needs to be duplicated.
Note the search starts with the third edge on the path. The first
edge is the incoming edge, the second edge always has its source
duplicated. Thus we start our search with the third edge. */
vec<jump_thread_edge *> *path = rd->path;
for (unsigned int i = 2; i < path->length (); i++)
{
if ((*path)[i]->type == EDGE_COPY_SRC_BLOCK
|| (*path)[i]->type == EDGE_COPY_SRC_JOINER_BLOCK)
{
create_block_for_threading ((*path)[i]->e->src, rd, 1);
break;
}
}
/* Create a template block if we have not done so already. Otherwise /* Create a template block if we have not done so already. Otherwise
use the template to create a new block. */ use the template to create a new block. */
if (local_info->template_block == NULL) if (local_info->template_block == NULL)
{ {
create_block_for_threading (local_info->bb, rd); create_block_for_threading ((*path)[1]->e->src, rd, 0);
local_info->template_block = rd->dup_block; local_info->template_block = rd->dup_blocks[0];
/* We do not create any outgoing edges for the template. We will /* We do not create any outgoing edges for the template. We will
take care of that in a later traversal. That way we do not take care of that in a later traversal. That way we do not
...@@ -461,7 +499,7 @@ ssa_create_duplicates (struct redirection_data **slot, ...@@ -461,7 +499,7 @@ ssa_create_duplicates (struct redirection_data **slot,
} }
else else
{ {
create_block_for_threading (local_info->template_block, rd); create_block_for_threading (local_info->template_block, rd, 0);
/* Go ahead and wire up outgoing edges and update PHIs for the duplicate /* Go ahead and wire up outgoing edges and update PHIs for the duplicate
block. */ block. */
...@@ -489,7 +527,7 @@ ssa_fixup_template_block (struct redirection_data **slot, ...@@ -489,7 +527,7 @@ ssa_fixup_template_block (struct redirection_data **slot,
to keep its control statement and redirect an outgoing edge. to keep its control statement and redirect an outgoing edge.
Else we want to remove the control statement & edges, then create Else we want to remove the control statement & edges, then create
a new outgoing edge. In both cases we may need to update PHIs. */ a new outgoing edge. In both cases we may need to update PHIs. */
if (rd->dup_block && rd->dup_block == local_info->template_block) if (rd->dup_blocks[0] && rd->dup_blocks[0] == local_info->template_block)
{ {
ssa_fix_duplicate_block_edges (rd, local_info); ssa_fix_duplicate_block_edges (rd, local_info);
return 0; return 0;
...@@ -523,30 +561,30 @@ ssa_redirect_edges (struct redirection_data **slot, ...@@ -523,30 +561,30 @@ ssa_redirect_edges (struct redirection_data **slot,
thread_stats.num_threaded_edges++; thread_stats.num_threaded_edges++;
if (rd->dup_block) if (rd->dup_blocks[0])
{ {
edge e2; edge e2;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Threaded jump %d --> %d to %d\n", fprintf (dump_file, " Threaded jump %d --> %d to %d\n",
e->src->index, e->dest->index, rd->dup_block->index); e->src->index, e->dest->index, rd->dup_blocks[0]->index);
rd->dup_block->count += e->count; rd->dup_blocks[0]->count += e->count;
/* Excessive jump threading may make frequencies large enough so /* Excessive jump threading may make frequencies large enough so
the computation overflows. */ the computation overflows. */
if (rd->dup_block->frequency < BB_FREQ_MAX * 2) if (rd->dup_blocks[0]->frequency < BB_FREQ_MAX * 2)
rd->dup_block->frequency += EDGE_FREQUENCY (e); rd->dup_blocks[0]->frequency += EDGE_FREQUENCY (e);
/* In the case of threading through a joiner block, the outgoing /* In the case of threading through a joiner block, the outgoing
edges from the duplicate block were updated when they were edges from the duplicate block were updated when they were
redirected during ssa_fix_duplicate_block_edges. */ redirected during ssa_fix_duplicate_block_edges. */
if ((*path)[1]->type != EDGE_COPY_SRC_JOINER_BLOCK) if ((*path)[1]->type != EDGE_COPY_SRC_JOINER_BLOCK)
EDGE_SUCC (rd->dup_block, 0)->count += e->count; EDGE_SUCC (rd->dup_blocks[0], 0)->count += e->count;
/* Redirect the incoming edge (possibly to the joiner block) to the /* Redirect the incoming edge (possibly to the joiner block) to the
appropriate duplicate block. */ appropriate duplicate block. */
e2 = redirect_edge_and_branch (e, rd->dup_block); e2 = redirect_edge_and_branch (e, rd->dup_blocks[0]);
gcc_assert (e == e2); gcc_assert (e == e2);
flush_pending_stmts (e2); flush_pending_stmts (e2);
} }
...@@ -827,21 +865,21 @@ thread_single_edge (edge e) ...@@ -827,21 +865,21 @@ thread_single_edge (edge e)
npath->safe_push (x); npath->safe_push (x);
rd.path = npath; rd.path = npath;
create_block_for_threading (bb, &rd); create_block_for_threading (bb, &rd, 0);
remove_ctrl_stmt_and_useless_edges (rd.dup_block, NULL); remove_ctrl_stmt_and_useless_edges (rd.dup_blocks[0], NULL);
create_edge_and_update_destination_phis (&rd, rd.dup_block); create_edge_and_update_destination_phis (&rd, rd.dup_blocks[0]);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Threaded jump %d --> %d to %d\n", fprintf (dump_file, " Threaded jump %d --> %d to %d\n",
e->src->index, e->dest->index, rd.dup_block->index); e->src->index, e->dest->index, rd.dup_blocks[0]->index);
rd.dup_block->count = e->count; rd.dup_blocks[0]->count = e->count;
rd.dup_block->frequency = EDGE_FREQUENCY (e); rd.dup_blocks[0]->frequency = EDGE_FREQUENCY (e);
single_succ_edge (rd.dup_block)->count = e->count; single_succ_edge (rd.dup_blocks[0])->count = e->count;
redirect_edge_and_branch (e, rd.dup_block); redirect_edge_and_branch (e, rd.dup_blocks[0]);
flush_pending_stmts (e); flush_pending_stmts (e);
return rd.dup_block; return rd.dup_blocks[0];
} }
/* Callback for dfs_enumerate_from. Returns true if BB is different /* Callback for dfs_enumerate_from. Returns true if BB is different
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment