]> 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 a1edb51c13d378d91ec9ba0ca2dc259e2b7e5a15..208c58354b48a3bcbee605b9aafc22eb6f7f966b 100644 (file)
@@ -1,6 +1,5 @@
 /* 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.
 
@@ -21,658 +20,775 @@ 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 "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;
+}
+
+
+