/* Loop optimizations over tree-ssa.
- Copyright (C) 2003, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2003-2019 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
#include "tree.h"
-#include "tm_p.h"
-#include "basic-block.h"
-#include "output.h"
-#include "tree-flow.h"
-#include "tree-dump.h"
+#include "gimple.h"
#include "tree-pass.h"
-#include "timevar.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "tree-ssa-loop-ivopts.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-ssa-loop.h"
#include "cfgloop.h"
-#include "flags.h"
#include "tree-inline.h"
#include "tree-scalar-evolution.h"
-#include "diagnostic-core.h"
#include "tree-vectorizer.h"
+#include "omp-general.h"
+#include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
-/* The loop superpass. */
-static bool
-gate_tree_loop (void)
-{
- return flag_tree_loop_optimize != 0;
-}
+/* A pass making sure loops are fixed up. */
-struct gimple_opt_pass pass_tree_loop =
-{
- {
- GIMPLE_PASS,
- "loop", /* name */
- gate_tree_loop, /* gate */
- NULL, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_LOOP, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- TODO_ggc_collect, /* todo_flags_start */
- TODO_dump_func | TODO_verify_ssa | TODO_ggc_collect /* todo_flags_finish */
- }
-};
+namespace {
-/* Loop optimizer initialization. */
+const pass_data pass_data_fix_loops =
+{
+ GIMPLE_PASS, /* type */
+ "fix_loops", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_TREE_LOOP, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
-static unsigned int
-tree_ssa_loop_init (void)
+class pass_fix_loops : public gimple_opt_pass
{
- loop_optimizer_init (LOOPS_NORMAL
- | LOOPS_HAVE_RECORDED_EXITS);
- rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+public:
+ pass_fix_loops (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_fix_loops, ctxt)
+ {}
- if (number_of_loops () <= 1)
- return 0;
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return flag_tree_loop_optimize; }
- scev_initialize ();
+ virtual unsigned int execute (function *fn);
+}; // class pass_fix_loops
+
+unsigned int
+pass_fix_loops::execute (function *)
+{
+ if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+ {
+ calculate_dominance_info (CDI_DOMINATORS);
+ fix_loop_structure (NULL);
+ }
return 0;
}
-struct gimple_opt_pass pass_tree_loop_init =
-{
- {
- GIMPLE_PASS,
- "loopinit", /* name */
- NULL, /* gate */
- tree_ssa_loop_init, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_LOOP_INIT, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
- }
-};
-
-/* Loop invariant motion pass. */
+} // anon namespace
-static unsigned int
-tree_ssa_loop_im (void)
+gimple_opt_pass *
+make_pass_fix_loops (gcc::context *ctxt)
{
- if (number_of_loops () <= 1)
- return 0;
-
- return tree_ssa_lim ();
+ return new pass_fix_loops (ctxt);
}
+
+/* Gate for loop pass group. The group is controlled by -ftree-loop-optimize
+ but we also avoid running it when the IL doesn't contain any loop. */
+
static bool
-gate_tree_ssa_loop_im (void)
+gate_loop (function *fn)
{
- return flag_tree_loop_im != 0;
+ if (!flag_tree_loop_optimize)
+ return false;
+
+ /* For -fdump-passes which runs before loop discovery print the
+ state of -ftree-loop-optimize. */
+ if (!loops_for_fn (fn))
+ return true;
+
+ return number_of_loops (fn) > 1;
}
-struct gimple_opt_pass pass_lim =
-{
- {
- GIMPLE_PASS,
- "lim", /* name */
- gate_tree_ssa_loop_im, /* gate */
- tree_ssa_loop_im, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_LIM, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
- }
-};
+/* The loop superpass. */
-/* Loop unswitching pass. */
+namespace {
-static unsigned int
-tree_ssa_loop_unswitch (void)
+const pass_data pass_data_tree_loop =
{
- if (number_of_loops () <= 1)
- return 0;
-
- return tree_ssa_unswitch_loops ();
-}
+ GIMPLE_PASS, /* type */
+ "loop", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_TREE_LOOP, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
-static bool
-gate_tree_ssa_loop_unswitch (void)
+class pass_tree_loop : public gimple_opt_pass
{
- return flag_unswitch_loops != 0;
-}
+public:
+ pass_tree_loop (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_tree_loop, ctxt)
+ {}
-struct gimple_opt_pass pass_tree_unswitch =
-{
- {
- GIMPLE_PASS,
- "unswitch", /* name */
- gate_tree_ssa_loop_unswitch, /* gate */
- tree_ssa_loop_unswitch, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_LOOP_UNSWITCH, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_ggc_collect | TODO_dump_func /* todo_flags_finish */
- }
-};
+ /* opt_pass methods: */
+ virtual bool gate (function *fn) { return gate_loop (fn); }
-/* Predictive commoning. */
+}; // class pass_tree_loop
-static unsigned
-run_tree_predictive_commoning (void)
-{
- if (!current_loops)
- return 0;
+} // anon namespace
- tree_predictive_commoning ();
- return 0;
+gimple_opt_pass *
+make_pass_tree_loop (gcc::context *ctxt)
+{
+ return new pass_tree_loop (ctxt);
}
+/* Gate for oacc kernels pass group. */
+
static bool
-gate_tree_predictive_commoning (void)
+gate_oacc_kernels (function *fn)
{
- return flag_predictive_commoning != 0;
+ if (!flag_openacc)
+ return false;
+
+ if (!lookup_attribute ("oacc kernels", DECL_ATTRIBUTES (fn->decl)))
+ return false;
+
+ struct loop *loop;
+ FOR_EACH_LOOP (loop, 0)
+ if (loop->in_oacc_kernels_region)
+ return true;
+
+ return false;
}
-struct gimple_opt_pass pass_predcom =
-{
- {
- GIMPLE_PASS,
- "pcom", /* name */
- gate_tree_predictive_commoning, /* gate */
- run_tree_predictive_commoning, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_PREDCOM, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func
- | TODO_update_ssa_only_virtuals /* todo_flags_finish */
- }
-};
+/* The oacc kernels superpass. */
-/* Loop autovectorization. */
+namespace {
-static unsigned int
-tree_vectorize (void)
+const pass_data pass_data_oacc_kernels =
{
- if (number_of_loops () <= 1)
- return 0;
+ GIMPLE_PASS, /* type */
+ "oacc_kernels", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_TREE_LOOP, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
- return vectorize_loops ();
-}
+class pass_oacc_kernels : public gimple_opt_pass
+{
+public:
+ pass_oacc_kernels (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_oacc_kernels, ctxt)
+ {}
-static bool
-gate_tree_vectorize (void)
+ /* opt_pass methods: */
+ virtual bool gate (function *fn) { return gate_oacc_kernels (fn); }
+
+}; // class pass_oacc_kernels
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_oacc_kernels (gcc::context *ctxt)
{
- return flag_tree_vectorize;
+ return new pass_oacc_kernels (ctxt);
}
-struct gimple_opt_pass pass_vectorize =
-{
- {
- GIMPLE_PASS,
- "vect", /* name */
- gate_tree_vectorize, /* gate */
- tree_vectorize, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_VECTORIZATION, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func | TODO_update_ssa
- | TODO_ggc_collect /* todo_flags_finish */
- }
-};
+/* The ipa oacc superpass. */
-/* GRAPHITE optimizations. */
+namespace {
-static unsigned int
-graphite_transforms (void)
+const pass_data pass_data_ipa_oacc =
{
- if (!current_loops)
- return 0;
+ SIMPLE_IPA_PASS, /* type */
+ "ipa_oacc", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_TREE_LOOP, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
- graphite_transform_loops ();
+class pass_ipa_oacc : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_oacc (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_oacc, ctxt)
+ {}
- return 0;
-}
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ return (optimize
+ && flag_openacc
+ /* Don't bother doing anything if the program has errors. */
+ && !seen_error ());
+ }
-static bool
-gate_graphite_transforms (void)
-{
- /* Enable -fgraphite pass if any one of the graphite optimization flags
- is turned on. */
- if (flag_loop_block
- || flag_loop_interchange
- || flag_loop_strip_mine
- || flag_graphite_identity
- || flag_loop_parallelize_all
- || flag_loop_flatten)
- flag_graphite = 1;
-
- return flag_graphite != 0;
+}; // class pass_ipa_oacc
+
+} // anon namespace
+
+simple_ipa_opt_pass *
+make_pass_ipa_oacc (gcc::context *ctxt)
+{
+ return new pass_ipa_oacc (ctxt);
}
-struct gimple_opt_pass pass_graphite =
-{
- {
- GIMPLE_PASS,
- "graphite0", /* name */
- gate_graphite_transforms, /* gate */
- NULL, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_GRAPHITE, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
+/* The ipa oacc kernels pass. */
-struct gimple_opt_pass pass_graphite_transforms =
-{
- {
- GIMPLE_PASS,
- "graphite", /* name */
- gate_graphite_transforms, /* gate */
- graphite_transforms, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_GRAPHITE_TRANSFORMS, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
- }
-};
+namespace {
-/* Check the correctness of the data dependence analyzers. */
+const pass_data pass_data_ipa_oacc_kernels =
+{
+ SIMPLE_IPA_PASS, /* type */
+ "ipa_oacc_kernels", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_TREE_LOOP, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
-static unsigned int
-check_data_deps (void)
+class pass_ipa_oacc_kernels : public simple_ipa_opt_pass
{
- if (number_of_loops () <= 1)
- return 0;
+public:
+ pass_ipa_oacc_kernels (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_oacc_kernels, ctxt)
+ {}
- tree_check_data_deps ();
- return 0;
-}
+}; // class pass_ipa_oacc_kernels
-static bool
-gate_check_data_deps (void)
+} // anon namespace
+
+simple_ipa_opt_pass *
+make_pass_ipa_oacc_kernels (gcc::context *ctxt)
{
- return flag_check_data_deps != 0;
+ return new pass_ipa_oacc_kernels (ctxt);
}
-struct gimple_opt_pass pass_check_data_deps =
-{
- {
- GIMPLE_PASS,
- "ckdd", /* name */
- gate_check_data_deps, /* gate */
- check_data_deps, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_CHECK_DATA_DEPS, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
- }
-};
+/* The no-loop superpass. */
-/* Canonical induction variable creation pass. */
+namespace {
-static unsigned int
-tree_ssa_loop_ivcanon (void)
+const pass_data pass_data_tree_no_loop =
{
- if (number_of_loops () <= 1)
- return 0;
-
- return canonicalize_induction_variables ();
-}
+ GIMPLE_PASS, /* type */
+ "no_loop", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_TREE_NOLOOP, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
-static bool
-gate_tree_ssa_loop_ivcanon (void)
+class pass_tree_no_loop : public gimple_opt_pass
{
- return flag_tree_loop_ivcanon != 0;
-}
+public:
+ pass_tree_no_loop (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_tree_no_loop, ctxt)
+ {}
-struct gimple_opt_pass pass_iv_canon =
-{
- {
- GIMPLE_PASS,
- "ivcanon", /* name */
- gate_tree_ssa_loop_ivcanon, /* gate */
- tree_ssa_loop_ivcanon, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_LOOP_IVCANON, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
- }
-};
+ /* opt_pass methods: */
+ virtual bool gate (function *fn) { return !gate_loop (fn); }
-/* Propagation of constants using scev. */
+}; // class pass_tree_no_loop
-static bool
-gate_scev_const_prop (void)
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_tree_no_loop (gcc::context *ctxt)
{
- return flag_tree_scev_cprop;
+ return new pass_tree_no_loop (ctxt);
}
-struct gimple_opt_pass pass_scev_cprop =
-{
- {
- GIMPLE_PASS,
- "sccp", /* name */
- gate_scev_const_prop, /* gate */
- scev_const_prop, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_SCEV_CONST, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func | TODO_cleanup_cfg
- | TODO_update_ssa_only_virtuals
- /* todo_flags_finish */
- }
-};
-/* Record bounds on numbers of iterations of loops. */
+/* Loop optimizer initialization. */
-static unsigned int
-tree_ssa_loop_bounds (void)
+namespace {
+
+const pass_data pass_data_tree_loop_init =
{
- if (number_of_loops () <= 1)
- return 0;
+ GIMPLE_PASS, /* type */
+ "loopinit", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ TODO_update_address_taken, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
- estimate_numbers_of_iterations (true);
- scev_reset ();
- return 0;
-}
+class pass_tree_loop_init : public gimple_opt_pass
+{
+public:
+ pass_tree_loop_init (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_tree_loop_init, ctxt)
+ {}
-struct gimple_opt_pass pass_record_bounds =
-{
- {
- GIMPLE_PASS,
- "*record_bounds", /* name */
- NULL, /* gate */
- tree_ssa_loop_bounds, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_LOOP_BOUNDS, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
+ /* opt_pass methods: */
+ virtual unsigned int execute (function *);
-/* Complete unrolling of loops. */
+}; // class pass_tree_loop_init
-static unsigned int
-tree_complete_unroll (void)
+unsigned int
+pass_tree_loop_init::execute (function *fun ATTRIBUTE_UNUSED)
{
- if (number_of_loops () <= 1)
- return 0;
+ /* When processing a loop in the loop pipeline, we should be able to assert
+ that:
+ (loops_state_satisfies_p (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS
+ | LOOP_CLOSED_SSA)
+ && scev_initialized_p ())
+ */
+ loop_optimizer_init (LOOPS_NORMAL
+ | LOOPS_HAVE_RECORDED_EXITS);
+ rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+ scev_initialize ();
- return tree_unroll_loops_completely (flag_unroll_loops
- || flag_peel_loops
- || optimize >= 3, true);
+ return 0;
}
-static bool
-gate_tree_complete_unroll (void)
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_tree_loop_init (gcc::context *ctxt)
{
- return true;
+ return new pass_tree_loop_init (ctxt);
}
-struct gimple_opt_pass pass_complete_unroll =
-{
- {
- GIMPLE_PASS,
- "cunroll", /* name */
- gate_tree_complete_unroll, /* gate */
- tree_complete_unroll, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_COMPLETE_UNROLL, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func
- | TODO_ggc_collect /* todo_flags_finish */
- }
-};
+/* Loop autovectorization. */
-/* Complete unrolling of inner loops. */
+namespace {
-static unsigned int
-tree_complete_unroll_inner (void)
+const pass_data pass_data_vectorize =
+{
+ GIMPLE_PASS, /* type */
+ "vect", /* name */
+ OPTGROUP_LOOP | OPTGROUP_VEC, /* optinfo_flags */
+ TV_TREE_VECTORIZATION, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_vectorize : public gimple_opt_pass
{
- unsigned ret = 0;
+public:
+ pass_vectorize (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_vectorize, ctxt)
+ {}
- loop_optimizer_init (LOOPS_NORMAL
- | LOOPS_HAVE_RECORDED_EXITS);
- if (number_of_loops () > 1)
+ /* opt_pass methods: */
+ virtual bool gate (function *fun)
{
- scev_initialize ();
- ret = tree_unroll_loops_completely (optimize >= 3, false);
- free_numbers_of_iterations_estimates ();
- scev_finalize ();
+ return flag_tree_loop_vectorize || fun->has_force_vectorize_loops;
}
- loop_optimizer_finalize ();
- return ret;
-}
+ virtual unsigned int execute (function *);
-static bool
-gate_tree_complete_unroll_inner (void)
+}; // class pass_vectorize
+
+unsigned int
+pass_vectorize::execute (function *fun)
{
- return optimize >= 2;
-}
+ if (number_of_loops (fun) <= 1)
+ return 0;
-struct gimple_opt_pass pass_complete_unrolli =
-{
- {
- GIMPLE_PASS,
- "cunrolli", /* name */
- gate_tree_complete_unroll_inner, /* gate */
- tree_complete_unroll_inner, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_COMPLETE_UNROLL, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_verify_flow
- | TODO_dump_func
- | TODO_ggc_collect /* todo_flags_finish */
- }
-};
+ return vectorize_loops ();
+}
-/* Parallelization. */
+} // anon namespace
-static bool
-gate_tree_parallelize_loops (void)
+gimple_opt_pass *
+make_pass_vectorize (gcc::context *ctxt)
{
- return flag_tree_parallelize_loops > 1;
+ return new pass_vectorize (ctxt);
}
-static unsigned
-tree_parallelize_loops (void)
-{
- if (number_of_loops () <= 1)
- return 0;
+/* Propagation of constants using scev. */
- if (parallelize_loops ())
- return TODO_cleanup_cfg | TODO_rebuild_alias;
- return 0;
-}
+namespace {
-struct gimple_opt_pass pass_parallelize_loops =
-{
- {
- GIMPLE_PASS,
- "parloops", /* name */
- gate_tree_parallelize_loops, /* gate */
- tree_parallelize_loops, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_PARALLELIZE_LOOPS, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
- }
+const pass_data pass_data_scev_cprop =
+{
+ GIMPLE_PASS, /* type */
+ "sccp", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_SCEV_CONST, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
-/* Prefetching. */
+class pass_scev_cprop : public gimple_opt_pass
+{
+public:
+ pass_scev_cprop (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_scev_cprop, ctxt)
+ {}
-static unsigned int
-tree_ssa_loop_prefetch (void)
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return flag_tree_scev_cprop; }
+ virtual unsigned int execute (function *);
+
+}; // class pass_scev_cprop
+
+unsigned
+pass_scev_cprop::execute (function *)
{
- if (number_of_loops () <= 1)
- return 0;
+ struct loop *loop;
+ bool any = false;
+
+ /* Perform final value replacement in loops, in case the replacement
+ expressions are cheap. */
+ FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+ any |= final_value_replacement_loop (loop);
- return tree_ssa_prefetch_arrays ();
+ return any ? TODO_cleanup_cfg | TODO_update_ssa_only_virtuals : 0;
}
-static bool
-gate_tree_ssa_loop_prefetch (void)
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_scev_cprop (gcc::context *ctxt)
{
- return flag_prefetch_loop_arrays > 0;
+ return new pass_scev_cprop (ctxt);
}
-struct gimple_opt_pass pass_loop_prefetch =
-{
- {
- GIMPLE_PASS,
- "aprefetch", /* name */
- gate_tree_ssa_loop_prefetch, /* gate */
- tree_ssa_loop_prefetch, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_PREFETCH, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
- }
+/* Induction variable optimizations. */
+
+namespace {
+
+const pass_data pass_data_iv_optimize =
+{
+ GIMPLE_PASS, /* type */
+ "ivopts", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_TREE_LOOP_IVOPTS, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_update_ssa, /* todo_flags_finish */
};
-/* Induction variable optimizations. */
+class pass_iv_optimize : public gimple_opt_pass
+{
+public:
+ pass_iv_optimize (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_iv_optimize, ctxt)
+ {}
-static unsigned int
-tree_ssa_loop_ivopts (void)
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return flag_ivopts != 0; }
+ virtual unsigned int execute (function *);
+
+}; // class pass_iv_optimize
+
+unsigned int
+pass_iv_optimize::execute (function *fun)
{
- if (number_of_loops () <= 1)
+ if (number_of_loops (fun) <= 1)
return 0;
tree_ssa_iv_optimize ();
return 0;
}
-static bool
-gate_tree_ssa_loop_ivopts (void)
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_iv_optimize (gcc::context *ctxt)
{
- return flag_ivopts != 0;
+ return new pass_iv_optimize (ctxt);
}
-struct gimple_opt_pass pass_iv_optimize =
-{
- {
- GIMPLE_PASS,
- "ivopts", /* name */
- gate_tree_ssa_loop_ivopts, /* gate */
- tree_ssa_loop_ivopts, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_LOOP_IVOPTS, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func | TODO_update_ssa | TODO_ggc_collect /* todo_flags_finish */
- }
-};
-
/* Loop optimizer finalization. */
static unsigned int
tree_ssa_loop_done (void)
{
- free_numbers_of_iterations_estimates ();
+ free_numbers_of_iterations_estimates (cfun);
scev_finalize ();
loop_optimizer_finalize ();
return 0;
}
-struct gimple_opt_pass pass_tree_loop_done =
-{
- {
- GIMPLE_PASS,
- "loopdone", /* name */
- NULL, /* gate */
- tree_ssa_loop_done, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_LOOP_FINI, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_cleanup_cfg
- | TODO_verify_flow
- | TODO_dump_func /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_tree_loop_done =
+{
+ GIMPLE_PASS, /* type */
+ "loopdone", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_cleanup_cfg, /* todo_flags_finish */
};
+
+class pass_tree_loop_done : public gimple_opt_pass
+{
+public:
+ pass_tree_loop_done (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_tree_loop_done, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual unsigned int execute (function *) { return tree_ssa_loop_done (); }
+
+}; // class pass_tree_loop_done
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_tree_loop_done (gcc::context *ctxt)
+{
+ return new pass_tree_loop_done (ctxt);
+}
+
+/* Calls CBCK for each index in memory reference ADDR_P. There are two
+ kinds situations handled; in each of these cases, the memory reference
+ and DATA are passed to the callback:
+
+ Access to an array: ARRAY_{RANGE_}REF (base, index). In this case we also
+ pass the pointer to the index to the callback.
+
+ Pointer dereference: INDIRECT_REF (addr). In this case we also pass the
+ pointer to addr to the callback.
+
+ If the callback returns false, the whole search stops and false is returned.
+ Otherwise the function returns true after traversing through the whole
+ reference *ADDR_P. */
+
+bool
+for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data)
+{
+ tree *nxt, *idx;
+
+ for (; ; addr_p = nxt)
+ {
+ switch (TREE_CODE (*addr_p))
+ {
+ case SSA_NAME:
+ return cbck (*addr_p, addr_p, data);
+
+ case MEM_REF:
+ nxt = &TREE_OPERAND (*addr_p, 0);
+ return cbck (*addr_p, nxt, data);
+
+ case BIT_FIELD_REF:
+ case VIEW_CONVERT_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ nxt = &TREE_OPERAND (*addr_p, 0);
+ break;
+
+ case COMPONENT_REF:
+ /* If the component has varying offset, it behaves like index
+ as well. */
+ idx = &TREE_OPERAND (*addr_p, 2);
+ if (*idx
+ && !cbck (*addr_p, idx, data))
+ return false;
+
+ nxt = &TREE_OPERAND (*addr_p, 0);
+ break;
+
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ nxt = &TREE_OPERAND (*addr_p, 0);
+ if (!cbck (*addr_p, &TREE_OPERAND (*addr_p, 1), data))
+ return false;
+ break;
+
+ case CONSTRUCTOR:
+ return true;
+
+ case ADDR_EXPR:
+ gcc_assert (is_gimple_min_invariant (*addr_p));
+ return true;
+
+ case TARGET_MEM_REF:
+ idx = &TMR_BASE (*addr_p);
+ if (*idx
+ && !cbck (*addr_p, idx, data))
+ return false;
+ idx = &TMR_INDEX (*addr_p);
+ if (*idx
+ && !cbck (*addr_p, idx, data))
+ return false;
+ idx = &TMR_INDEX2 (*addr_p);
+ if (*idx
+ && !cbck (*addr_p, idx, data))
+ return false;
+ return true;
+
+ default:
+ if (DECL_P (*addr_p)
+ || CONSTANT_CLASS_P (*addr_p))
+ return true;
+ gcc_unreachable ();
+ }
+ }
+}
+
+
+/* The name and the length of the currently generated variable
+ for lsm. */
+#define MAX_LSM_NAME_LENGTH 40
+static char lsm_tmp_name[MAX_LSM_NAME_LENGTH + 1];
+static int lsm_tmp_name_length;
+
+/* Adds S to lsm_tmp_name. */
+
+static void
+lsm_tmp_name_add (const char *s)
+{
+ int l = strlen (s) + lsm_tmp_name_length;
+ if (l > MAX_LSM_NAME_LENGTH)
+ return;
+
+ strcpy (lsm_tmp_name + lsm_tmp_name_length, s);
+ lsm_tmp_name_length = l;
+}
+
+/* Stores the name for temporary variable that replaces REF to
+ lsm_tmp_name. */
+
+static void
+gen_lsm_tmp_name (tree ref)
+{
+ const char *name;
+
+ switch (TREE_CODE (ref))
+ {
+ case MEM_REF:
+ case TARGET_MEM_REF:
+ gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
+ lsm_tmp_name_add ("_");
+ break;
+
+ case ADDR_EXPR:
+ gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
+ break;
+
+ case BIT_FIELD_REF:
+ case VIEW_CONVERT_EXPR:
+ case ARRAY_RANGE_REF:
+ gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
+ break;
+
+ case REALPART_EXPR:
+ gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
+ lsm_tmp_name_add ("_RE");
+ break;
+
+ case IMAGPART_EXPR:
+ gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
+ lsm_tmp_name_add ("_IM");
+ break;
+
+ case COMPONENT_REF:
+ gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
+ lsm_tmp_name_add ("_");
+ name = get_name (TREE_OPERAND (ref, 1));
+ if (!name)
+ name = "F";
+ lsm_tmp_name_add (name);
+ break;
+
+ case ARRAY_REF:
+ gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
+ lsm_tmp_name_add ("_I");
+ break;
+
+ case SSA_NAME:
+ case VAR_DECL:
+ case PARM_DECL:
+ case FUNCTION_DECL:
+ case LABEL_DECL:
+ name = get_name (ref);
+ if (!name)
+ name = "D";
+ lsm_tmp_name_add (name);
+ break;
+
+ case STRING_CST:
+ lsm_tmp_name_add ("S");
+ break;
+
+ case RESULT_DECL:
+ lsm_tmp_name_add ("R");
+ break;
+
+ case INTEGER_CST:
+ default:
+ /* Nothing. */
+ break;
+ }
+}
+
+/* Determines name for temporary variable that replaces REF.
+ The name is accumulated into the lsm_tmp_name variable.
+ N is added to the name of the temporary. */
+
+char *
+get_lsm_tmp_name (tree ref, unsigned n, const char *suffix)
+{
+ char ns[2];
+
+ lsm_tmp_name_length = 0;
+ gen_lsm_tmp_name (ref);
+ lsm_tmp_name_add ("_lsm");
+ if (n < 10)
+ {
+ ns[0] = '0' + n;
+ ns[1] = 0;
+ lsm_tmp_name_add (ns);
+ }
+ if (suffix != NULL)
+ lsm_tmp_name_add (suffix);
+ return lsm_tmp_name;
+}
+
+/* Computes an estimated number of insns in LOOP, weighted by WEIGHTS. */
+
+unsigned
+tree_num_loop_insns (struct loop *loop, eni_weights *weights)
+{
+ basic_block *body = get_loop_body (loop);
+ gimple_stmt_iterator gsi;
+ unsigned size = 0, i;
+
+ for (i = 0; i < loop->num_nodes; i++)
+ for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi))
+ size += estimate_num_insns (gsi_stmt (gsi), weights);
+ free (body);
+
+ return size;
+}
+
+
+