aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-threadedge.c
diff options
context:
space:
mode:
authorJeff Law <law@redhat.com>2017-03-16 19:21:33 +0000
committerJeff Law <law@redhat.com>2017-03-16 19:21:33 +0000
commita765e977a18f3572f8019756cac9f048662098fe (patch)
tree2015d481070a9147dbdeef1dd1ffd15cc2a515b3 /gcc/tree-ssa-threadedge.c
parentb4a928dd8b7ebc0e0876f60f03eb8dd7a0ab8b76 (diff)
PR tree-optimization/71437
* tree-ssa-dom.c (dom_opt_dom_walker): Remove thread_across_edge member function. Implementation moved into after_dom_children member function and into the threader's thread_outgoing_edges function. (dom_opt_dom_walker::after_dom_children): Simplify by moving some code into new thread_outgoing_edges. * tree-ssa-threadedge.c (thread_across_edge): Make static and simplify definition. Simplify marker handling (do it here). Assume we always have the available expression and the const/copies tables. (thread_outgoing_edges): New function extracted from tree-ssa-dom.c and tree-vrp.c * tree-ssa-threadedge.h (thread_outgoing_edges): Declare. * tree-vrp.c (equiv_stack): No longer file scoped. (vrp_dom_walker): New class. (vrp_dom_walker::before_dom_children): New member function. (vrp_dom_walker::after_dom_children): Likewise. (identify_jump_threads): Setup domwalker. Use it rather than walking edges in a random order by hand. Simplify setup/finalization. (finalize_jump_threads): Remove. (vrp_finalize): Do not call identify_jump_threads here. (execute_vrp): Do it here instead and call thread_through_all_blocks here too. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@246208 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-threadedge.c')
-rw-r--r--gcc/tree-ssa-threadedge.c77
1 files changed, 70 insertions, 7 deletions
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 7f70b40fd0c..536c4717b72 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -1100,16 +1100,18 @@ thread_through_normal_block (edge e,
SIMPLIFY is a pass-specific function used to simplify statements. */
-void
+static void
thread_across_edge (gcond *dummy_cond,
edge e,
class const_and_copies *const_and_copies,
class avail_exprs_stack *avail_exprs_stack,
- tree (*simplify) (gimple *, gimple *,
- class avail_exprs_stack *, basic_block))
+ pfn_simplify simplify)
{
bitmap visited = BITMAP_ALLOC (NULL);
+ const_and_copies->push_marker ();
+ avail_exprs_stack->push_marker ();
+
stmt_count = 0;
vec<jump_thread_edge *> *path = new vec<jump_thread_edge *> ();
@@ -1132,6 +1134,7 @@ thread_across_edge (gcond *dummy_cond,
propagate_threaded_block_debug_into (path->last ()->e->dest,
e->dest);
const_and_copies->pop_to_marker ();
+ avail_exprs_stack->pop_to_marker ();
BITMAP_FREE (visited);
register_jump_thread (path);
return;
@@ -1156,6 +1159,7 @@ thread_across_edge (gcond *dummy_cond,
{
BITMAP_FREE (visited);
const_and_copies->pop_to_marker ();
+ avail_exprs_stack->pop_to_marker ();
return;
}
}
@@ -1182,6 +1186,7 @@ thread_across_edge (gcond *dummy_cond,
if (taken_edge->flags & EDGE_ABNORMAL)
{
const_and_copies->pop_to_marker ();
+ avail_exprs_stack->pop_to_marker ();
BITMAP_FREE (visited);
return;
}
@@ -1196,8 +1201,7 @@ thread_across_edge (gcond *dummy_cond,
/* Push a fresh marker so we can unwind the equivalences created
for each of E->dest's successors. */
const_and_copies->push_marker ();
- if (avail_exprs_stack)
- avail_exprs_stack->push_marker ();
+ avail_exprs_stack->push_marker ();
/* Avoid threading to any block we have already visited. */
bitmap_clear (visited);
@@ -1240,12 +1244,71 @@ thread_across_edge (gcond *dummy_cond,
delete_jump_thread_path (path);
/* And unwind the equivalence table. */
- if (avail_exprs_stack)
- avail_exprs_stack->pop_to_marker ();
+ avail_exprs_stack->pop_to_marker ();
const_and_copies->pop_to_marker ();
}
BITMAP_FREE (visited);
}
const_and_copies->pop_to_marker ();
+ avail_exprs_stack->pop_to_marker ();
+}
+
+/* Examine the outgoing edges from BB and conditionally
+ try to thread them.
+
+ DUMMY_COND is a shared cond_expr used by condition simplification as scratch,
+ to avoid allocating memory.
+
+ CONST_AND_COPIES is used to undo temporary equivalences created during the
+ walk of E->dest.
+
+ The available expression table is referenced vai AVAIL_EXPRS_STACK.
+
+ SIMPLIFY is a pass-specific function used to simplify statements. */
+
+void
+thread_outgoing_edges (basic_block bb, gcond *dummy_cond,
+ class const_and_copies *const_and_copies,
+ class avail_exprs_stack *avail_exprs_stack,
+ tree (*simplify) (gimple *, gimple *,
+ class avail_exprs_stack *,
+ basic_block))
+{
+ int flags = (EDGE_IGNORE | EDGE_COMPLEX | EDGE_ABNORMAL);
+ gimple *last;
+
+ /* If we have an outgoing edge to a block with multiple incoming and
+ outgoing edges, then we may be able to thread the edge, i.e., we
+ may be able to statically determine which of the outgoing edges
+ will be traversed when the incoming edge from BB is traversed. */
+ if (single_succ_p (bb)
+ && (single_succ_edge (bb)->flags & flags) == 0
+ && potentially_threadable_block (single_succ (bb)))
+ {
+ thread_across_edge (dummy_cond, single_succ_edge (bb),
+ const_and_copies, avail_exprs_stack,
+ simplify);
+ }
+ else if ((last = last_stmt (bb))
+ && gimple_code (last) == GIMPLE_COND
+ && EDGE_COUNT (bb->succs) == 2
+ && (EDGE_SUCC (bb, 0)->flags & flags) == 0
+ && (EDGE_SUCC (bb, 1)->flags & flags) == 0)
+ {
+ edge true_edge, false_edge;
+
+ extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
+
+ /* Only try to thread the edge if it reaches a target block with
+ more than one predecessor and more than one successor. */
+ if (potentially_threadable_block (true_edge->dest))
+ thread_across_edge (dummy_cond, true_edge,
+ const_and_copies, avail_exprs_stack, simplify);
+
+ /* Similarly for the ELSE arm. */
+ if (potentially_threadable_block (false_edge->dest))
+ thread_across_edge (dummy_cond, false_edge,
+ const_and_copies, avail_exprs_stack, simplify);
+ }
}