/* Loop optimizations over tree-ssa.
- Copyright (C) 2003-2013 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 "tree-flow.h"
+#include "gimple.h"
#include "tree-pass.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. */
namespace {
-const pass_data pass_data_tree_loop =
+const pass_data pass_data_fix_loops =
{
GIMPLE_PASS, /* type */
- "loop", /* name */
+ "fix_loops", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- false, /* has_execute */
TV_TREE_LOOP, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_verify_ssa, /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
-class pass_tree_loop : public gimple_opt_pass
+class pass_fix_loops : public gimple_opt_pass
{
public:
- pass_tree_loop(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_tree_loop, ctxt)
+ pass_fix_loops (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_fix_loops, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_tree_loop (); }
+ virtual bool gate (function *) { return flag_tree_loop_optimize; }
-}; // class pass_tree_loop
+ 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;
+}
} // anon namespace
gimple_opt_pass *
-make_pass_tree_loop (gcc::context *ctxt)
+make_pass_fix_loops (gcc::context *ctxt)
{
- return new pass_tree_loop (ctxt);
+ return new pass_fix_loops (ctxt);
}
-/* Loop optimizer initialization. */
-static unsigned int
-tree_ssa_loop_init (void)
-{
- loop_optimizer_init (LOOPS_NORMAL
- | LOOPS_HAVE_RECORDED_EXITS);
- rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+/* 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. */
- /* We might discover new loops, e.g. when turning irreducible
- regions into reducible. */
- scev_initialize ();
+static bool
+gate_loop (function *fn)
+{
+ if (!flag_tree_loop_optimize)
+ return false;
- if (number_of_loops (cfun) <= 1)
- return 0;
+ /* For -fdump-passes which runs before loop discovery print the
+ state of -ftree-loop-optimize. */
+ if (!loops_for_fn (fn))
+ return true;
- return 0;
+ return number_of_loops (fn) > 1;
}
+/* The loop superpass. */
+
namespace {
-const pass_data pass_data_tree_loop_init =
+const pass_data pass_data_tree_loop =
{
GIMPLE_PASS, /* type */
- "loopinit", /* name */
+ "loop", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- false, /* has_gate */
- true, /* has_execute */
- TV_NONE, /* tv_id */
+ TV_TREE_LOOP, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_finish */
};
-class pass_tree_loop_init : public gimple_opt_pass
+class pass_tree_loop : public gimple_opt_pass
{
public:
- pass_tree_loop_init(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_tree_loop_init, ctxt)
+ pass_tree_loop (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_tree_loop, ctxt)
{}
/* opt_pass methods: */
- unsigned int execute () { return tree_ssa_loop_init (); }
+ virtual bool gate (function *fn) { return gate_loop (fn); }
-}; // class pass_tree_loop_init
+}; // class pass_tree_loop
} // anon namespace
gimple_opt_pass *
-make_pass_tree_loop_init (gcc::context *ctxt)
+make_pass_tree_loop (gcc::context *ctxt)
{
- return new pass_tree_loop_init (ctxt);
+ return new pass_tree_loop (ctxt);
}
-/* Loop invariant motion pass. */
+/* Gate for oacc kernels pass group. */
-static unsigned int
-tree_ssa_loop_im (void)
+static bool
+gate_oacc_kernels (function *fn)
{
- if (number_of_loops (cfun) <= 1)
- return 0;
+ if (!flag_openacc)
+ return false;
- return tree_ssa_lim ();
-}
+ if (!lookup_attribute ("oacc kernels", DECL_ATTRIBUTES (fn->decl)))
+ return false;
-static bool
-gate_tree_ssa_loop_im (void)
-{
- return flag_tree_loop_im != 0;
+ struct loop *loop;
+ FOR_EACH_LOOP (loop, 0)
+ if (loop->in_oacc_kernels_region)
+ return true;
+
+ return false;
}
+/* The oacc kernels superpass. */
+
namespace {
-const pass_data pass_data_lim =
+const pass_data pass_data_oacc_kernels =
{
GIMPLE_PASS, /* type */
- "lim", /* name */
+ "oacc_kernels", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_LIM, /* tv_id */
+ TV_TREE_LOOP, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_finish */
};
-class pass_lim : public gimple_opt_pass
+class pass_oacc_kernels : public gimple_opt_pass
{
public:
- pass_lim(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_lim, ctxt)
+ pass_oacc_kernels (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_oacc_kernels, ctxt)
{}
/* opt_pass methods: */
- opt_pass * clone () { return new pass_lim (ctxt_); }
- bool gate () { return gate_tree_ssa_loop_im (); }
- unsigned int execute () { return tree_ssa_loop_im (); }
+ virtual bool gate (function *fn) { return gate_oacc_kernels (fn); }
-}; // class pass_lim
+}; // class pass_oacc_kernels
} // anon namespace
gimple_opt_pass *
-make_pass_lim (gcc::context *ctxt)
-{
- return new pass_lim (ctxt);
-}
-
-/* Loop unswitching pass. */
-
-static unsigned int
-tree_ssa_loop_unswitch (void)
+make_pass_oacc_kernels (gcc::context *ctxt)
{
- if (number_of_loops (cfun) <= 1)
- return 0;
-
- return tree_ssa_unswitch_loops ();
+ return new pass_oacc_kernels (ctxt);
}
-static bool
-gate_tree_ssa_loop_unswitch (void)
-{
- return flag_unswitch_loops != 0;
-}
+/* The ipa oacc superpass. */
namespace {
-const pass_data pass_data_tree_unswitch =
+const pass_data pass_data_ipa_oacc =
{
- GIMPLE_PASS, /* type */
- "unswitch", /* name */
+ SIMPLE_IPA_PASS, /* type */
+ "ipa_oacc", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_TREE_LOOP_UNSWITCH, /* tv_id */
+ TV_TREE_LOOP, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_finish */
};
-class pass_tree_unswitch : public gimple_opt_pass
+class pass_ipa_oacc : public simple_ipa_opt_pass
{
public:
- pass_tree_unswitch(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_tree_unswitch, ctxt)
+ pass_ipa_oacc (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_oacc, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_tree_ssa_loop_unswitch (); }
- unsigned int execute () { return tree_ssa_loop_unswitch (); }
+ virtual bool gate (function *)
+ {
+ return (optimize
+ && flag_openacc
+ /* Don't bother doing anything if the program has errors. */
+ && !seen_error ());
+ }
-}; // class pass_tree_unswitch
+}; // class pass_ipa_oacc
} // anon namespace
-gimple_opt_pass *
-make_pass_tree_unswitch (gcc::context *ctxt)
+simple_ipa_opt_pass *
+make_pass_ipa_oacc (gcc::context *ctxt)
{
- return new pass_tree_unswitch (ctxt);
+ return new pass_ipa_oacc (ctxt);
}
-/* Predictive commoning. */
-
-static unsigned
-run_tree_predictive_commoning (void)
-{
- if (!current_loops)
- return 0;
-
- return tree_predictive_commoning ();
-}
-
-static bool
-gate_tree_predictive_commoning (void)
-{
- return flag_predictive_commoning != 0;
-}
+/* The ipa oacc kernels pass. */
namespace {
-const pass_data pass_data_predcom =
+const pass_data pass_data_ipa_oacc_kernels =
{
- GIMPLE_PASS, /* type */
- "pcom", /* name */
+ SIMPLE_IPA_PASS, /* type */
+ "ipa_oacc_kernels", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_PREDCOM, /* tv_id */
+ TV_TREE_LOOP, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_update_ssa_only_virtuals, /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
-class pass_predcom : public gimple_opt_pass
+class pass_ipa_oacc_kernels : public simple_ipa_opt_pass
{
public:
- pass_predcom(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_predcom, ctxt)
+ pass_ipa_oacc_kernels (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_oacc_kernels, ctxt)
{}
- /* opt_pass methods: */
- bool gate () { return gate_tree_predictive_commoning (); }
- unsigned int execute () { return run_tree_predictive_commoning (); }
-
-}; // class pass_predcom
+}; // class pass_ipa_oacc_kernels
} // anon namespace
-gimple_opt_pass *
-make_pass_predcom (gcc::context *ctxt)
+simple_ipa_opt_pass *
+make_pass_ipa_oacc_kernels (gcc::context *ctxt)
{
- return new pass_predcom (ctxt);
-}
-
-/* Loop autovectorization. */
-
-static unsigned int
-tree_vectorize (void)
-{
- if (number_of_loops (cfun) <= 1)
- return 0;
-
- return vectorize_loops ();
+ return new pass_ipa_oacc_kernels (ctxt);
}
-static bool
-gate_tree_vectorize (void)
-{
- return flag_tree_vectorize || cfun->has_force_vect_loops;
-}
+/* The no-loop superpass. */
namespace {
-const pass_data pass_data_vectorize =
+const pass_data pass_data_tree_no_loop =
{
GIMPLE_PASS, /* type */
- "vect", /* name */
- OPTGROUP_LOOP | OPTGROUP_VEC, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_TREE_VECTORIZATION, /* tv_id */
- ( PROP_cfg | PROP_ssa ), /* properties_required */
+ "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 */
};
-class pass_vectorize : public gimple_opt_pass
+class pass_tree_no_loop : public gimple_opt_pass
{
public:
- pass_vectorize(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_vectorize, ctxt)
+ pass_tree_no_loop (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_tree_no_loop, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_tree_vectorize (); }
- unsigned int execute () { return tree_vectorize (); }
+ virtual bool gate (function *fn) { return !gate_loop (fn); }
-}; // class pass_vectorize
+}; // class pass_tree_no_loop
} // anon namespace
gimple_opt_pass *
-make_pass_vectorize (gcc::context *ctxt)
+make_pass_tree_no_loop (gcc::context *ctxt)
{
- return new pass_vectorize (ctxt);
+ return new pass_tree_no_loop (ctxt);
}
-/* GRAPHITE optimizations. */
-
-static unsigned int
-graphite_transforms (void)
-{
- if (!current_loops)
- return 0;
-
- graphite_transform_loops ();
-
- return 0;
-}
-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_optimize_isl)
- flag_graphite = 1;
-
- return flag_graphite != 0;
-}
+/* Loop optimizer initialization. */
namespace {
-const pass_data pass_data_graphite =
+const pass_data pass_data_tree_loop_init =
{
GIMPLE_PASS, /* type */
- "graphite0", /* name */
+ "loopinit", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- false, /* has_execute */
- TV_GRAPHITE, /* tv_id */
- ( PROP_cfg | PROP_ssa ), /* properties_required */
+ TV_NONE, /* tv_id */
+ PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
- 0, /* todo_flags_start */
+ TODO_update_address_taken, /* todo_flags_start */
0, /* todo_flags_finish */
};
-class pass_graphite : public gimple_opt_pass
+class pass_tree_loop_init : public gimple_opt_pass
{
public:
- pass_graphite(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_graphite, ctxt)
+ pass_tree_loop_init (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_tree_loop_init, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_graphite_transforms (); }
-
-}; // class pass_graphite
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_graphite (gcc::context *ctxt)
-{
- return new pass_graphite (ctxt);
-}
-
-namespace {
+ virtual unsigned int execute (function *);
-const pass_data pass_data_graphite_transforms =
-{
- GIMPLE_PASS, /* type */
- "graphite", /* name */
- OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_GRAPHITE_TRANSFORMS, /* tv_id */
- ( PROP_cfg | PROP_ssa ), /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
+}; // class pass_tree_loop_init
-class pass_graphite_transforms : public gimple_opt_pass
+unsigned int
+pass_tree_loop_init::execute (function *fun ATTRIBUTE_UNUSED)
{
-public:
- pass_graphite_transforms(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_graphite_transforms, ctxt)
- {}
-
- /* opt_pass methods: */
- bool gate () { return gate_graphite_transforms (); }
- unsigned int execute () { return graphite_transforms (); }
+ /* 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 ();
-}; // class pass_graphite_transforms
+ return 0;
+}
} // anon namespace
gimple_opt_pass *
-make_pass_graphite_transforms (gcc::context *ctxt)
-{
- return new pass_graphite_transforms (ctxt);
-}
-
-/* Check the correctness of the data dependence analyzers. */
-
-static unsigned int
-check_data_deps (void)
+make_pass_tree_loop_init (gcc::context *ctxt)
{
- if (number_of_loops (cfun) <= 1)
- return 0;
-
- tree_check_data_deps ();
- return 0;
+ return new pass_tree_loop_init (ctxt);
}
-static bool
-gate_check_data_deps (void)
-{
- return flag_check_data_deps != 0;
-}
+/* Loop autovectorization. */
namespace {
-const pass_data pass_data_check_data_deps =
+const pass_data pass_data_vectorize =
{
GIMPLE_PASS, /* type */
- "ckdd", /* name */
- OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_CHECK_DATA_DEPS, /* tv_id */
+ "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_finish */
};
-class pass_check_data_deps : public gimple_opt_pass
+class pass_vectorize : public gimple_opt_pass
{
public:
- pass_check_data_deps(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_check_data_deps, ctxt)
+ pass_vectorize (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_vectorize, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_check_data_deps (); }
- unsigned int execute () { return check_data_deps (); }
-
-}; // class pass_check_data_deps
+ virtual bool gate (function *fun)
+ {
+ return flag_tree_loop_vectorize || fun->has_force_vectorize_loops;
+ }
-} // anon namespace
+ virtual unsigned int execute (function *);
-gimple_opt_pass *
-make_pass_check_data_deps (gcc::context *ctxt)
-{
- return new pass_check_data_deps (ctxt);
-}
-
-/* Canonical induction variable creation pass. */
+}; // class pass_vectorize
-static unsigned int
-tree_ssa_loop_ivcanon (void)
+unsigned int
+pass_vectorize::execute (function *fun)
{
- if (number_of_loops (cfun) <= 1)
+ if (number_of_loops (fun) <= 1)
return 0;
- return canonicalize_induction_variables ();
-}
-
-static bool
-gate_tree_ssa_loop_ivcanon (void)
-{
- return flag_tree_loop_ivcanon != 0;
+ return vectorize_loops ();
}
-namespace {
-
-const pass_data pass_data_iv_canon =
-{
- GIMPLE_PASS, /* type */
- "ivcanon", /* name */
- OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_TREE_LOOP_IVCANON, /* tv_id */
- ( PROP_cfg | PROP_ssa ), /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
-
-class pass_iv_canon : public gimple_opt_pass
-{
-public:
- pass_iv_canon(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_iv_canon, ctxt)
- {}
-
- /* opt_pass methods: */
- bool gate () { return gate_tree_ssa_loop_ivcanon (); }
- unsigned int execute () { return tree_ssa_loop_ivcanon (); }
-
-}; // class pass_iv_canon
-
} // anon namespace
gimple_opt_pass *
-make_pass_iv_canon (gcc::context *ctxt)
+make_pass_vectorize (gcc::context *ctxt)
{
- return new pass_iv_canon (ctxt);
+ return new pass_vectorize (ctxt);
}
/* Propagation of constants using scev. */
-static bool
-gate_scev_const_prop (void)
-{
- return flag_tree_scev_cprop;
-}
-
namespace {
const pass_data pass_data_scev_cprop =
GIMPLE_PASS, /* type */
"sccp", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
TV_SCEV_CONST, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- ( TODO_cleanup_cfg
- | TODO_update_ssa_only_virtuals ), /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
class pass_scev_cprop : public gimple_opt_pass
{
public:
- pass_scev_cprop(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_scev_cprop, ctxt)
+ pass_scev_cprop (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_scev_cprop, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_scev_const_prop (); }
- unsigned int execute () { return scev_const_prop (); }
+ virtual bool gate (function *) { return flag_tree_scev_cprop; }
+ virtual unsigned int execute (function *);
}; // class pass_scev_cprop
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_scev_cprop (gcc::context *ctxt)
+unsigned
+pass_scev_cprop::execute (function *)
{
- return new pass_scev_cprop (ctxt);
-}
+ struct loop *loop;
+ bool any = false;
-/* Record bounds on numbers of iterations of loops. */
+ /* 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);
-static unsigned int
-tree_ssa_loop_bounds (void)
-{
- if (number_of_loops (cfun) <= 1)
- return 0;
-
- estimate_numbers_of_iterations ();
- scev_reset ();
- return 0;
+ return any ? TODO_cleanup_cfg | TODO_update_ssa_only_virtuals : 0;
}
-namespace {
-
-const pass_data pass_data_record_bounds =
-{
- GIMPLE_PASS, /* type */
- "*record_bounds", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- false, /* has_gate */
- true, /* has_execute */
- 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 */
-};
-
-class pass_record_bounds : public gimple_opt_pass
-{
-public:
- pass_record_bounds(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_record_bounds, ctxt)
- {}
-
- /* opt_pass methods: */
- unsigned int execute () { return tree_ssa_loop_bounds (); }
-
-}; // class pass_record_bounds
-
} // anon namespace
gimple_opt_pass *
-make_pass_record_bounds (gcc::context *ctxt)
-{
- return new pass_record_bounds (ctxt);
-}
-
-/* Complete unrolling of loops. */
-
-static unsigned int
-tree_complete_unroll (void)
+make_pass_scev_cprop (gcc::context *ctxt)
{
- if (number_of_loops (cfun) <= 1)
- return 0;
-
- return tree_unroll_loops_completely (flag_unroll_loops
- || flag_peel_loops
- || optimize >= 3, true);
+ return new pass_scev_cprop (ctxt);
}
-static bool
-gate_tree_complete_unroll (void)
-{
- return true;
-}
+/* Induction variable optimizations. */
namespace {
-const pass_data pass_data_complete_unroll =
+const pass_data pass_data_iv_optimize =
{
GIMPLE_PASS, /* type */
- "cunroll", /* name */
+ "ivopts", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_COMPLETE_UNROLL, /* tv_id */
+ TV_TREE_LOOP_IVOPTS, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ TODO_update_ssa, /* todo_flags_finish */
};
-class pass_complete_unroll : public gimple_opt_pass
+class pass_iv_optimize : public gimple_opt_pass
{
public:
- pass_complete_unroll(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_complete_unroll, ctxt)
+ pass_iv_optimize (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_iv_optimize, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_tree_complete_unroll (); }
- unsigned int execute () { return tree_complete_unroll (); }
-
-}; // class pass_complete_unroll
-
-} // anon namespace
+ virtual bool gate (function *) { return flag_ivopts != 0; }
+ virtual unsigned int execute (function *);
-gimple_opt_pass *
-make_pass_complete_unroll (gcc::context *ctxt)
-{
- return new pass_complete_unroll (ctxt);
-}
-
-/* Complete unrolling of inner loops. */
+}; // class pass_iv_optimize
-static unsigned int
-tree_complete_unroll_inner (void)
+unsigned int
+pass_iv_optimize::execute (function *fun)
{
- unsigned ret = 0;
-
- loop_optimizer_init (LOOPS_NORMAL
- | LOOPS_HAVE_RECORDED_EXITS);
- if (number_of_loops (cfun) > 1)
- {
- scev_initialize ();
- ret = tree_unroll_loops_completely (optimize >= 3, false);
- free_numbers_of_iterations_estimates ();
- scev_finalize ();
- }
- loop_optimizer_finalize ();
-
- return ret;
-}
+ if (number_of_loops (fun) <= 1)
+ return 0;
-static bool
-gate_tree_complete_unroll_inner (void)
-{
- return optimize >= 2;
+ tree_ssa_iv_optimize ();
+ return 0;
}
-namespace {
-
-const pass_data pass_data_complete_unrolli =
-{
- GIMPLE_PASS, /* type */
- "cunrolli", /* name */
- OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- 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_flags_finish */
-};
-
-class pass_complete_unrolli : public gimple_opt_pass
-{
-public:
- pass_complete_unrolli(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_complete_unrolli, ctxt)
- {}
-
- /* opt_pass methods: */
- bool gate () { return gate_tree_complete_unroll_inner (); }
- unsigned int execute () { return tree_complete_unroll_inner (); }
-
-}; // class pass_complete_unrolli
-
} // anon namespace
gimple_opt_pass *
-make_pass_complete_unrolli (gcc::context *ctxt)
+make_pass_iv_optimize (gcc::context *ctxt)
{
- return new pass_complete_unrolli (ctxt);
+ return new pass_iv_optimize (ctxt);
}
-/* Parallelization. */
-
-static bool
-gate_tree_parallelize_loops (void)
-{
- return flag_tree_parallelize_loops > 1;
-}
+/* Loop optimizer finalization. */
-static unsigned
-tree_parallelize_loops (void)
+static unsigned int
+tree_ssa_loop_done (void)
{
- if (number_of_loops (cfun) <= 1)
- return 0;
-
- if (parallelize_loops ())
- return TODO_cleanup_cfg | TODO_rebuild_alias;
+ free_numbers_of_iterations_estimates (cfun);
+ scev_finalize ();
+ loop_optimizer_finalize ();
return 0;
}
namespace {
-const pass_data pass_data_parallelize_loops =
+const pass_data pass_data_tree_loop_done =
{
GIMPLE_PASS, /* type */
- "parloops", /* name */
+ "loopdone", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_TREE_PARALLELIZE_LOOPS, /* tv_id */
- ( PROP_cfg | PROP_ssa ), /* properties_required */
+ TV_NONE, /* tv_id */
+ PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_verify_flow, /* todo_flags_finish */
+ TODO_cleanup_cfg, /* todo_flags_finish */
};
-class pass_parallelize_loops : public gimple_opt_pass
+class pass_tree_loop_done : public gimple_opt_pass
{
public:
- pass_parallelize_loops(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_parallelize_loops, ctxt)
+ pass_tree_loop_done (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_tree_loop_done, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_tree_parallelize_loops (); }
- unsigned int execute () { return tree_parallelize_loops (); }
+ virtual unsigned int execute (function *) { return tree_ssa_loop_done (); }
-}; // class pass_parallelize_loops
+}; // class pass_tree_loop_done
} // anon namespace
gimple_opt_pass *
-make_pass_parallelize_loops (gcc::context *ctxt)
+make_pass_tree_loop_done (gcc::context *ctxt)
{
- return new pass_parallelize_loops (ctxt);
+ return new pass_tree_loop_done (ctxt);
}
-/* Prefetching. */
+/* 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:
-static unsigned int
-tree_ssa_loop_prefetch (void)
-{
- if (number_of_loops (cfun) <= 1)
- return 0;
+ Access to an array: ARRAY_{RANGE_}REF (base, index). In this case we also
+ pass the pointer to the index to the callback.
- return tree_ssa_prefetch_arrays ();
-}
+ Pointer dereference: INDIRECT_REF (addr). In this case we also pass the
+ pointer to addr to the callback.
-static bool
-gate_tree_ssa_loop_prefetch (void)
-{
- return flag_prefetch_loop_arrays > 0;
-}
+ 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. */
-namespace {
-
-const pass_data pass_data_loop_prefetch =
+bool
+for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data)
{
- GIMPLE_PASS, /* type */
- "aprefetch", /* name */
- OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_TREE_PREFETCH, /* tv_id */
- ( PROP_cfg | PROP_ssa ), /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
-
-class pass_loop_prefetch : public gimple_opt_pass
-{
-public:
- pass_loop_prefetch(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_loop_prefetch, ctxt)
- {}
+ tree *nxt, *idx;
- /* opt_pass methods: */
- bool gate () { return gate_tree_ssa_loop_prefetch (); }
- unsigned int execute () { return tree_ssa_loop_prefetch (); }
-
-}; // class pass_loop_prefetch
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_loop_prefetch (gcc::context *ctxt)
-{
- return new pass_loop_prefetch (ctxt);
+ 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 ();
+ }
+ }
}
-/* Induction variable optimizations. */
-static unsigned int
-tree_ssa_loop_ivopts (void)
-{
- if (number_of_loops (cfun) <= 1)
- return 0;
+/* 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;
- tree_ssa_iv_optimize ();
- return 0;
-}
+/* Adds S to lsm_tmp_name. */
-static bool
-gate_tree_ssa_loop_ivopts (void)
+static void
+lsm_tmp_name_add (const char *s)
{
- return flag_ivopts != 0;
+ 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;
}
-namespace {
+/* Stores the name for temporary variable that replaces REF to
+ lsm_tmp_name. */
-const pass_data pass_data_iv_optimize =
+static void
+gen_lsm_tmp_name (tree ref)
{
- GIMPLE_PASS, /* type */
- "ivopts", /* name */
- OPTGROUP_LOOP, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- 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 */
-};
-
-class pass_iv_optimize : public gimple_opt_pass
-{
-public:
- pass_iv_optimize(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_iv_optimize, ctxt)
- {}
-
- /* opt_pass methods: */
- bool gate () { return gate_tree_ssa_loop_ivopts (); }
- unsigned int execute () { return tree_ssa_loop_ivopts (); }
-
-}; // class pass_iv_optimize
-
-} // anon namespace
+ const char *name;
-gimple_opt_pass *
-make_pass_iv_optimize (gcc::context *ctxt)
-{
- return new pass_iv_optimize (ctxt);
+ 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;
+ }
}
-/* Loop optimizer finalization. */
+/* 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. */
-static unsigned int
-tree_ssa_loop_done (void)
+char *
+get_lsm_tmp_name (tree ref, unsigned n, const char *suffix)
{
- free_numbers_of_iterations_estimates ();
- scev_finalize ();
- loop_optimizer_finalize ();
- return 0;
+ 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;
}
-namespace {
+/* Computes an estimated number of insns in LOOP, weighted by WEIGHTS. */
-const pass_data pass_data_tree_loop_done =
+unsigned
+tree_num_loop_insns (struct loop *loop, eni_weights *weights)
{
- GIMPLE_PASS, /* type */
- "loopdone", /* name */
- OPTGROUP_LOOP, /* optinfo_flags */
- false, /* has_gate */
- true, /* has_execute */
- TV_NONE, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- ( TODO_cleanup_cfg | TODO_verify_flow ), /* todo_flags_finish */
-};
+ basic_block *body = get_loop_body (loop);
+ gimple_stmt_iterator gsi;
+ unsigned size = 0, i;
-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)
- {}
+ 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);
- /* opt_pass methods: */
- unsigned int execute () { return tree_ssa_loop_done (); }
+ return size;
+}
-}; // 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);
-}