Commit 770da076 by Jeff Law Committed by Jeff Law

tree-ssa-threadedge.c (thread_around_empty_blocks): Renamed from thread_around_empty_block.

       * tree-ssa-threadedge.c (thread_around_empty_blocks): Renamed
       from thread_around_empty_block.  Record threading path into PATH.
       Recurse if threading through the initial block is successful.
       (thread_across_edge): Corresponding changes to slightly simplify.

From-SVN: r202296
parent fe6f68e2
2013-09-05 Jeff Law <law@redhat.com>
* tree-ssa-threadedge.c (thread_around_empty_blocks): Renamed
from thread_around_empty_block. Record threading path into PATH.
Recurse if threading through the initial block is successful.
(thread_across_edge): Corresponding changes to slightly simplify.
2013-09-05 James Greenhalgh <james.greenhalgh@arm.com> 2013-09-05 James Greenhalgh <james.greenhalgh@arm.com>
* config/aarch64/aarch64.md * config/aarch64/aarch64.md
......
...@@ -738,46 +738,68 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src) ...@@ -738,46 +738,68 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
fewvars.release (); fewvars.release ();
} }
/* TAKEN_EDGE represents the an edge taken as a result of jump threading. /* See if TAKEN_EDGE->dest is a threadable block with no side effecs (ie, it
See if we can thread around TAKEN_EDGE->dest as well. If so, return need not be duplicated as part of the CFG/SSA updating process).
the edge out of TAKEN_EDGE->dest that we can statically compute will be
traversed. If it is threadable, add it to PATH and VISITED and recurse, ultimately
returning TRUE from the toplevel call. Otherwise do nothing and
We are much more restrictive as to the contents of TAKEN_EDGE->dest return false.
as the path isolation code in tree-ssa-threadupdate.c isn't prepared
to handle copying intermediate blocks on a threaded path. DUMMY_COND, HANDLE_DOMINATING_ASSERTS and SIMPLIFY are used to
try and simplify the condition at the end of TAKEN_EDGE->dest. */
Long term a more consistent and structured approach to path isolation static bool
would be a huge help. */ thread_around_empty_blocks (edge taken_edge,
static edge
thread_around_empty_block (edge taken_edge,
gimple dummy_cond, gimple dummy_cond,
bool handle_dominating_asserts, bool handle_dominating_asserts,
tree (*simplify) (gimple, gimple), tree (*simplify) (gimple, gimple),
bitmap visited) bitmap visited,
vec<edge> *path)
{ {
basic_block bb = taken_edge->dest; basic_block bb = taken_edge->dest;
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
gimple stmt; gimple stmt;
tree cond; tree cond;
/* This block can have no PHI nodes. This is overly conservative. */ /* The key property of these blocks is that they need not be duplicated
when threading. Thus they can not have visible side effects such
as PHI nodes. */
if (!gsi_end_p (gsi_start_phis (bb))) if (!gsi_end_p (gsi_start_phis (bb)))
return NULL; return NULL;
/* Skip over DEBUG statements at the start of the block. */ /* Skip over DEBUG statements at the start of the block. */
gsi = gsi_start_nondebug_bb (bb); gsi = gsi_start_nondebug_bb (bb);
/* If the block has no statements, but does have a single successor, then
it's just a forwarding block and we can thread through it trivially. */
if (gsi_end_p (gsi)) if (gsi_end_p (gsi))
return NULL; {
if (single_succ_p (bb))
{
taken_edge = single_succ_edge (bb);
if ((taken_edge->flags & EDGE_DFS_BACK) == 0
&& !bitmap_bit_p (visited, taken_edge->dest->index))
{
bitmap_set_bit (visited, taken_edge->dest->index);
path->safe_push (taken_edge);
thread_around_empty_blocks (taken_edge,
dummy_cond,
handle_dominating_asserts,
simplify,
visited,
path);
return true;
}
}
return false;
}
/* This block can have no statements other than its control altering /* The only real statements this block can have are a control
statement. This is overly conservative. */ flow altering statement. Anything else stops the thread. */
stmt = gsi_stmt (gsi); stmt = gsi_stmt (gsi);
if (gimple_code (stmt) != GIMPLE_COND if (gimple_code (stmt) != GIMPLE_COND
&& gimple_code (stmt) != GIMPLE_GOTO && gimple_code (stmt) != GIMPLE_GOTO
&& gimple_code (stmt) != GIMPLE_SWITCH) && gimple_code (stmt) != GIMPLE_SWITCH)
return NULL; return false;
/* Extract and simplify the condition. */ /* Extract and simplify the condition. */
cond = simplify_control_stmt_condition (taken_edge, stmt, dummy_cond, cond = simplify_control_stmt_condition (taken_edge, stmt, dummy_cond,
...@@ -788,15 +810,22 @@ thread_around_empty_block (edge taken_edge, ...@@ -788,15 +810,22 @@ thread_around_empty_block (edge taken_edge,
path. */ path. */
if (cond && is_gimple_min_invariant (cond)) if (cond && is_gimple_min_invariant (cond))
{ {
edge taken_edge = find_taken_edge (bb, cond); taken_edge = find_taken_edge (bb, cond);
if (bitmap_bit_p (visited, taken_edge->dest->index)) if (bitmap_bit_p (visited, taken_edge->dest->index))
return NULL; return false;
bitmap_set_bit (visited, taken_edge->dest->index); bitmap_set_bit (visited, taken_edge->dest->index);
return taken_edge; path->safe_push (taken_edge);
thread_around_empty_blocks (taken_edge,
dummy_cond,
handle_dominating_asserts,
simplify,
visited,
path);
return true;
} }
return NULL; return false;
} }
/* E1 and E2 are edges into the same basic block. Return TRUE if the /* E1 and E2 are edges into the same basic block. Return TRUE if the
...@@ -896,51 +925,40 @@ thread_across_edge (gimple dummy_cond, ...@@ -896,51 +925,40 @@ thread_across_edge (gimple dummy_cond,
edge taken_edge = find_taken_edge (e->dest, cond); edge taken_edge = find_taken_edge (e->dest, cond);
basic_block dest = (taken_edge ? taken_edge->dest : NULL); basic_block dest = (taken_edge ? taken_edge->dest : NULL);
bitmap visited; bitmap visited;
edge e2;
if (dest == e->dest) /* DEST could be NULL for a computed jump to an absolute
address. */
if (dest == NULL || dest == e->dest)
goto fail; goto fail;
vec<edge> path = vNULL; vec<edge> path = vNULL;
path.safe_push (e); path.safe_push (e);
path.safe_push (taken_edge); path.safe_push (taken_edge);
/* DEST could be null for a computed jump to an absolute /* See if we can thread through DEST as well, this helps capture
address. If DEST is not null, then see if we can thread secondary effects of threading without having to re-run DOM or
through it as well, this helps capture secondary effects VRP. */
of threading without having to re-run DOM or VRP. */ if ((e->flags & EDGE_DFS_BACK) == 0
if (dest || ! cond_arg_set_in_bb (taken_edge, e->dest))
&& ((e->flags & EDGE_DFS_BACK) == 0
|| ! cond_arg_set_in_bb (taken_edge, e->dest)))
{ {
/* We don't want to thread back to a block we have already /* We don't want to thread back to a block we have already
visited. This may be overly conservative. */ visited. This may be overly conservative. */
visited = BITMAP_ALLOC (NULL); visited = BITMAP_ALLOC (NULL);
bitmap_set_bit (visited, dest->index); bitmap_set_bit (visited, dest->index);
bitmap_set_bit (visited, e->dest->index); bitmap_set_bit (visited, e->dest->index);
do thread_around_empty_blocks (taken_edge,
{
e2 = thread_around_empty_block (taken_edge,
dummy_cond, dummy_cond,
handle_dominating_asserts, handle_dominating_asserts,
simplify, simplify,
visited); visited,
if (e2) &path);
{
taken_edge = e2;
path.safe_push (e2);
}
}
while (e2);
BITMAP_FREE (visited); BITMAP_FREE (visited);
} }
remove_temporary_equivalences (stack); remove_temporary_equivalences (stack);
if (taken_edge) propagate_threaded_block_debug_into (path[path.length () - 1]->dest,
{ e->dest);
propagate_threaded_block_debug_into (taken_edge->dest, e->dest);
register_jump_thread (path, false); register_jump_thread (path, false);
}
path.release (); path.release ();
return; return;
} }
...@@ -958,7 +976,7 @@ thread_across_edge (gimple dummy_cond, ...@@ -958,7 +976,7 @@ thread_across_edge (gimple dummy_cond,
This is a stopgap until we have a more structured approach to path This is a stopgap until we have a more structured approach to path
isolation. */ isolation. */
{ {
edge e2, e3, taken_edge; edge taken_edge;
edge_iterator ei; edge_iterator ei;
bool found = false; bool found = false;
bitmap visited = BITMAP_ALLOC (NULL); bitmap visited = BITMAP_ALLOC (NULL);
...@@ -976,28 +994,14 @@ thread_across_edge (gimple dummy_cond, ...@@ -976,28 +994,14 @@ thread_across_edge (gimple dummy_cond,
of E->dest. */ of E->dest. */
path.safe_push (e); path.safe_push (e);
path.safe_push (taken_edge); path.safe_push (taken_edge);
found = false;
e3 = taken_edge;
do
{
if ((e->flags & EDGE_DFS_BACK) == 0 if ((e->flags & EDGE_DFS_BACK) == 0
|| ! cond_arg_set_in_bb (e3, e->dest)) || ! cond_arg_set_in_bb (path[path.length () - 1], e->dest))
e2 = thread_around_empty_block (e3, found = thread_around_empty_blocks (taken_edge,
dummy_cond, dummy_cond,
handle_dominating_asserts, handle_dominating_asserts,
simplify, simplify,
visited); visited,
else &path);
e2 = NULL;
if (e2)
{
path.safe_push (e2);
e3 = e2;
found = true;
}
}
while (e2);
/* If we were able to thread through a successor of E->dest, then /* If we were able to thread through a successor of E->dest, then
record the jump threading opportunity. */ record the jump threading opportunity. */
...@@ -1008,10 +1012,10 @@ thread_across_edge (gimple dummy_cond, ...@@ -1008,10 +1012,10 @@ thread_across_edge (gimple dummy_cond,
(E2->src) to the final target (E3->dest), then make sure that (E2->src) to the final target (E3->dest), then make sure that
the PHI args associated with the edges E2 and E3 are the the PHI args associated with the edges E2 and E3 are the
same. */ same. */
tmp = find_edge (taken_edge->src, e3->dest); tmp = find_edge (taken_edge->src, path[path.length () - 1]->dest);
if (!tmp || phi_args_equal_on_edges (tmp, e3)) if (!tmp || phi_args_equal_on_edges (tmp, path[path.length () - 1]))
{ {
propagate_threaded_block_debug_into (e3->dest, propagate_threaded_block_debug_into (path[path.length () - 1]->dest,
taken_edge->dest); taken_edge->dest);
register_jump_thread (path, true); register_jump_thread (path, true);
} }
......
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