aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-threadedge.c
diff options
context:
space:
mode:
authorJeff Law <law@redhat.com>2011-03-28 12:33:42 -0600
committerJeff Law <law@gcc.gnu.org>2011-03-28 12:33:42 -0600
commit520af9ec9a673351b046e06e91d8f66fa70341d2 (patch)
tree6f6e281ff34d399c1d3ec13acccdbbca92243795 /gcc/tree-ssa-threadedge.c
parent80ec23acbd7c94b82afc2e53506d5bfa2a049fe8 (diff)
downloadgcc-520af9ec9a673351b046e06e91d8f66fa70341d2.zip
gcc-520af9ec9a673351b046e06e91d8f66fa70341d2.tar.gz
gcc-520af9ec9a673351b046e06e91d8f66fa70341d2.tar.bz2
tree-ssa-threadupdate.c (redirect_edges): Call create_edge_and_update_destination_phis as needed.
* tree-ssa-threadupdate.c (redirect_edges): Call create_edge_and_update_destination_phis as needed. (create_edge_and_update_destination_phis): Accept new BB argument. All callers updated. (thread_block): Do not update the profile when threading around intermediate blocks. (thread_single_edge): Likewise. (determine_bb_domination_status): If BB is not a successor of the loop header, return NONDOMINATING. (register_jump_thread): Note when we register a jump thread around an intermediate block. * tree-ssa-threadedge.c (thread_around_empty_block): New function. (thread_across_edge): Use it. * gcc.dg/tree-ssa/ssa-dom-thread-3.c: New test. From-SVN: r171622
Diffstat (limited to 'gcc/tree-ssa-threadedge.c')
-rw-r--r--gcc/tree-ssa-threadedge.c100
1 files changed, 99 insertions, 1 deletions
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 020f6e7..1fee9bf 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -583,6 +583,76 @@ simplify_control_stmt_condition (edge e,
return cached_lhs;
}
+/* TAKEN_EDGE represents the an edge taken as a result of jump threading.
+ See if we can thread around TAKEN_EDGE->dest as well. If so, return
+ the edge out of TAKEN_EDGE->dest that we can statically compute will be
+ traversed.
+
+ We are much more restrictive as to the contents of TAKEN_EDGE->dest
+ as the path isolation code in tree-ssa-threadupdate.c isn't prepared
+ to handle copying intermediate blocks on a threaded path.
+
+ Long term a more consistent and structured approach to path isolation
+ would be a huge help. */
+static edge
+thread_around_empty_block (edge taken_edge,
+ gimple dummy_cond,
+ bool handle_dominating_asserts,
+ tree (*simplify) (gimple, gimple),
+ bitmap visited)
+{
+ basic_block bb = taken_edge->dest;
+ gimple_stmt_iterator gsi;
+ gimple stmt;
+ tree cond;
+
+ /* This block must have a single predecessor (E->dest). */
+ if (!single_pred_p (bb))
+ return NULL;
+
+ /* This block must have more than one successor. */
+ if (single_succ_p (bb))
+ return NULL;
+
+ /* This block can have no PHI nodes. This is overly conservative. */
+ if (!gsi_end_p (gsi_start_phis (bb)))
+ return NULL;
+
+ /* Skip over DEBUG statements at the start of the block. */
+ gsi = gsi_start_nondebug_bb (bb);
+
+ if (gsi_end_p (gsi))
+ return NULL;
+
+ /* This block can have no statements other than its control altering
+ statement. This is overly conservative. */
+ stmt = gsi_stmt (gsi);
+ if (gimple_code (stmt) != GIMPLE_COND
+ && gimple_code (stmt) != GIMPLE_GOTO
+ && gimple_code (stmt) != GIMPLE_SWITCH)
+ return NULL;
+
+ /* Extract and simplify the condition. */
+ cond = simplify_control_stmt_condition (taken_edge, stmt, dummy_cond,
+ simplify, handle_dominating_asserts);
+
+ /* If the condition can be statically computed and we have not already
+ visited the destination edge, then add the taken edge to our thread
+ path. */
+ if (cond && is_gimple_min_invariant (cond))
+ {
+ edge taken_edge = find_taken_edge (bb, cond);
+
+ if (bitmap_bit_p (visited, taken_edge->dest->index))
+ return NULL;
+ bitmap_set_bit (visited, taken_edge->dest->index);
+ return taken_edge;
+ }
+
+ return NULL;
+}
+
+
/* We are exiting E->src, see if E->dest ends with a conditional
jump which has a known value when reached via E.
@@ -661,16 +731,44 @@ thread_across_edge (gimple dummy_cond,
tree cond;
/* Extract and simplify the condition. */
- cond = simplify_control_stmt_condition (e, stmt, dummy_cond, simplify, handle_dominating_asserts);
+ cond = simplify_control_stmt_condition (e, stmt, dummy_cond, simplify,
+ handle_dominating_asserts);
if (cond && is_gimple_min_invariant (cond))
{
edge taken_edge = find_taken_edge (e->dest, cond);
basic_block dest = (taken_edge ? taken_edge->dest : NULL);
+ bitmap visited;
+ edge e2;
if (dest == e->dest)
goto fail;
+ /* DEST could be null for a computed jump to an absolute
+ address. If DEST is not null, then see if we can thread
+ through it as well, this helps capture secondary effects
+ of threading without having to re-run DOM or VRP. */
+ if (dest)
+ {
+ /* We don't want to thread back to a block we have already
+ visited. This may be overly conservative. */
+ visited = BITMAP_ALLOC (NULL);
+ bitmap_set_bit (visited, dest->index);
+ bitmap_set_bit (visited, e->dest->index);
+ do
+ {
+ e2 = thread_around_empty_block (taken_edge,
+ dummy_cond,
+ handle_dominating_asserts,
+ simplify,
+ visited);
+ if (e2)
+ taken_edge = e2;
+ }
+ while (e2);
+ BITMAP_FREE (visited);
+ }
+
remove_temporary_equivalences (stack);
register_jump_thread (e, taken_edge);
}