]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-loop.c
2019-06-14 Harald Anlauf <anlauf@gmx.de>
[thirdparty/gcc.git] / gcc / tree-ssa-loop.c
index 8bcfd060e60550552ed6972b23876126528c84ff..208c58354b48a3bcbee605b9aafc22eb6f7f966b 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
 
@@ -20,93 +20,105 @@ along with GCC; see the file COPYING3.  If not see
 #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 */
@@ -114,53 +126,55 @@ const pass_data pass_data_tree_loop_init =
   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 */
@@ -168,55 +182,36 @@ const pass_data pass_data_lim =
   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 */
@@ -224,269 +219,168 @@ const pass_data pass_data_tree_unswitch =
   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 */
@@ -494,90 +388,42 @@ const pass_data pass_data_check_data_deps =
   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 =
@@ -585,422 +431,364 @@ 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);
-}