* tree-ssa-threadedge.c: Remove include of tree-ssa-threadbackward.h.
(thread_across_edge): Remove calls to find_jump_threads_backwards.
* passes.def: Add jump threading passes before DOM/VRP.
* tree-ssa-threadbackward.c (find_jump_threads_backwards): Change
argument to a basic block from an edge. Remove tests which are
handled elsewhere.
(pass_data_thread_jumps, class pass_thread_jumps): New.
(pass_thread_jumps::gate, pass_thread_jumps::execute): New.
(make_pass_thread_jumps): Likewise.
* tree-pass.h (make_pass_thread_jumps): Declare.
* gcc.dg/tree-ssa/pr21417.c: Update expected output.
* gcc.dg/tree-ssa/pr66752-3.c: Likewise.
* gcc.dg/tree-ssa/pr68198.c: Likewise.
* gcc.dg/tree-ssa/pr69196-1.c: Likewise.
* gcc.dg/tree-ssa/pr69270-3.c: Likewise.
* gcc.dg/tree-ssa/ssa-dom-thread-2b.c: Likewise.
* gcc.dg/tree-ssa/ssa-dom-thread-2g.c: Likewise.
* gcc.dg/tree-ssa/ssa-dom-thread-2h.c: Likewise.
* gcc.dg/tree-ssa/ssa-dom-thread-6.c: Likewise.
* gcc.dg/tree-ssa/ssa-dom-thread-7.c: Likewise.
* gcc.dg/tree-ssa/ssa-dom-thread-12.c: Likewise.
* gcc.dg/tree-ssa/ssa-dom-thread-13.c: Likewise.
* gcc.dg/tree-ssa/vrp56.c: Likewise.
From-SVN: r236831
+2016-05-26 Jeff Law <law@redhat.com>
+
+ * tree-ssa-threadedge.c: Remove include of tree-ssa-threadbackward.h.
+ (thread_across_edge): Remove calls to find_jump_threads_backwards.
+ * passes.def: Add jump threading passes before DOM/VRP.
+ * tree-ssa-threadbackward.c (find_jump_threads_backwards): Change
+ argument to a basic block from an edge. Remove tests which are
+ handled elsewhere.
+ (pass_data_thread_jumps, class pass_thread_jumps): New.
+ (pass_thread_jumps::gate, pass_thread_jumps::execute): New.
+ (make_pass_thread_jumps): Likewise.
+ * tree-pass.h (make_pass_thread_jumps): Declare.
+
2016-05-27 Eric Botcazou <ebotcazou@adacore.com>
* config/visium/visium-protos.h (split_double_move): Rename into...
NEXT_PASS (pass_return_slot);
NEXT_PASS (pass_fre);
NEXT_PASS (pass_merge_phi);
+ NEXT_PASS (pass_thread_jumps);
NEXT_PASS (pass_vrp, true /* warn_array_bounds_p */);
NEXT_PASS (pass_chkp_opt);
NEXT_PASS (pass_dce);
propagations have already run, but before some more dead code
is removed, and this place fits nicely. Remember this when
trying to move or duplicate pass_dominator somewhere earlier. */
+ NEXT_PASS (pass_thread_jumps);
NEXT_PASS (pass_dominator, true /* may_peel_loop_headers_p */);
/* At this point the majority of const/copy propagations
are exposed. Go ahead and identify paths that should never
NEXT_PASS (pass_strength_reduction);
NEXT_PASS (pass_split_paths);
NEXT_PASS (pass_tracer);
+ NEXT_PASS (pass_thread_jumps);
NEXT_PASS (pass_dominator, false /* may_peel_loop_headers_p */);
NEXT_PASS (pass_strlen);
+ NEXT_PASS (pass_thread_jumps);
NEXT_PASS (pass_vrp, false /* warn_array_bounds_p */);
/* The only const/copy propagation opportunities left after
DOM and VRP should be due to degenerate PHI nodes. So rather than
+2016-05-26 Jeff Law <law@redhat.com>
+
+ * gcc.dg/tree-ssa/pr21417.c: Update expected output.
+ * gcc.dg/tree-ssa/pr66752-3.c: Likewise.
+ * gcc.dg/tree-ssa/pr68198.c: Likewise.
+ * gcc.dg/tree-ssa/pr69196-1.c: Likewise.
+ * gcc.dg/tree-ssa/pr69270-3.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-dom-thread-2b.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-dom-thread-2g.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-dom-thread-2h.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-dom-thread-6.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-dom-thread-12.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-dom-thread-13.c: Likewise.
+ * gcc.dg/tree-ssa/vrp56.c: Likewise.
+
2016-05-27 Ville Voutilainen <ville.voutilainen@gmail.com>
PR c++/69855
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-dom3-details" } */
+/* { dg-options "-O2 -fdump-tree-thread4-details" } */
struct tree_common
{
/* We should thread the backedge to the top of the loop; ie we only
execute the if (expr->common.code != 142) test once per loop
iteration. */
-/* { dg-final { scan-tree-dump-times "FSM jump thread" 1 "dom3" } } */
+/* { dg-final { scan-tree-dump-times "FSM jump thread" 1 "thread4" } } */
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fdump-tree-thread1-details -fdump-tree-dce2" } */
extern int status, pt;
extern int count;
pt--;
}
-/* There are 3 FSM jump threading opportunities, all of which will be
+/* There are 4 FSM jump threading opportunities, all of which will be
realized, which will eliminate testing of FLAG, completely. */
-/* { dg-final { scan-tree-dump-times "Registering FSM" 3 "vrp1"} } */
+/* { dg-final { scan-tree-dump-times "Registering FSM" 4 "thread1"} } */
-/* There should be no assignments or references to FLAG. */
-/* { dg-final { scan-tree-dump-not "flag" "optimized"} } */
+/* There should be no assignments or references to FLAG, verify they're
+ eliminated as early as possible. */
+/* { dg-final { scan-tree-dump-not "if .flag" "dce2"} } */
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-thread1-details" } */
extern void abort (void);
/* There are 3 FSM jump threading opportunities, two of which will
get filtered out. */
-/* { dg-final { scan-tree-dump-times "Registering FSM" 1 "vrp1"} } */
-/* { dg-final { scan-tree-dump-times "FSM Thread through multiway branch without threading a multiway branch" 2 "vrp1"} } */
+/* { dg-final { scan-tree-dump-times "Registering FSM" 1 "thread1"} } */
+/* { dg-final { scan-tree-dump-times "FSM Thread through multiway branch without threading a multiway branch" 2 "thread1"} } */
/* { dg-do compile { target sparc*-*-* x86_64-*-* } } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-thread1-details" } */
-/* { dg-final { scan-tree-dump "FSM did not thread around loop and would copy too many statements" "vrp1" } } */
+/* { dg-final { scan-tree-dump "FSM did not thread around loop and would copy too many statements" "thread1" } } */
typedef __builtin_va_list __gnuc_va_list;
/* We're looking for a constant argument a PHI node. There
should only be one if we unpropagate correctly. */
-/* { dg-final { scan-tree-dump-times ", 1" 1 "uncprop1"} } */
+/* { dg-final { scan-tree-dump-times ", 1" 4 "uncprop1"} } */
typedef long unsigned int size_t;
typedef union gimple_statement_d *gimple;
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-stats -fdump-tree-dom2-stats" } */
+/* { dg-options "-O2 -fdump-tree-thread1-stats -fdump-tree-dom2-stats" } */
void foo();
void bla();
case. And we want to thread through the header as well. These
are both caught by threading in DOM. */
/* { dg-final { scan-tree-dump-not "Jumps threaded" "dom2"} } */
-/* { dg-final { scan-tree-dump-times "Jumps threaded: 2" 1 "vrp1"} } */
+/* { dg-final { scan-tree-dump-times "Jumps threaded: 1" 1 "thread1"} } */
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-stats -fdump-tree-dom2-stats" } */
+/* { dg-options "-O2 -fdump-tree-dom2-details" } */
void foo();
void bla();
} while (i++ < 100);
}
-/* { dg-final { scan-tree-dump "Jumps threaded: 2" "vrp1"} } */
-/* { dg-final { scan-tree-dump "Jumps threaded: 1" "dom2"} } */
+/* This one can only be threaded if both paths to the
+ conditional inside the loop are threaded at the same
+ time. Else we potentially end up with irreducible
+ loops. */
+/* { dg-final { scan-tree-dump-not "IRREDUCIBLE_LOOP" "dom2" } } */
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-stats -fdump-tree-dom2-stats" } */
+/* { dg-options "-O2 -fdump-tree-dom2-details" } */
void foo();
void bla();
/* Peeling off the first iteration would make threading through
the loop latch safe, but we don't do that currently. */
-/* { dg-final { scan-tree-dump "Jumps threaded: 1" "vrp1"} } */
-/* { dg-final { scan-tree-dump "Jumps threaded: 1" "dom2"} } */
+/* { dg-final { scan-tree-dump-not "IRREDUCIBLE_LOOP" "dom2" } } */
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-dom2-details" } */
-/* { dg-final { scan-tree-dump-times "FSM" 6 "dom2" } } */
+/* { dg-options "-O2 -fdump-tree-thread1-details -fdump-tree-thread2-details" } */
+/* { dg-final { scan-tree-dump-times "FSM" 3 "thread1" } } */
+/* { dg-final { scan-tree-dump-times "FSM" 4 "thread2" } } */
int sum0, sum1, sum2, sum3;
int foo (char *s, char **ret)
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-stats -fdump-tree-dom2-stats -fdump-tree-dom3-stats -fdump-tree-vrp2-stats" } */
-/* { dg-final { scan-tree-dump "Jumps threaded: 19" "vrp1" } } */
-/* { dg-final { scan-tree-dump "Jumps threaded: 12" "dom2" } } */
+/* { dg-options "-O2 -fdump-tree-thread1-stats -fdump-tree-thread2-stats -fdump-tree-thread3-stats -fdump-tree-dom3-stats -fdump-tree-vrp2-stats" } */
+/* { dg-final { scan-tree-dump "Jumps threaded: 16" "thread1" } } */
+/* { dg-final { scan-tree-dump "Jumps threaded: 11" "thread2" } } */
+/* { dg-final { scan-tree-dump "Jumps threaded: 3" "thread3" } } */
/* { dg-final { scan-tree-dump-not "Jumps threaded" "dom3" } } */
/* { dg-final { scan-tree-dump-not "Jumps threaded" "vrp2" } } */
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-dom2-details" } */
-/* { dg-final { scan-tree-dump "FSM" "dom2" } } */
+/* { dg-options "-O2 -fdump-tree-thread2-details -fdump-tree-thread3-details -fdump-tree-thread4-details" } */
+/* { dg-final { scan-tree-dump "FSM" "thread2" } } */
+/* { dg-final { scan-tree-dump "FSM" "thread3" } } */
+/* { dg-final { scan-tree-dump "FSM" "thread4" } } */
typedef struct bitmap_head_def *bitmap;
typedef const struct bitmap_head_def *const_bitmap;
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
-/* { dg-final { scan-tree-dump "FSM" "vrp1" } } */
+/* { dg-options "-O2 -fdump-tree-thread1-details" } */
+/* { dg-final { scan-tree-dump "FSM" "thread1" } } */
typedef struct rtx_def *rtx;
typedef const struct rtx_def *const_rtx;
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fdump-tree-thread1-stats" } */
typedef struct basic_block_def *basic_block;
struct basic_block_def;
struct edge_def;
foo ();
}
}
-/* { dg-final { scan-tree-dump-times "Threaded" 1 "vrp1"} } */
+/* { dg-final { scan-tree-dump "Jumps threaded: 1" "thread1"} } */
DEFTIMEVAR (TV_TREE_SSA_INCREMENTAL , "tree SSA incremental")
DEFTIMEVAR (TV_TREE_OPS , "tree operand scan")
DEFTIMEVAR (TV_TREE_SSA_DOMINATOR_OPTS , "dominator optimization")
+DEFTIMEVAR (TV_TREE_SSA_THREAD_JUMPS , "backwards jump threading")
DEFTIMEVAR (TV_TREE_SRA , "tree SRA")
DEFTIMEVAR (TV_ISOLATE_ERRONEOUS_PATHS , "isolate eroneous paths")
DEFTIMEVAR (TV_TREE_CCP , "tree CCP")
extern gimple_opt_pass *make_pass_cd_dce (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_call_cdce (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_merge_phi (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_thread_jumps (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_split_crit_edges (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_laddress (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_pre (gcc::context *ctxt);
#include "tree-ssa-loop.h"
#include "cfganal.h"
#include "tree-pass.h"
+#include "gimple-ssa.h"
+#include "tree-phinodes.h"
static int max_threaded_paths;
finding a path where NAME is a constant, we can thread the path. */
void
-find_jump_threads_backwards (edge e)
+find_jump_threads_backwards (basic_block bb)
{
if (!flag_expensive_optimizations
- || optimize_function_for_size_p (cfun)
- || e->dest->loop_father != e->src->loop_father
- || loop_depth (e->dest->loop_father) == 0)
+ || optimize_function_for_size_p (cfun))
return;
- gimple *stmt = get_gimple_control_stmt (e->dest);
+ gimple *stmt = get_gimple_control_stmt (bb);
if (!stmt)
return;
vec<basic_block, va_gc> *bb_path;
vec_alloc (bb_path, 10);
- vec_safe_push (bb_path, e->dest);
+ vec_safe_push (bb_path, bb);
hash_set<basic_block> *visited_bbs = new hash_set<basic_block>;
max_threaded_paths = PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATHS);
delete visited_bbs;
vec_free (bb_path);
}
+
+namespace {
+
+const pass_data pass_data_thread_jumps =
+{
+ GIMPLE_PASS,
+ "thread",
+ OPTGROUP_NONE,
+ TV_TREE_SSA_THREAD_JUMPS,
+ ( PROP_cfg | PROP_ssa ),
+ 0,
+ 0,
+ 0,
+ ( TODO_cleanup_cfg | TODO_update_ssa ),
+};
+
+class pass_thread_jumps : public gimple_opt_pass
+{
+public:
+ pass_thread_jumps (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_thread_jumps, ctxt)
+ {}
+
+ opt_pass * clone (void) { return new pass_thread_jumps (m_ctxt); }
+ virtual bool gate (function *);
+ virtual unsigned int execute (function *);
+};
+
+bool
+pass_thread_jumps::gate (function *fun ATTRIBUTE_UNUSED)
+{
+ return (flag_expensive_optimizations
+ && ! optimize_function_for_size_p (cfun));
+}
+
+
+unsigned int
+pass_thread_jumps::execute (function *fun)
+{
+ /* Try to thread each block with more than one successor. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, fun)
+ {
+ if (EDGE_COUNT (bb->succs) > 1)
+ find_jump_threads_backwards (bb);
+ }
+ thread_through_all_blocks (true);
+ return 0;
+}
+
+}
+
+gimple_opt_pass *
+make_pass_thread_jumps (gcc::context *ctxt)
+{
+ return new pass_thread_jumps (ctxt);
+}
#include "params.h"
#include "tree-ssa-scopedtables.h"
#include "tree-ssa-threadedge.h"
-#include "tree-ssa-threadbackward.h"
#include "tree-ssa-dom.h"
#include "gimple-fold.h"
path->release ();
delete path;
- find_jump_threads_backwards (e);
-
/* A negative status indicates the target block was deemed too big to
duplicate. Just quit now rather than trying to use the block as
a joiner in a jump threading path.
{
if ((e->flags & EDGE_DFS_BACK) != 0
|| (taken_edge->flags & EDGE_DFS_BACK) != 0)
- {
- find_jump_threads_backwards (taken_edge);
- continue;
- }
+ continue;
/* Push a fresh marker so we can unwind the equivalences created
for each of E->dest's successors. */
register_jump_thread (path);
}
else
- {
- find_jump_threads_backwards (path->last ()->e);
- delete_jump_thread_path (path);
- }
+ delete_jump_thread_path (path);
/* And unwind the equivalence table. */
if (avail_exprs_stack)