summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-threadupdate.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-threadupdate.c')
-rw-r--r--gcc/tree-ssa-threadupdate.c76
1 files changed, 66 insertions, 10 deletions
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
index 8c21ac2aa16..b6264f5de54 100644
--- a/gcc/tree-ssa-threadupdate.c
+++ b/gcc/tree-ssa-threadupdate.c
@@ -147,6 +147,14 @@ struct local_info
bool jumps_threaded;
};
+/* Passes which use the jump threading code register jump threading
+ opportunities as they are discovered. We keep the registered
+ jump threading opportunities in this vector as edge pairs
+ (original_edge, target_edge). */
+DEF_VEC_ALLOC_P(edge,heap);
+static VEC(edge,heap) *threaded_edges;
+
+
/* Jump threading statistics. */
struct thread_stats_d
@@ -802,18 +810,37 @@ thread_block (basic_block bb)
return local_info.jumps_threaded;
}
-/* Walk through all blocks and thread incoming edges to the block's
- destinations as requested. This is the only entry point into this
- file.
+/* Walk through the registered jump threads and convert them into a
+ form convienent for this pass.
+
+ Any block which has incoming edges threaded to outgoing edges
+ will have its entry in THREADED_BLOCK set.
- Blocks which have one or more incoming edges have INCOMING_EDGE_THREADED
- set in the block's annotation.
+ Any threaded edge will have its new outgoing edge stored in the
+ original edge's AUX field.
- Each edge that should be threaded has the new destination edge stored in
- the original edge's AUX field.
+ This form avoids the need to walk all the edges in the CFG to
+ discover blocks which need processing and avoids unnecessary
+ hash table lookups to map from threaded edge to new target. */
- This routine (or one of its callees) will clear INCOMING_EDGE_THREADED
- in the block annotations and the AUX field in the edges.
+static void
+mark_threaded_blocks (bitmap threaded_blocks)
+{
+ unsigned int i;
+
+ for (i = 0; i < VEC_length (edge, threaded_edges); i += 2)
+ {
+ edge e = VEC_index (edge, threaded_edges, i);
+ edge e2 = VEC_index (edge, threaded_edges, i + 1);
+
+ e->aux = e2;
+ bitmap_set_bit (threaded_blocks, e->dest->index);
+ }
+}
+
+
+/* Walk through all blocks and thread incoming edges to the appropriate
+ outgoing edge for each edge pair recorded in THREADED_EDGES.
It is the caller's responsibility to fix the dominance information
and rewrite duplicated SSA_NAMEs back into SSA form.
@@ -821,15 +848,22 @@ thread_block (basic_block bb)
Returns true if one or more edges were threaded, false otherwise. */
bool
-thread_through_all_blocks (bitmap threaded_blocks)
+thread_through_all_blocks (void)
{
bool retval = false;
unsigned int i;
bitmap_iterator bi;
+ bitmap threaded_blocks;
+
+ if (threaded_edges == NULL)
+ return false;
+ threaded_blocks = BITMAP_ALLOC (NULL);
rediscover_loops_after_threading = false;
memset (&thread_stats, 0, sizeof (thread_stats));
+ mark_threaded_blocks (threaded_blocks);
+
EXECUTE_IF_SET_IN_BITMAP (threaded_blocks, 0, i, bi)
{
basic_block bb = BASIC_BLOCK (i);
@@ -842,5 +876,27 @@ thread_through_all_blocks (bitmap threaded_blocks)
fprintf (dump_file, "\nJumps threaded: %lu\n",
thread_stats.num_threaded_edges);
+ BITMAP_FREE (threaded_blocks);
+ threaded_blocks = NULL;
+ VEC_free (edge, heap, threaded_edges);
+ threaded_edges = NULL;
return retval;
}
+
+/* Register a jump threading opportunity. We queue up all the jump
+ threading opportunities discovered by a pass and update the CFG
+ and SSA form all at once.
+
+ E is the edge we can thread, E2 is the new target edge. ie, we
+ are effectively recording that E->dest can be changed to E2->dest
+ after fixing the SSA graph. */
+
+void
+register_jump_thread (edge e, edge e2)
+{
+ if (threaded_edges == NULL)
+ threaded_edges = VEC_alloc (edge, heap, 10);
+
+ VEC_safe_push (edge, heap, threaded_edges, e);
+ VEC_safe_push (edge, heap, threaded_edges, e2);
+}