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.c112
1 files changed, 71 insertions, 41 deletions
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
index e791269ebac..10271919786 100644
--- a/gcc/tree-ssa-threadupdate.c
+++ b/gcc/tree-ssa-threadupdate.c
@@ -24,6 +24,9 @@ along with GCC; see the file COPYING3. If not see
#include "flags.h"
#include "basic-block.h"
#include "function.h"
+#include "gimple.h"
+#include "gimple-ssa.h"
+#include "tree-phinodes.h"
#include "tree-ssa.h"
#include "tree-ssa-threadupdate.h"
#include "dumpfile.h"
@@ -613,10 +616,12 @@ redirection_block_p (basic_block bb)
the appropriate duplicate of BB.
If NOLOOP_ONLY is true, we only perform the threading as long as it
- does not affect the structure of the loops in a nontrivial way. */
+ does not affect the structure of the loops in a nontrivial way.
+
+ If JOINERS is true, then thread through joiner blocks as well. */
static bool
-thread_block (basic_block bb, bool noloop_only)
+thread_block_1 (basic_block bb, bool noloop_only, bool joiners)
{
/* E is an incoming edge into BB that we may or may not want to
redirect to a duplicate of BB. */
@@ -639,7 +644,9 @@ thread_block (basic_block bb, bool noloop_only)
e = loop_latch_edge (loop);
vec<jump_thread_edge *> *path = THREAD_PATH (e);
- if (path)
+ if (path
+ && (((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK && joiners)
+ || ((*path)[1]->type == EDGE_COPY_SRC_BLOCK && !joiners)))
{
for (unsigned int i = 1; i < path->length (); i++)
{
@@ -663,6 +670,11 @@ thread_block (basic_block bb, bool noloop_only)
continue;
vec<jump_thread_edge *> *path = THREAD_PATH (e);
+
+ if (((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK && !joiners)
+ || ((*path)[1]->type == EDGE_COPY_SRC_BLOCK && joiners))
+ continue;
+
e2 = path->last ()->e;
if (!e2 || noloop_only)
{
@@ -759,6 +771,24 @@ thread_block (basic_block bb, bool noloop_only)
return local_info.jumps_threaded;
}
+/* Wrapper for thread_block_1 so that we can first handle jump
+ thread paths which do not involve copying joiner blocks, then
+ handle jump thread paths which have joiner blocks.
+
+ By doing things this way we can be as aggressive as possible and
+ not worry that copying a joiner block will create a jump threading
+ opportunity. */
+
+static bool
+thread_block (basic_block bb, bool noloop_only)
+{
+ bool retval;
+ retval = thread_block_1 (bb, noloop_only, false);
+ retval |= thread_block_1 (bb, noloop_only, true);
+ return retval;
+}
+
+
/* Threads edge E through E->dest to the edge THREAD_TARGET (E). Returns the
copy of E->dest created during threading, or E->dest if it was not necessary
to copy it (E is its single predecessor). */
@@ -1237,47 +1267,14 @@ mark_threaded_blocks (bitmap threaded_blocks)
edge e;
edge_iterator ei;
- /* It is possible to have jump threads in which one is a subpath
- of the other. ie, (A, B), (B, C), (C, D) where B is a joiner
- block and (B, C), (C, D) where no joiner block exists.
-
- When this occurs ignore the jump thread request with the joiner
- block. It's totally subsumed by the simpler jump thread request.
-
- This results in less block copying, simpler CFGs. More improtantly,
- when we duplicate the joiner block, B, in this case we will create
- a new threading opportunity that we wouldn't be able to optimize
- until the next jump threading iteration.
-
- So first convert the jump thread requests which do not require a
- joiner block. */
- for (i = 0; i < paths.length (); i++)
- {
- vec<jump_thread_edge *> *path = paths[i];
-
- if ((*path)[1]->type != EDGE_COPY_SRC_JOINER_BLOCK)
- {
- edge e = (*path)[0]->e;
- e->aux = (void *)path;
- bitmap_set_bit (tmp, e->dest->index);
- }
- }
-
-
- /* Now iterate again, converting cases where we threaded through
- a joiner block, but ignoring those where we have already
- threaded through the joiner block. */
+ /* Move the jump threading requests from PATHS to each edge
+ which starts a jump thread path. */
for (i = 0; i < paths.length (); i++)
{
vec<jump_thread_edge *> *path = paths[i];
-
- if ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK
- && (*path)[0]->e->aux == NULL)
- {
- edge e = (*path)[0]->e;
- e->aux = path;
- bitmap_set_bit (tmp, e->dest->index);
- }
+ edge e = (*path)[0]->e;
+ e->aux = (void *)path;
+ bitmap_set_bit (tmp, e->dest->index);
}
/* If we have a joiner block (J) which has two successors S1 and S2 and
@@ -1475,6 +1472,39 @@ thread_through_all_blocks (bool may_peel_loop_headers)
retval |= thread_through_loop_header (loop, may_peel_loop_headers);
}
+ /* Assume we had a jump thread path which went from the latch to the exit
+ and a path which goes from outside to inside the same loop.
+
+ If the latch to exit was handled first, we will thread it and clear
+ loop->header.
+
+ The second path will be ignored by thread_block because we're going
+ through a loop header. It will also be ignored by the loop above
+ because loop->header is NULL.
+
+ This results in the second path never being threaded. The failure
+ mode is a dangling AUX field.
+
+ This is inherently a bit of a pain to fix, so we just walk all the
+ blocks and all the incoming edges to those blocks and clear their
+ AUX fields. */
+ basic_block bb;
+ edge_iterator ei;
+ edge e;
+ FOR_EACH_BB (bb)
+ {
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ if (e->aux)
+ {
+ vec<jump_thread_edge *> *path = THREAD_PATH (e);
+
+ for (unsigned int i = 0; i < path->length (); i++)
+ delete (*path)[i];
+ path->release ();
+ e->aux = NULL;
+ }
+ }
+
statistics_counter_event (cfun, "Jumps threaded",
thread_stats.num_threaded_edges);