re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / passes.c
index 0f1d21436be45b0d9ebdac429ed36ff5e1159895..4966334206e1b0e834b300cbf8c8893dfa3afd00 100644 (file)
@@ -1,5 +1,5 @@
 /* Top level of GCC compilers (cc1, cc1plus, etc.)
-   Copyright (C) 1987-2013 Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -26,10 +26,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "line-map.h"
-#include "hash-table.h"
-#include "input.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
+#include "varasm.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "flags.h"
@@ -42,10 +43,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "function.h"
 #include "toplev.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
 #include "expr.h"
+#include "predict.h"
 #include "basic-block.h"
 #include "intl.h"
-#include "ggc.h"
 #include "graph.h"
 #include "regs.h"
 #include "diagnostic-core.h"
@@ -56,27 +63,97 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "hosthooks.h"
-#include "cgraph.h"
 #include "opts.h"
 #include "coverage.h"
 #include "value-prof.h"
 #include "tree-inline.h"
-#include "tree-flow.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-into-ssa.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
 #include "tree-pass.h"
 #include "tree-dump.h"
 #include "df.h"
-#include "predict.h"
+#include "cgraph.h"
 #include "lto-streamer.h"
 #include "plugin.h"
 #include "ipa-utils.h"
 #include "tree-pretty-print.h" /* for dump_function_header */
+#include "context.h"
+#include "pass_manager.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "tree-ssa-live.h"  /* For remove_unused_locals.  */
+#include "tree-cfgcleanup.h"
+
+using namespace gcc;
 
 /* This is used for debugging.  It allows the current pass to printed
    from anywhere in compilation.
    The variable current_pass is also used for statistics and plugins.  */
-struct opt_pass *current_pass;
+opt_pass *current_pass;
+
+static void register_pass_name (opt_pass *, const char *);
+
+/* Most passes are single-instance (within their context) and thus don't
+   need to implement cloning, but passes that support multiple instances
+   *must* provide their own implementation of the clone method.
+
+   Handle this by providing a default implemenation, but make it a fatal
+   error to call it.  */
+
+opt_pass *
+opt_pass::clone ()
+{
+  internal_error ("pass %s does not support cloning", name);
+}
+
+bool
+opt_pass::gate (function *)
+{
+  return true;
+}
+
+unsigned int
+opt_pass::execute (function *)
+{
+  return 0;
+}
+
+opt_pass::opt_pass (const pass_data &data, context *ctxt)
+  : pass_data (data),
+    sub (NULL),
+    next (NULL),
+    static_pass_number (0),
+    m_ctxt (ctxt)
+{
+}
+
+
+void
+pass_manager::execute_early_local_passes ()
+{
+  execute_pass_list (cfun, pass_build_ssa_passes_1->sub);
+  if (flag_check_pointer_bounds)
+    execute_pass_list (cfun, pass_chkp_instrumentation_passes_1->sub);
+  execute_pass_list (cfun, pass_local_optimization_passes_1->sub);
+}
+
+unsigned int
+pass_manager::execute_pass_mode_switching ()
+{
+  return pass_mode_switching_1->execute (cfun);
+}
 
-static void register_pass_name (struct opt_pass *, const char *);
 
 /* Call from anywhere to find out what pass this is.  Useful for
    printing out debugging information deep inside an service
@@ -123,6 +200,8 @@ rest_of_decl_compilation (tree decl,
                          int top_level,
                          int at_end)
 {
+  bool finalize = true;
+
   /* We deferred calling assemble_alias so that we could collect
      other attributes such as visibility.  Emit the alias now.  */
   if (!in_lto_p)
@@ -136,9 +215,10 @@ rest_of_decl_compilation (tree decl,
        /* A quirk of the initial implementation of aliases required that the
           user add "extern" to all of them.  Which is silly, but now
           historical.  Do note that the symbol is in fact locally defined.  */
-       if (!lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
-         DECL_EXTERNAL (decl) = 0;
+       DECL_EXTERNAL (decl) = 0;
+       TREE_STATIC (decl) = 1;
        assemble_alias (decl, alias);
+       finalize = false;
       }
   }
 
@@ -170,8 +250,8 @@ rest_of_decl_compilation (tree decl,
             rebuild it.  */
          if (in_lto_p && !at_end)
            ;
-         else if (TREE_CODE (decl) != FUNCTION_DECL)
-           varpool_finalize_decl (decl);
+         else if (finalize && TREE_CODE (decl) != FUNCTION_DECL)
+           varpool_node::finalize_decl (decl);
        }
 
 #ifdef ASM_FINISH_DECLARE_OBJECT
@@ -199,7 +279,57 @@ rest_of_decl_compilation (tree decl,
     ;
   else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)
           && TREE_STATIC (decl))
-    varpool_node_for_decl (decl);
+    varpool_node::get_create (decl);
+
+  /* Generate early debug for global variables.  Any local variables will
+     be handled by either handling reachable functions from
+     finalize_compilation_unit (and by consequence, locally scoped
+     symbols), or by rest_of_type_compilation below.
+
+     Also, pick up function prototypes, which will be mostly ignored
+     by the different early_global_decl() hooks, but will at least be
+     used by Go's hijack of the debug_hooks to implement
+     -fdump-go-spec.  */
+  if (!in_lto_p
+      && (TREE_CODE (decl) != FUNCTION_DECL
+         /* This will pick up function prototypes with no bodies,
+            which are not visible in finalize_compilation_unit()
+            while iterating with FOR_EACH_*_FUNCTION through the
+            symbol table.  */
+         || !DECL_SAVED_TREE (decl))
+
+      /* We need to check both decl_function_context and
+        current_function_decl here to make sure local extern
+        declarations end up with the correct context.
+
+        For local extern declarations, decl_function_context is
+        empty, but current_function_decl is set to the function where
+        the extern was declared .  Without the check for
+        !current_function_decl below, the local extern ends up
+        incorrectly with a top-level context.
+
+        For example:
+
+        namespace S
+        {
+          int
+          f()
+          {
+            {
+              int i = 42;
+              {
+                extern int i; // Local extern declaration.
+                return i;
+              }
+            }
+          }
+        }
+      */
+      && !decl_function_context (decl)
+      && !current_function_decl
+      && DECL_SOURCE_LOCATION (decl) != BUILTINS_LOCATION
+      && !decl_type_context (decl))
+    (*debug_hooks->early_global_decl) (decl);
 }
 
 /* Called after finishing a record, union or enumeral type.  */
@@ -220,32 +350,34 @@ rest_of_type_compilation (tree type, int toplev)
 \f
 
 void
+pass_manager::
 finish_optimization_passes (void)
 {
   int i;
   struct dump_file_info *dfi;
   char *name;
+  gcc::dump_manager *dumps = m_ctxt->get_dumps ();
 
   timevar_push (TV_DUMP);
   if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
     {
-      dump_start (pass_profile.pass.static_pass_number, NULL);
+      dumps->dump_start (pass_profile_1->static_pass_number, NULL);
       end_branch_prob ();
-      dump_finish (pass_profile.pass.static_pass_number);
+      dumps->dump_finish (pass_profile_1->static_pass_number);
     }
 
   if (optimize > 0)
     {
-      dump_start (pass_profile.pass.static_pass_number, NULL);
+      dumps->dump_start (pass_profile_1->static_pass_number, NULL);
       print_combine_total_stats ();
-      dump_finish (pass_profile.pass.static_pass_number);
+      dumps->dump_finish (pass_profile_1->static_pass_number);
     }
 
   /* Do whatever is necessary to finish printing the graphs.  */
-  for (i = TDI_end; (dfi = get_dump_file_info (i)) != NULL; ++i)
-    if (dump_initialized_p (i)
+  for (i = TDI_end; (dfi = dumps->get_dump_file_info (i)) != NULL; ++i)
+    if (dumps->dump_initialized_p (i)
        && (dfi->pflags & TDF_GRAPH) != 0
-       && (name = get_dump_file_name (i)) != NULL)
+       && (name = dumps->get_dump_file_name (i)) != NULL)
       {
        finish_graph_dump_file (name);
        free (name);
@@ -255,7 +387,7 @@ finish_optimization_passes (void)
 }
 
 static unsigned int
-execute_all_early_local_passes (void)
+execute_build_ssa_passes (void)
 {
   /* Once this pass (and its sub-passes) are complete, all functions
      will be in SSA form.  Technically this state change is happening
@@ -263,205 +395,364 @@ execute_all_early_local_passes (void)
      none of the sub-passes are IPA passes and do not create new
      functions, this is ok.  We're setting this value for the benefit
      of IPA passes that follow.  */
-  if (cgraph_state < CGRAPH_STATE_IPA_SSA)
-    cgraph_state = CGRAPH_STATE_IPA_SSA;
+  if (symtab->state < IPA_SSA)
+    symtab->state = IPA_SSA;
   return 0;
 }
 
-/* Gate: execute, or not, all of the non-trivial optimizations.  */
+namespace {
 
-static bool
-gate_all_early_local_passes (void)
-{
-         /* Don't bother doing anything if the program has errors.  */
-  return (!seen_error () && !in_lto_p);
-}
-
-struct simple_ipa_opt_pass pass_early_local_passes =
-{
- {
-  SIMPLE_IPA_PASS,
-  "early_local_cleanups",              /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_all_early_local_passes,         /* gate */
-  execute_all_early_local_passes,      /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_EARLY_LOCAL,                      /* tv_id */
-  0,                                   /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_remove_functions                        /* todo_flags_finish */
- }
+const pass_data pass_data_build_ssa_passes =
+{
+  SIMPLE_IPA_PASS, /* type */
+  "build_ssa_passes", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_EARLY_LOCAL, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  /* todo_flags_finish is executed before subpases. For this reason
+     it makes no sense to remove unreachable functions here.  */
+  0, /* todo_flags_finish */
 };
 
-/* Gate: execute, or not, all of the non-trivial optimizations.  */
+class pass_build_ssa_passes : public simple_ipa_opt_pass
+{
+public:
+  pass_build_ssa_passes (gcc::context *ctxt)
+    : simple_ipa_opt_pass (pass_data_build_ssa_passes, ctxt)
+  {}
 
-static bool
-gate_all_early_optimizations (void)
-{
-  return (optimize >= 1
-         /* Don't bother doing anything if the program has errors.  */
-         && !seen_error ());
-}
-
-static struct gimple_opt_pass pass_all_early_optimizations =
-{
- {
-  GIMPLE_PASS,
-  "early_optimizations",               /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_all_early_optimizations,                /* gate */
-  NULL,                                        /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_NONE,                             /* tv_id */
-  0,                                   /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
- }
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      /* Don't bother doing anything if the program has errors.  */
+      return (!seen_error () && !in_lto_p);
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return execute_build_ssa_passes ();
+    }
+
+}; // class pass_build_ssa_passes
+
+const pass_data pass_data_chkp_instrumentation_passes =
+{
+  SIMPLE_IPA_PASS, /* type */
+  "chkp_passes", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
-/* Gate: execute, or not, all of the non-trivial optimizations.  */
+class pass_chkp_instrumentation_passes : public simple_ipa_opt_pass
+{
+public:
+  pass_chkp_instrumentation_passes (gcc::context *ctxt)
+    : simple_ipa_opt_pass (pass_data_chkp_instrumentation_passes, ctxt)
+  {}
 
-static bool
-gate_all_optimizations (void)
-{
-  return optimize >= 1 && !optimize_debug;
-}
-
-static struct gimple_opt_pass pass_all_optimizations =
-{
- {
-  GIMPLE_PASS,
-  "*all_optimizations",                        /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_all_optimizations,              /* gate */
-  NULL,                                        /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_OPTIMIZE,                         /* tv_id */
-  0,                                   /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
- }
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      /* Don't bother doing anything if the program has errors.  */
+      return (flag_check_pointer_bounds
+             && !seen_error () && !in_lto_p);
+    }
+
+}; // class pass_chkp_instrumentation_passes
+
+const pass_data pass_data_local_optimization_passes =
+{
+  SIMPLE_IPA_PASS, /* type */
+  "opt_local_passes", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
-/* Gate: execute, or not, all of the non-trivial optimizations.  */
+class pass_local_optimization_passes : public simple_ipa_opt_pass
+{
+public:
+  pass_local_optimization_passes (gcc::context *ctxt)
+    : simple_ipa_opt_pass (pass_data_local_optimization_passes, ctxt)
+  {}
 
-static bool
-gate_all_optimizations_g (void)
-{
-  return optimize >= 1 && optimize_debug;
-}
-
-static struct gimple_opt_pass pass_all_optimizations_g =
-{
- {
-  GIMPLE_PASS,
-  "*all_optimizations_g",              /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_all_optimizations_g,            /* gate */
-  NULL,                                        /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_OPTIMIZE,                         /* tv_id */
-  0,                                   /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
- }
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      /* Don't bother doing anything if the program has errors.  */
+      return (!seen_error () && !in_lto_p);
+    }
+
+}; // class pass_local_optimization_passes
+
+} // anon namespace
+
+simple_ipa_opt_pass *
+make_pass_build_ssa_passes (gcc::context *ctxt)
+{
+  return new pass_build_ssa_passes (ctxt);
+}
+
+simple_ipa_opt_pass *
+make_pass_chkp_instrumentation_passes (gcc::context *ctxt)
+{
+  return new pass_chkp_instrumentation_passes (ctxt);
+}
+
+simple_ipa_opt_pass *
+make_pass_local_optimization_passes (gcc::context *ctxt)
+{
+  return new pass_local_optimization_passes (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_all_early_optimizations =
+{
+  GIMPLE_PASS, /* type */
+  "early_optimizations", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
-static bool
-gate_rest_of_compilation (void)
-{
-  /* Early return if there were errors.  We can run afoul of our
-     consistency checks, and there's not really much point in fixing them.  */
-  return !(rtl_dump_and_exit || flag_syntax_only || seen_error ());
-}
-
-static struct rtl_opt_pass pass_rest_of_compilation =
-{
- {
-  RTL_PASS,
-  "*rest_of_compilation",               /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_rest_of_compilation,             /* gate */
-  NULL,                                 /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_REST_OF_COMPILATION,               /* tv_id */
-  PROP_rtl,                             /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
- }
+class pass_all_early_optimizations : public gimple_opt_pass
+{
+public:
+  pass_all_early_optimizations (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_all_early_optimizations, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      return (optimize >= 1
+             /* Don't bother doing anything if the program has errors.  */
+             && !seen_error ());
+    }
+
+}; // class pass_all_early_optimizations
+
+} // anon namespace
+
+static gimple_opt_pass *
+make_pass_all_early_optimizations (gcc::context *ctxt)
+{
+  return new pass_all_early_optimizations (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_all_optimizations =
+{
+  GIMPLE_PASS, /* type */
+  "*all_optimizations", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_OPTIMIZE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
-static bool
-gate_postreload (void)
-{
-  return reload_completed;
-}
-
-static struct rtl_opt_pass pass_postreload =
-{
- {
-  RTL_PASS,
-  "*all-postreload",                        /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_postreload,                      /* gate */
-  NULL,                                 /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_POSTRELOAD,                        /* tv_id */
-  PROP_rtl,                             /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_verify_rtl_sharing               /* todo_flags_finish */
- }
+class pass_all_optimizations : public gimple_opt_pass
+{
+public:
+  pass_all_optimizations (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_all_optimizations, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return optimize >= 1 && !optimize_debug; }
+
+}; // class pass_all_optimizations
+
+} // anon namespace
+
+static gimple_opt_pass *
+make_pass_all_optimizations (gcc::context *ctxt)
+{
+  return new pass_all_optimizations (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_all_optimizations_g =
+{
+  GIMPLE_PASS, /* type */
+  "*all_optimizations_g", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_OPTIMIZE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_all_optimizations_g : public gimple_opt_pass
+{
+public:
+  pass_all_optimizations_g (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_all_optimizations_g, ctxt)
+  {}
 
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return optimize >= 1 && optimize_debug; }
 
-/* The root of the compilation pass tree, once constructed.  */
-struct opt_pass *all_passes, *all_small_ipa_passes, *all_lowering_passes,
-  *all_regular_ipa_passes, *all_late_ipa_passes, *all_lto_gen_passes;
+}; // class pass_all_optimizations_g
+
+} // anon namespace
+
+static gimple_opt_pass *
+make_pass_all_optimizations_g (gcc::context *ctxt)
+{
+  return new pass_all_optimizations_g (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_rest_of_compilation =
+{
+  RTL_PASS, /* type */
+  "*rest_of_compilation", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_REST_OF_COMPILATION, /* tv_id */
+  PROP_rtl, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_rest_of_compilation : public rtl_opt_pass
+{
+public:
+  pass_rest_of_compilation (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_rest_of_compilation, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      /* Early return if there were errors.  We can run afoul of our
+        consistency checks, and there's not really much point in fixing them.  */
+      return !(rtl_dump_and_exit || flag_syntax_only || seen_error ());
+    }
+
+}; // class pass_rest_of_compilation
+
+} // anon namespace
+
+static rtl_opt_pass *
+make_pass_rest_of_compilation (gcc::context *ctxt)
+{
+  return new pass_rest_of_compilation (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_postreload =
+{
+  RTL_PASS, /* type */
+  "*all-postreload", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_POSTRELOAD, /* tv_id */
+  PROP_rtl, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_postreload : public rtl_opt_pass
+{
+public:
+  pass_postreload (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_postreload, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return reload_completed; }
+
+}; // class pass_postreload
+
+} // anon namespace
+
+static rtl_opt_pass *
+make_pass_postreload (gcc::context *ctxt)
+{
+  return new pass_postreload (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_late_compilation =
+{
+  RTL_PASS, /* type */
+  "*all-late_compilation", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_LATE_COMPILATION, /* tv_id */
+  PROP_rtl, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_late_compilation : public rtl_opt_pass
+{
+public:
+  pass_late_compilation (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_late_compilation, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+  {
+    return reload_completed || targetm.no_register_allocation;
+  }
+
+}; // class pass_late_compilation
+
+} // anon namespace
+
+static rtl_opt_pass *
+make_pass_late_compilation (gcc::context *ctxt)
+{
+  return new pass_late_compilation (ctxt);
+}
 
-/* This is used by plugins, and should also be used in register_pass.  */
-#define DEF_PASS_LIST(LIST) &LIST,
-struct opt_pass **gcc_pass_lists[] = { GCC_PASS_LISTS NULL };
-#undef DEF_PASS_LIST
 
-/* A map from static pass id to optimization pass.  */
-struct opt_pass **passes_by_id;
-int passes_by_id_size;
 
 /* Set the static pass number of pass PASS to ID and record that
    in the mapping from static pass number to pass.  */
 
-static void
-set_pass_for_id (int id, struct opt_pass *pass)
+void
+pass_manager::
+set_pass_for_id (int id, opt_pass *pass)
 {
   pass->static_pass_number = id;
   if (passes_by_id_size <= id)
     {
-      passes_by_id = XRESIZEVEC (struct opt_pass *, passes_by_id, id + 1);
+      passes_by_id = XRESIZEVEC (opt_pass *, passes_by_id, id + 1);
       memset (passes_by_id + passes_by_id_size, 0,
              (id + 1 - passes_by_id_size) * sizeof (void *));
       passes_by_id_size = id + 1;
@@ -471,8 +762,8 @@ set_pass_for_id (int id, struct opt_pass *pass)
 
 /* Return the pass with the static pass number ID.  */
 
-struct opt_pass *
-get_pass_for_id (int id)
+opt_pass *
+pass_manager::get_pass_for_id (int id) const
 {
   if (id >= passes_by_id_size)
     return NULL;
@@ -484,13 +775,20 @@ get_pass_for_id (int id)
    enabled or not.  */
 
 void
-register_one_dump_file (struct opt_pass *pass)
+register_one_dump_file (opt_pass *pass)
+{
+  g->get_passes ()->register_one_dump_file (pass);
+}
+
+void
+pass_manager::register_one_dump_file (opt_pass *pass)
 {
   char *dot_name, *flag_name, *glob_name;
   const char *name, *full_name, *prefix;
   char num[10];
   int flags, id;
   int optgroup_flags = OPTGROUP_NONE;
+  gcc::dump_manager *dumps = m_ctxt->get_dumps ();
 
   /* See below in next_pass_1.  */
   num[0] = '\0';
@@ -526,112 +824,53 @@ register_one_dump_file (struct opt_pass *pass)
   flag_name = concat (prefix, name, num, NULL);
   glob_name = concat (prefix, name, NULL);
   optgroup_flags |= pass->optinfo_flags;
-  id = dump_register (dot_name, flag_name, glob_name, flags, optgroup_flags);
+  /* For any passes that do not have an optgroup set, and which are not
+     IPA passes setup above, set the optgroup to OPTGROUP_OTHER so that
+     any dump messages are emitted properly under -fopt-info(-optall).  */
+  if (optgroup_flags == OPTGROUP_NONE)
+    optgroup_flags = OPTGROUP_OTHER;
+  id = dumps->dump_register (dot_name, flag_name, glob_name, flags,
+                            optgroup_flags,
+                            true);
   set_pass_for_id (id, pass);
   full_name = concat (prefix, pass->name, num, NULL);
   register_pass_name (pass, full_name);
   free (CONST_CAST (char *, full_name));
 }
 
-/* Recursive worker function for register_dump_files.  */
+/* Register the dump files for the pass_manager starting at PASS. */
 
-static int
-register_dump_files_1 (struct opt_pass *pass, int properties)
+void
+pass_manager::register_dump_files (opt_pass *pass)
 {
   do
     {
-      int new_properties = (properties | pass->properties_provided)
-                          & ~pass->properties_destroyed;
-
       if (pass->name && pass->name[0] != '*')
         register_one_dump_file (pass);
 
       if (pass->sub)
-        new_properties = register_dump_files_1 (pass->sub, new_properties);
-
-      /* If we have a gate, combine the properties that we could have with
-         and without the pass being examined.  */
-      if (pass->gate)
-        properties &= new_properties;
-      else
-        properties = new_properties;
+        register_dump_files (pass->sub);
 
       pass = pass->next;
     }
   while (pass);
-
-  return properties;
-}
-
-/* Register the dump files for the pipeline starting at PASS.
-   PROPERTIES reflects the properties that are guaranteed to be available at
-   the beginning of the pipeline.  */
-
-static void
-register_dump_files (struct opt_pass *pass,int properties)
-{
-  pass->properties_required |= properties;
-  register_dump_files_1 (pass, properties);
-}
-
-struct pass_registry
-{
-  const char* unique_name;
-  struct opt_pass *pass;
-};
-
-/* Helper for pass_registry hash table.  */
-
-struct pass_registry_hasher : typed_noop_remove <pass_registry>
-{
-  typedef pass_registry value_type;
-  typedef pass_registry compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
-};
-
-/* Pass registry hash function.  */
-
-inline hashval_t
-pass_registry_hasher::hash (const value_type *s)
-{
-  return htab_hash_string (s->unique_name);
-}
-
-/* Hash equal function  */
-
-inline bool
-pass_registry_hasher::equal (const value_type *s1, const compare_type *s2)
-{
-  return !strcmp (s1->unique_name, s2->unique_name);
 }
 
-static hash_table <pass_registry_hasher> name_to_pass_map;
+static hash_map<nofree_string_hash, opt_pass *> *name_to_pass_map;
 
 /* Register PASS with NAME.  */
 
 static void
-register_pass_name (struct opt_pass *pass, const char *name)
+register_pass_name (opt_pass *pass, const char *name)
 {
-  struct pass_registry **slot;
-  struct pass_registry pr;
-
-  if (!name_to_pass_map.is_created ())
-    name_to_pass_map.create (256);
-
-  pr.unique_name = name;
-  slot = name_to_pass_map.find_slot (&pr, INSERT);
-  if (!*slot)
-    {
-      struct pass_registry *new_pr;
+  if (!name_to_pass_map)
+    name_to_pass_map = new hash_map<nofree_string_hash, opt_pass *> (256);
 
-      new_pr = XCNEW (struct pass_registry);
-      new_pr->unique_name = xstrdup (name);
-      new_pr->pass = pass;
-      *slot = new_pr;
-    }
-  else
+  if (name_to_pass_map->get (name))
     return; /* Ignore plugin passes.  */
+
+      const char *unique_name = xstrdup (name);
+      name_to_pass_map->put (unique_name, pass);
 }
 
 /* Map from pass id to canonicalized pass name.  */
@@ -641,15 +880,13 @@ static vec<char_ptr> pass_tab = vNULL;
 
 /* Callback function for traversing NAME_TO_PASS_MAP.  */
 
-int
-passes_pass_traverse (pass_registry **p, void *data ATTRIBUTE_UNUSED)
+bool
+passes_pass_traverse (const char *const &name, opt_pass *const &pass, void *)
 {
-  struct opt_pass *pass = (*p)->pass;
-
   gcc_assert (pass->static_pass_number > 0);
   gcc_assert (pass_tab.exists ());
 
-  pass_tab[pass->static_pass_number] = (*p)->unique_name;
+  pass_tab[pass->static_pass_number] = name;
 
   return 1;
 }
@@ -663,23 +900,23 @@ create_pass_tab (void)
   if (!flag_dump_passes)
     return;
 
-  pass_tab.safe_grow_cleared (passes_by_id_size + 1);
-  name_to_pass_map.traverse <void *, passes_pass_traverse> (NULL);
+  pass_tab.safe_grow_cleared (g->get_passes ()->passes_by_id_size + 1);
+  name_to_pass_map->traverse <void *, passes_pass_traverse> (NULL);
 }
 
-static bool override_gate_status (struct opt_pass *, tree, bool);
+static bool override_gate_status (opt_pass *, tree, bool);
 
 /* Dump the instantiated name for PASS. IS_ON indicates if PASS
    is turned on or not.  */
 
 static void
-dump_one_pass (struct opt_pass *pass, int pass_indent)
+dump_one_pass (opt_pass *pass, int pass_indent)
 {
   int indent = 3 * pass_indent;
   const char *pn;
   bool is_on, is_really_on;
 
-  is_on = (pass->gate == NULL) ? true : pass->gate();
+  is_on = pass->gate (cfun);
   is_really_on = override_gate_status (pass, current_function_decl, is_on);
 
   if (pass->static_pass_number <= 0)
@@ -697,7 +934,7 @@ dump_one_pass (struct opt_pass *pass, int pass_indent)
 /* Dump pass list PASS with indentation INDENT.  */
 
 static void
-dump_pass_list (struct opt_pass *pass, int indent)
+dump_pass_list (opt_pass *pass, int indent)
 {
   do
     {
@@ -714,47 +951,35 @@ dump_pass_list (struct opt_pass *pass, int indent)
 void
 dump_passes (void)
 {
-  struct cgraph_node *n, *node = NULL;
-
-  create_pass_tab();
-
-  FOR_EACH_DEFINED_FUNCTION (n)
-    if (DECL_STRUCT_FUNCTION (n->symbol.decl))
-      {
-       node = n;
-       break;
-      }
+  g->get_passes ()->dump_passes ();
+}
 
-  if (!node)
-    return;
+void
+pass_manager::dump_passes () const
+{
+  push_dummy_function (true);
 
-  push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
+  create_pass_tab ();
 
   dump_pass_list (all_lowering_passes, 1);
   dump_pass_list (all_small_ipa_passes, 1);
   dump_pass_list (all_regular_ipa_passes, 1);
-  dump_pass_list (all_lto_gen_passes, 1);
   dump_pass_list (all_late_ipa_passes, 1);
   dump_pass_list (all_passes, 1);
 
-  pop_cfun ();
+  pop_dummy_function ();
 }
 
-
 /* Returns the pass with NAME.  */
 
-static struct opt_pass *
+static opt_pass *
 get_pass_by_name (const char *name)
 {
-  struct pass_registry **slot, pr;
-
-  pr.unique_name = name;
-  slot = name_to_pass_map.find_slot (&pr, NO_INSERT);
+  opt_pass **p = name_to_pass_map->get (name);
+  if (p)
+    return *p;
 
-  if (!slot || !*slot)
-    return NULL;
-
-  return (*slot)->pass;
+  return NULL;
 }
 
 
@@ -790,7 +1015,7 @@ static vec<uid_range_p>
 static void
 enable_disable_pass (const char *arg, bool is_enable)
 {
-  struct opt_pass *pass;
+  opt_pass *pass;
   char *range_str, *phase_name;
   char *argstr = xstrdup (arg);
   vec<uid_range_p> *tab = 0;
@@ -973,7 +1198,7 @@ disable_pass (const char *arg)
 /* Returns true if PASS is explicitly enabled/disabled for FUNC.  */
 
 static bool
-is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
+is_pass_explicitly_enabled_or_disabled (opt_pass *pass,
                                        tree func,
                                        vec<uid_range_p> tab)
 {
@@ -990,7 +1215,7 @@ is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
   if (!slot)
     return false;
 
-  cgraph_uid = func ? cgraph_get_node (func)->uid : 0;
+  cgraph_uid = func ? cgraph_node::get (func)->uid : 0;
   if (func && DECL_ASSEMBLER_NAME_SET_P (func))
     aname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func));
 
@@ -1009,68 +1234,76 @@ is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
   return false;
 }
 
-/* Look at the static_pass_number and duplicate the pass
-   if it is already added to a list. */
 
-static struct opt_pass *
-make_pass_instance (struct opt_pass *pass, bool track_duplicates)
-{
-  /* A nonzero static_pass_number indicates that the
-     pass is already in the list.  */
-  if (pass->static_pass_number)
-    {
-      struct opt_pass *new_pass;
+/* Update static_pass_number for passes (and the flag
+   TODO_mark_first_instance).
 
-      if (pass->type == GIMPLE_PASS
-          || pass->type == RTL_PASS
-          || pass->type == SIMPLE_IPA_PASS)
-        {
-          new_pass = XNEW (struct opt_pass);
-          memcpy (new_pass, pass, sizeof (struct opt_pass));
-        }
-      else if (pass->type == IPA_PASS)
-        {
-          new_pass = (struct opt_pass *)XNEW (struct ipa_opt_pass_d);
-          memcpy (new_pass, pass, sizeof (struct ipa_opt_pass_d));
-        }
-      else
-        gcc_unreachable ();
+   Passes are constructed with static_pass_number preinitialized to 0
+
+   This field is used in two different ways: initially as instance numbers
+   of their kind, and then as ids within the entire pass manager.
+
+   Within pass_manager::pass_manager:
+
+   * In add_pass_instance(), as called by next_pass_1 in
+     NEXT_PASS in init_optimization_passes
 
-      new_pass->next = NULL;
+   * When the initial instance of a pass within a pass manager is seen,
+     it is flagged, and its static_pass_number is set to -1
 
+   * On subsequent times that it is seen, the static pass number
+     is decremented each time, so that if there are e.g. 4 dups,
+     they have static_pass_number -4, 2, 3, 4 respectively (note
+     how the initial one is negative and gives the count); these
+     can be thought of as instance numbers of the specific pass
+
+   * Within the register_dump_files () traversal, set_pass_for_id()
+     is called on each pass, using these instance numbers to create
+     dumpfile switches, and then overwriting them with a pass id,
+     which are global to the whole pass manager (based on
+     (TDI_end + current value of extra_dump_files_in_use) )  */
+
+static void
+add_pass_instance (opt_pass *new_pass, bool track_duplicates,
+                  opt_pass *initial_pass)
+{
+  /* Are we dealing with the first pass of its kind, or a clone?  */
+  if (new_pass != initial_pass)
+    {
+      /* We're dealing with a clone.  */
       new_pass->todo_flags_start &= ~TODO_mark_first_instance;
 
       /* Indicate to register_dump_files that this pass has duplicates,
          and so it should rename the dump file.  The first instance will
          be -1, and be number of duplicates = -static_pass_number - 1.
          Subsequent instances will be > 0 and just the duplicate number.  */
-      if ((pass->name && pass->name[0] != '*') || track_duplicates)
+      if ((new_pass->name && new_pass->name[0] != '*') || track_duplicates)
         {
-          pass->static_pass_number -= 1;
-          new_pass->static_pass_number = -pass->static_pass_number;
+          initial_pass->static_pass_number -= 1;
+          new_pass->static_pass_number = -initial_pass->static_pass_number;
        }
-      return new_pass;
     }
   else
     {
-      pass->todo_flags_start |= TODO_mark_first_instance;
-      pass->static_pass_number = -1;
+      /* We're dealing with the first pass of its kind.  */
+      new_pass->todo_flags_start |= TODO_mark_first_instance;
+      new_pass->static_pass_number = -1;
 
-      invoke_plugin_callbacks (PLUGIN_NEW_PASS, pass);
+      invoke_plugin_callbacks (PLUGIN_NEW_PASS, new_pass);
     }
-  return pass;
 }
 
 /* Add a pass to the pass list. Duplicate the pass if it's already
    in the list.  */
 
-static struct opt_pass **
-next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
+static opt_pass **
+next_pass_1 (opt_pass **list, opt_pass *pass, opt_pass *initial_pass)
 {
   /* Every pass should have a name so that plugins can refer to them.  */
   gcc_assert (pass->name != NULL);
 
-  *list = make_pass_instance (pass, false);
+  add_pass_instance (pass, false, initial_pass);
+  *list = pass;
 
   return &(*list)->next;
 }
@@ -1084,7 +1317,7 @@ next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
 
 struct pass_list_node
 {
-  struct opt_pass *pass;
+  opt_pass *pass;
   struct pass_list_node *next;
 };
 
@@ -1098,10 +1331,9 @@ static struct pass_list_node *prev_added_pass_node;
    PASS_LIST - root of the pass list to insert the new pass to  */
 
 static bool
-position_pass (struct register_pass_info *new_pass_info,
-               struct opt_pass **pass_list)
+position_pass (struct register_pass_info *new_pass_info, opt_pass **pass_list)
 {
-  struct opt_pass *pass = *pass_list, *prev_pass = NULL;
+  opt_pass *pass = *pass_list, *prev_pass = NULL;
   bool success = false;
 
   for ( ; pass; prev_pass = pass, pass = pass->next)
@@ -1117,10 +1349,19 @@ position_pass (struct register_pass_info *new_pass_info,
               || (new_pass_info->ref_pass_instance_number == 1
                   && pass->todo_flags_start & TODO_mark_first_instance)))
         {
-          struct opt_pass *new_pass;
+          opt_pass *new_pass;
           struct pass_list_node *new_pass_node;
 
-         new_pass = make_pass_instance (new_pass_info->pass, true);
+         if (new_pass_info->ref_pass_instance_number == 0)
+           {
+             new_pass = new_pass_info->pass->clone ();
+             add_pass_instance (new_pass, true, new_pass_info->pass);
+           }
+         else
+           {
+             new_pass = new_pass_info->pass;
+             add_pass_instance (new_pass, true, new_pass);
+           }
 
           /* Insert the new pass instance based on the positioning op.  */
           switch (new_pass_info->pos_op)
@@ -1187,21 +1428,42 @@ position_pass (struct register_pass_info *new_pass_info,
 
 void
 register_pass (struct register_pass_info *pass_info)
+{
+  g->get_passes ()->register_pass (pass_info);
+}
+
+void
+register_pass (opt_pass* pass, pass_positioning_ops pos,
+              const char* ref_pass_name, int ref_pass_inst_number)
+{
+  register_pass_info i;
+  i.pass = pass;
+  i.reference_pass_name = ref_pass_name;
+  i.ref_pass_instance_number = ref_pass_inst_number;
+  i.pos_op = pos;
+
+  g->get_passes ()->register_pass (&i);
+}
+
+void
+pass_manager::register_pass (struct register_pass_info *pass_info)
 {
   bool all_instances, success;
+  gcc::dump_manager *dumps = m_ctxt->get_dumps ();
 
   /* The checks below could fail in buggy plugins.  Existing GCC
      passes should never fail these checks, so we mention plugin in
      the messages.  */
   if (!pass_info->pass)
-      fatal_error ("plugin cannot register a missing pass");
+      fatal_error (input_location, "plugin cannot register a missing pass");
 
   if (!pass_info->pass->name)
-      fatal_error ("plugin cannot register an unnamed pass");
+      fatal_error (input_location, "plugin cannot register an unnamed pass");
 
   if (!pass_info->reference_pass_name)
       fatal_error
-       ("plugin cannot register pass %qs without reference pass name",
+       (input_location,
+        "plugin cannot register pass %qs without reference pass name",
         pass_info->pass->name);
 
   /* Try to insert the new pass to the pass lists.  We need to check
@@ -1213,15 +1475,14 @@ register_pass (struct register_pass_info *pass_info)
     success |= position_pass (pass_info, &all_small_ipa_passes);
   if (!success || all_instances)
     success |= position_pass (pass_info, &all_regular_ipa_passes);
-  if (!success || all_instances)
-    success |= position_pass (pass_info, &all_lto_gen_passes);
   if (!success || all_instances)
     success |= position_pass (pass_info, &all_late_ipa_passes);
   if (!success || all_instances)
     success |= position_pass (pass_info, &all_passes);
   if (!success)
     fatal_error
-      ("pass %qs not found but is referenced by new pass %qs",
+      (input_location,
+       "pass %qs not found but is referenced by new pass %qs",
        pass_info->reference_pass_name, pass_info->pass->name);
 
   /* OK, we have successfully inserted the new pass. We need to register
@@ -1246,9 +1507,9 @@ register_pass (struct register_pass_info *pass_info)
       else
         tdi = TDI_rtl_all;
       /* Check if dump-all flag is specified.  */
-      if (get_dump_file_info (tdi)->pstate)
-        get_dump_file_info (added_pass_nodes->pass->static_pass_number)
-            ->pstate = get_dump_file_info (tdi)->pstate;
+      if (dumps->get_dump_file_info (tdi)->pstate)
+        dumps->get_dump_file_info (added_pass_nodes->pass->static_pass_number)
+            ->pstate = dumps->get_dump_file_info (tdi)->pstate;
       XDELETE (added_pass_nodes);
       added_pass_nodes = next_node;
     }
@@ -1277,423 +1538,104 @@ register_pass (struct register_pass_info *pass_info)
                                        -> all_passes
 */
 
+void *
+pass_manager::operator new (size_t sz)
+{
+  /* Ensure that all fields of the pass manager are zero-initialized.  */
+  return xcalloc (1, sz);
+}
+
 void
-init_optimization_passes (void)
-{
-  struct opt_pass **p;
-
-#define NEXT_PASS(PASS)  (p = next_pass_1 (p, &((PASS).pass)))
-
- /* All passes needed to lower the function into shape optimizers can
-    operate on.  These passes are always run first on the function, but
-    backend might produce already lowered functions that are not processed
-    by these passes.  */
-  p = &all_lowering_passes;
-  NEXT_PASS (pass_warn_unused_result);
-  NEXT_PASS (pass_diagnose_omp_blocks);
-  NEXT_PASS (pass_diagnose_tm_blocks);
-  NEXT_PASS (pass_mudflap_1);
-  NEXT_PASS (pass_lower_omp);
-  NEXT_PASS (pass_lower_cf);
-  NEXT_PASS (pass_lower_tm);
-  NEXT_PASS (pass_refactor_eh);
-  NEXT_PASS (pass_lower_eh);
-  NEXT_PASS (pass_build_cfg);
-  NEXT_PASS (pass_warn_function_return);
-  NEXT_PASS (pass_build_cgraph_edges);
-  *p = NULL;
+pass_manager::operator delete (void *ptr)
+{
+  free (ptr);
+}
 
-  /* Interprocedural optimization passes.  */
-  p = &all_small_ipa_passes;
-  NEXT_PASS (pass_ipa_free_lang_data);
-  NEXT_PASS (pass_ipa_function_and_variable_visibility);
-  NEXT_PASS (pass_early_local_passes);
-    {
-      struct opt_pass **p = &pass_early_local_passes.pass.sub;
-      NEXT_PASS (pass_fixup_cfg);
-      NEXT_PASS (pass_init_datastructures);
-      NEXT_PASS (pass_expand_omp);
-
-      NEXT_PASS (pass_build_ssa);
-      NEXT_PASS (pass_early_warn_uninitialized);
-      NEXT_PASS (pass_rebuild_cgraph_edges);
-      NEXT_PASS (pass_inline_parameters);
-      NEXT_PASS (pass_early_inline);
-      NEXT_PASS (pass_all_early_optimizations);
-       {
-         struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
-         NEXT_PASS (pass_remove_cgraph_callee_edges);
-         NEXT_PASS (pass_rename_ssa_copies);
-         NEXT_PASS (pass_ccp);
-         /* After CCP we rewrite no longer addressed locals into SSA
-            form if possible.  */
-         NEXT_PASS (pass_forwprop);
-         /* pass_build_ealias is a dummy pass that ensures that we
-            execute TODO_rebuild_alias at this point.  */
-         NEXT_PASS (pass_build_ealias);
-         NEXT_PASS (pass_sra_early);
-         NEXT_PASS (pass_fre);
-         NEXT_PASS (pass_copy_prop);
-         NEXT_PASS (pass_merge_phi);
-         NEXT_PASS (pass_cd_dce);
-         NEXT_PASS (pass_early_ipa_sra);
-         NEXT_PASS (pass_tail_recursion);
-         NEXT_PASS (pass_convert_switch);
-          NEXT_PASS (pass_cleanup_eh);
-          NEXT_PASS (pass_profile);
-          NEXT_PASS (pass_local_pure_const);
-         /* Split functions creates parts that are not run through
-            early optimizations again.  It is thus good idea to do this
-            late.  */
-          NEXT_PASS (pass_split_functions);
-       }
-      NEXT_PASS (pass_release_ssa_names);
-      NEXT_PASS (pass_rebuild_cgraph_edges);
-      NEXT_PASS (pass_inline_parameters);
-    }
-  NEXT_PASS (pass_ipa_free_inline_summary);
-  NEXT_PASS (pass_ipa_tree_profile);
-    {
-      struct opt_pass **p = &pass_ipa_tree_profile.pass.sub;
-      NEXT_PASS (pass_feedback_split_functions);
-    }
-  NEXT_PASS (pass_ipa_increase_alignment);
-  NEXT_PASS (pass_ipa_tm);
-  NEXT_PASS (pass_ipa_lower_emutls);
-  *p = NULL;
+pass_manager::pass_manager (context *ctxt)
+: all_passes (NULL), all_small_ipa_passes (NULL), all_lowering_passes (NULL),
+  all_regular_ipa_passes (NULL),
+  all_late_ipa_passes (NULL), passes_by_id (NULL), passes_by_id_size (0),
+  m_ctxt (ctxt)
+{
+  opt_pass **p;
 
-  p = &all_regular_ipa_passes;
-  NEXT_PASS (pass_ipa_whole_program_visibility);
-  NEXT_PASS (pass_ipa_profile);
-  NEXT_PASS (pass_ipa_cp);
-  NEXT_PASS (pass_ipa_cdtor_merge);
-  NEXT_PASS (pass_ipa_inline);
-  NEXT_PASS (pass_ipa_pure_const);
-  NEXT_PASS (pass_ipa_reference);
-  *p = NULL;
+  /* Initialize the pass_lists array.  */
+#define DEF_PASS_LIST(LIST) pass_lists[PASS_LIST_NO_##LIST] = &LIST;
+  GCC_PASS_LISTS
+#undef DEF_PASS_LIST
 
-  p = &all_lto_gen_passes;
-  NEXT_PASS (pass_ipa_lto_gimple_out);
-  NEXT_PASS (pass_ipa_lto_finish_out);  /* This must be the last LTO pass.  */
-  *p = NULL;
+  /* Build the tree of passes.  */
 
-  /* Simple IPA passes executed after the regular passes.  In WHOPR mode the
-     passes are executed after partitioning and thus see just parts of the
-     compiled unit.  */
-  p = &all_late_ipa_passes;
-  NEXT_PASS (pass_ipa_pta);
-  *p = NULL;
+#define INSERT_PASSES_AFTER(PASS) \
+  p = &(PASS);
 
-  /* These passes are run after IPA passes on every function that is being
-     output to the assembler file.  */
-  p = &all_passes;
-  NEXT_PASS (pass_fixup_cfg);
-  NEXT_PASS (pass_lower_eh_dispatch);
-  NEXT_PASS (pass_all_optimizations);
-    {
-      struct opt_pass **p = &pass_all_optimizations.pass.sub;
-      NEXT_PASS (pass_remove_cgraph_callee_edges);
-      /* Initial scalar cleanups before alias computation.
-        They ensure memory accesses are not indirect wherever possible.  */
-      NEXT_PASS (pass_strip_predict_hints);
-      NEXT_PASS (pass_rename_ssa_copies);
-      NEXT_PASS (pass_copy_prop);
-      NEXT_PASS (pass_complete_unrolli);
-      NEXT_PASS (pass_ccp);
-      /* After CCP we rewrite no longer addressed locals into SSA
-        form if possible.  */
-      NEXT_PASS (pass_forwprop);
-      /* pass_build_alias is a dummy pass that ensures that we
-        execute TODO_rebuild_alias at this point.  */
-      NEXT_PASS (pass_build_alias);
-      NEXT_PASS (pass_return_slot);
-      NEXT_PASS (pass_phiprop);
-      NEXT_PASS (pass_fre);
-      NEXT_PASS (pass_copy_prop);
-      NEXT_PASS (pass_merge_phi);
-      NEXT_PASS (pass_vrp);
-      NEXT_PASS (pass_dce);
-      NEXT_PASS (pass_call_cdce);
-      NEXT_PASS (pass_cselim);
-      NEXT_PASS (pass_tree_ifcombine);
-      NEXT_PASS (pass_phiopt);
-      NEXT_PASS (pass_tail_recursion);
-      NEXT_PASS (pass_ch);
-      NEXT_PASS (pass_stdarg);
-      NEXT_PASS (pass_lower_complex);
-      NEXT_PASS (pass_sra);
-      NEXT_PASS (pass_rename_ssa_copies);
-      /* The dom pass will also resolve all __builtin_constant_p calls
-         that are still there to 0.  This has to be done after some
-        propagations have already run, but before some more dead code
-        is removed, and this place fits nicely.  Remember this when
-        trying to move or duplicate pass_dominator somewhere earlier.  */
-      NEXT_PASS (pass_dominator);
-      /* The only const/copy propagation opportunities left after
-        DOM should be due to degenerate PHI nodes.  So rather than
-        run the full propagators, run a specialized pass which
-        only examines PHIs to discover const/copy propagation
-        opportunities.  */
-      NEXT_PASS (pass_phi_only_cprop);
-      NEXT_PASS (pass_dse);
-      NEXT_PASS (pass_reassoc);
-      NEXT_PASS (pass_dce);
-      NEXT_PASS (pass_forwprop);
-      NEXT_PASS (pass_phiopt);
-      NEXT_PASS (pass_object_sizes);
-      NEXT_PASS (pass_strlen);
-      NEXT_PASS (pass_ccp);
-      /* After CCP we rewrite no longer addressed locals into SSA
-        form if possible.  */
-      NEXT_PASS (pass_copy_prop);
-      NEXT_PASS (pass_cse_sincos);
-      NEXT_PASS (pass_optimize_bswap);
-      NEXT_PASS (pass_split_crit_edges);
-      NEXT_PASS (pass_pre);
-      NEXT_PASS (pass_sink_code);
-      NEXT_PASS (pass_asan);
-      NEXT_PASS (pass_tsan);
-      NEXT_PASS (pass_tree_loop);
-       {
-         struct opt_pass **p = &pass_tree_loop.pass.sub;
-         NEXT_PASS (pass_tree_loop_init);
-         NEXT_PASS (pass_lim);
-         NEXT_PASS (pass_copy_prop);
-         NEXT_PASS (pass_dce_loop);
-         NEXT_PASS (pass_tree_unswitch);
-         NEXT_PASS (pass_scev_cprop);
-         NEXT_PASS (pass_record_bounds);
-         NEXT_PASS (pass_check_data_deps);
-         NEXT_PASS (pass_loop_distribution);
-         NEXT_PASS (pass_copy_prop);
-         NEXT_PASS (pass_graphite);
-           {
-             struct opt_pass **p = &pass_graphite.pass.sub;
-             NEXT_PASS (pass_graphite_transforms);
-             NEXT_PASS (pass_lim);
-             NEXT_PASS (pass_copy_prop);
-             NEXT_PASS (pass_dce_loop);
-           }
-         NEXT_PASS (pass_iv_canon);
-         NEXT_PASS (pass_parallelize_loops);
-         NEXT_PASS (pass_if_conversion);
-         NEXT_PASS (pass_vectorize);
-           {
-             struct opt_pass **p = &pass_vectorize.pass.sub;
-             NEXT_PASS (pass_dce_loop);
-           }
-          NEXT_PASS (pass_predcom);
-         NEXT_PASS (pass_complete_unroll);
-         NEXT_PASS (pass_slp_vectorize);
-         NEXT_PASS (pass_loop_prefetch);
-         NEXT_PASS (pass_iv_optimize);
-         NEXT_PASS (pass_lim);
-         NEXT_PASS (pass_tree_loop_done);
-       }
-      NEXT_PASS (pass_lower_vector_ssa);
-      NEXT_PASS (pass_cse_reciprocals);
-      NEXT_PASS (pass_reassoc);
-      NEXT_PASS (pass_strength_reduction);
-      NEXT_PASS (pass_dominator);
-      /* The only const/copy propagation opportunities left after
-        DOM should be due to degenerate PHI nodes.  So rather than
-        run the full propagators, run a specialized pass which
-        only examines PHIs to discover const/copy propagation
-        opportunities.  */
-      NEXT_PASS (pass_phi_only_cprop);
-      NEXT_PASS (pass_vrp);
-      NEXT_PASS (pass_cd_dce);
-      NEXT_PASS (pass_tracer);
-
-      /* FIXME: If DCE is not run before checking for uninitialized uses,
-        we may get false warnings (e.g., testsuite/gcc.dg/uninit-5.c).
-        However, this also causes us to misdiagnose cases that should be
-        real warnings (e.g., testsuite/gcc.dg/pr18501.c).
-
-        To fix the false positives in uninit-5.c, we would have to
-        account for the predicates protecting the set and the use of each
-        variable.  Using a representation like Gated Single Assignment
-        may help.  */
-      NEXT_PASS (pass_late_warn_uninitialized);
-      NEXT_PASS (pass_dse);
-      NEXT_PASS (pass_forwprop);
-      NEXT_PASS (pass_phiopt);
-      NEXT_PASS (pass_fold_builtins);
-      NEXT_PASS (pass_optimize_widening_mul);
-      NEXT_PASS (pass_tail_calls);
-      NEXT_PASS (pass_rename_ssa_copies);
-      NEXT_PASS (pass_uncprop);
-      NEXT_PASS (pass_local_pure_const);
-    }
-  NEXT_PASS (pass_all_optimizations_g);
-    {
-      struct opt_pass **p = &pass_all_optimizations_g.pass.sub;
-      NEXT_PASS (pass_remove_cgraph_callee_edges);
-      NEXT_PASS (pass_strip_predict_hints);
-      /* Lower remaining pieces of GIMPLE.  */
-      NEXT_PASS (pass_lower_complex);
-      NEXT_PASS (pass_lower_vector_ssa);
-      /* Perform simple scalar cleanup which is constant/copy propagation.  */
-      NEXT_PASS (pass_ccp);
-      NEXT_PASS (pass_object_sizes);
-      /* Copy propagation also copy-propagates constants, this is necessary
-         to forward object-size results properly.  */
-      NEXT_PASS (pass_copy_prop);
-      NEXT_PASS (pass_asan);
-      NEXT_PASS (pass_tsan);
-      NEXT_PASS (pass_rename_ssa_copies);
-      NEXT_PASS (pass_dce);
-      /* Fold remaining builtins.  */
-      NEXT_PASS (pass_fold_builtins);
-      /* ???  We do want some kind of loop invariant motion, but we possibly
-         need to adjust LIM to be more friendly towards preserving accurate
-        debug information here.  */
-      NEXT_PASS (pass_late_warn_uninitialized);
-      NEXT_PASS (pass_uncprop);
-      NEXT_PASS (pass_local_pure_const);
-    }
-  NEXT_PASS (pass_tm_init);
-    {
-      struct opt_pass **p = &pass_tm_init.pass.sub;
-      NEXT_PASS (pass_tm_mark);
-      NEXT_PASS (pass_tm_memopt);
-      NEXT_PASS (pass_tm_edges);
-    }
-  NEXT_PASS (pass_lower_vector);
-  NEXT_PASS (pass_lower_complex_O0);
-  NEXT_PASS (pass_asan_O0);
-  NEXT_PASS (pass_tsan_O0);
-  NEXT_PASS (pass_cleanup_eh);
-  NEXT_PASS (pass_lower_resx);
-  NEXT_PASS (pass_nrv);
-  NEXT_PASS (pass_mudflap_2);
-  NEXT_PASS (pass_cleanup_cfg_post_optimizing);
-  NEXT_PASS (pass_warn_function_noreturn);
-
-  NEXT_PASS (pass_expand);
-
-  NEXT_PASS (pass_rest_of_compilation);
-    {
-      struct opt_pass **p = &pass_rest_of_compilation.pass.sub;
-      NEXT_PASS (pass_instantiate_virtual_regs);
-      NEXT_PASS (pass_into_cfg_layout_mode);
-      NEXT_PASS (pass_jump);
-      NEXT_PASS (pass_lower_subreg);
-      NEXT_PASS (pass_df_initialize_opt);
-      NEXT_PASS (pass_cse);
-      NEXT_PASS (pass_rtl_fwprop);
-      NEXT_PASS (pass_rtl_cprop);
-      NEXT_PASS (pass_rtl_pre);
-      NEXT_PASS (pass_rtl_hoist);
-      NEXT_PASS (pass_rtl_cprop);
-      NEXT_PASS (pass_rtl_store_motion);
-      NEXT_PASS (pass_cse_after_global_opts);
-      NEXT_PASS (pass_rtl_ifcvt);
-      NEXT_PASS (pass_reginfo_init);
-      /* Perform loop optimizations.  It might be better to do them a bit
-        sooner, but we want the profile feedback to work more
-        efficiently.  */
-      NEXT_PASS (pass_loop2);
-       {
-         struct opt_pass **p = &pass_loop2.pass.sub;
-         NEXT_PASS (pass_rtl_loop_init);
-         NEXT_PASS (pass_rtl_move_loop_invariants);
-         NEXT_PASS (pass_rtl_unswitch);
-         NEXT_PASS (pass_rtl_unroll_and_peel_loops);
-         NEXT_PASS (pass_rtl_doloop);
-         NEXT_PASS (pass_rtl_loop_done);
-         *p = NULL;
-       }
-      NEXT_PASS (pass_web);
-      NEXT_PASS (pass_rtl_cprop);
-      NEXT_PASS (pass_cse2);
-      NEXT_PASS (pass_rtl_dse1);
-      NEXT_PASS (pass_rtl_fwprop_addr);
-      NEXT_PASS (pass_inc_dec);
-      NEXT_PASS (pass_initialize_regs);
-      NEXT_PASS (pass_ud_rtl_dce);
-      NEXT_PASS (pass_combine);
-      NEXT_PASS (pass_if_after_combine);
-      NEXT_PASS (pass_partition_blocks);
-      NEXT_PASS (pass_regmove);
-      NEXT_PASS (pass_outof_cfg_layout_mode);
-      NEXT_PASS (pass_split_all_insns);
-      NEXT_PASS (pass_lower_subreg2);
-      NEXT_PASS (pass_df_initialize_no_opt);
-      NEXT_PASS (pass_stack_ptr_mod);
-      NEXT_PASS (pass_mode_switching);
-      NEXT_PASS (pass_match_asm_constraints);
-      NEXT_PASS (pass_sms);
-      NEXT_PASS (pass_sched);
-      NEXT_PASS (pass_ira);
-      NEXT_PASS (pass_reload);
-      NEXT_PASS (pass_postreload);
-       {
-         struct opt_pass **p = &pass_postreload.pass.sub;
-         NEXT_PASS (pass_postreload_cse);
-         NEXT_PASS (pass_gcse2);
-         NEXT_PASS (pass_split_after_reload);
-         NEXT_PASS (pass_ree);
-         NEXT_PASS (pass_compare_elim_after_reload);
-         NEXT_PASS (pass_branch_target_load_optimize1);
-         NEXT_PASS (pass_thread_prologue_and_epilogue);
-         NEXT_PASS (pass_rtl_dse2);
-         NEXT_PASS (pass_stack_adjustments);
-         NEXT_PASS (pass_jump2);
-         NEXT_PASS (pass_peephole2);
-         NEXT_PASS (pass_if_after_reload);
-         NEXT_PASS (pass_regrename);
-         NEXT_PASS (pass_cprop_hardreg);
-         NEXT_PASS (pass_fast_rtl_dce);
-         NEXT_PASS (pass_reorder_blocks);
-         NEXT_PASS (pass_branch_target_load_optimize2);
-         NEXT_PASS (pass_leaf_regs);
-         NEXT_PASS (pass_split_before_sched2);
-         NEXT_PASS (pass_sched2);
-         NEXT_PASS (pass_stack_regs);
-           {
-             struct opt_pass **p = &pass_stack_regs.pass.sub;
-             NEXT_PASS (pass_split_before_regstack);
-             NEXT_PASS (pass_stack_regs_run);
-           }
-         NEXT_PASS (pass_compute_alignments);
-         NEXT_PASS (pass_duplicate_computed_gotos);
-         NEXT_PASS (pass_variable_tracking);
-         NEXT_PASS (pass_free_cfg);
-         NEXT_PASS (pass_machine_reorg);
-         NEXT_PASS (pass_cleanup_barriers);
-         NEXT_PASS (pass_delay_slots);
-         NEXT_PASS (pass_split_for_shorten_branches);
-         NEXT_PASS (pass_convert_to_eh_region_ranges);
-         NEXT_PASS (pass_shorten_branches);
-         NEXT_PASS (pass_set_nothrow_function_flags);
-         NEXT_PASS (pass_dwarf2_frame);
-         NEXT_PASS (pass_final);
-       }
-      NEXT_PASS (pass_df_finish);
-    }
-  NEXT_PASS (pass_clean_state);
+#define PUSH_INSERT_PASSES_WITHIN(PASS) \
+  { \
+    opt_pass **p = &(PASS ## _1)->sub;
+
+#define POP_INSERT_PASSES() \
+  }
+
+#define NEXT_PASS(PASS, NUM) \
+  do { \
+    gcc_assert (NULL == PASS ## _ ## NUM); \
+    if ((NUM) == 1)                              \
+      PASS ## _1 = make_##PASS (m_ctxt);          \
+    else                                         \
+      {                                          \
+        gcc_assert (PASS ## _1);                 \
+        PASS ## _ ## NUM = PASS ## _1->clone (); \
+      }                                          \
+    p = next_pass_1 (p, PASS ## _ ## NUM, PASS ## _1);  \
+  } while (0)
+
+#define TERMINATE_PASS_LIST() \
   *p = NULL;
 
+#include "pass-instances.def"
+
+#undef INSERT_PASSES_AFTER
+#undef PUSH_INSERT_PASSES_WITHIN
+#undef POP_INSERT_PASSES
 #undef NEXT_PASS
+#undef TERMINATE_PASS_LIST
 
   /* Register the passes with the tree dump code.  */
-  register_dump_files (all_lowering_passes, PROP_gimple_any);
-  register_dump_files (all_small_ipa_passes,
-                      PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
-                      | PROP_cfg);
-  register_dump_files (all_regular_ipa_passes,
-                      PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
-                      | PROP_cfg);
-  register_dump_files (all_lto_gen_passes,
-                      PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
-                      | PROP_cfg);
-  register_dump_files (all_late_ipa_passes,
-                      PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
-                      | PROP_cfg);
-  register_dump_files (all_passes,
-                      PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
-                      | PROP_cfg);
+  register_dump_files (all_lowering_passes);
+  register_dump_files (all_small_ipa_passes);
+  register_dump_files (all_regular_ipa_passes);
+  register_dump_files (all_late_ipa_passes);
+  register_dump_files (all_passes);
+}
+
+static void
+delete_pass_tree (opt_pass *pass)
+{
+  while (pass)
+    {
+      /* Recurse into child passes.  */
+      delete_pass_tree (pass->sub);
+
+      opt_pass *next = pass->next;
+
+      /* Delete this pass.  */
+      delete pass;
+
+      /* Iterate onto sibling passes.  */
+      pass = next;
+    }
+}
+
+pass_manager::~pass_manager ()
+{
+  XDELETEVEC (passes_by_id);
+
+  /* Call delete_pass_tree on each of the pass_lists.  */
+#define DEF_PASS_LIST(LIST) \
+    delete_pass_tree (*pass_lists[PASS_LIST_NO_##LIST]);
+  GCC_PASS_LISTS
+#undef DEF_PASS_LIST
+
 }
 
 /* If we are in IPA mode (i.e., current_function_decl is NULL), call
@@ -1701,27 +1643,17 @@ init_optimization_passes (void)
    call CALLBACK on the current function.  */
 
 static void
-do_per_function (void (*callback) (void *data), void *data)
+do_per_function (void (*callback) (function *, void *data), void *data)
 {
   if (current_function_decl)
-    callback (data);
+    callback (cfun, data);
   else
     {
       struct cgraph_node *node;
       FOR_EACH_DEFINED_FUNCTION (node)
-       if (gimple_has_body_p (node->symbol.decl)
-           && (!node->clone_of || node->symbol.decl != node->clone_of->symbol.decl))
-         {
-           push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
-           callback (data);
-           if (!flag_wpa)
-             {
-               free_dominance_info (CDI_DOMINATORS);
-               free_dominance_info (CDI_POST_DOMINATORS);
-             }
-           pop_cfun ();
-           ggc_collect ();
-         }
+       if (node->analyzed && (gimple_has_body_p (node->decl) && !in_lto_p)
+           && (!node->clone_of || node->decl != node->clone_of->decl))
+         callback (DECL_STRUCT_FUNCTION (node->decl), data);
     }
 }
 
@@ -1729,43 +1661,71 @@ do_per_function (void (*callback) (void *data), void *data)
    keep the array visible to garbage collector to avoid reading collected
    out nodes.  */
 static int nnodes;
-static GTY ((length ("nnodes"))) cgraph_node_ptr *order;
+static GTY ((length ("nnodes"))) cgraph_node **order;
+
+/* Hook called when NODE is removed and therefore should be
+   excluded from order vector.  DATA is an array of integers.
+   DATA[0] holds max index it may be accessed by.  For cgraph
+   node DATA[node->uid + 1] holds index of this node in order
+   vector.  */
+static void
+remove_cgraph_node_from_order (cgraph_node *node, void *data)
+{
+  int *order_idx = (int *)data;
+
+  if (node->uid >= order_idx[0])
+    return;
+
+  int idx = order_idx[node->uid + 1];
+  if (idx >= 0 && idx < nnodes && order[idx] == node)
+    order[idx] = NULL;
+}
 
 /* If we are in IPA mode (i.e., current_function_decl is NULL), call
    function CALLBACK for every function in the call graph.  Otherwise,
    call CALLBACK on the current function.
    This function is global so that plugins can use it.  */
 void
-do_per_function_toporder (void (*callback) (void *data), void *data)
+do_per_function_toporder (void (*callback) (function *, void *data), void *data)
 {
   int i;
 
   if (current_function_decl)
-    callback (data);
+    callback (cfun, data);
   else
     {
+      cgraph_node_hook_list *hook;
+      int *order_idx;
       gcc_assert (!order);
-      order = ggc_alloc_vec_cgraph_node_ptr (cgraph_n_nodes);
+      order = ggc_vec_alloc<cgraph_node *> (symtab->cgraph_count);
+
+      order_idx = XALLOCAVEC (int, symtab->cgraph_max_uid + 1);
+      memset (order_idx + 1, -1, sizeof (int) * symtab->cgraph_max_uid);
+      order_idx[0] = symtab->cgraph_max_uid;
+
       nnodes = ipa_reverse_postorder (order);
       for (i = nnodes - 1; i >= 0; i--)
-        order[i]->process = 1;
+       {
+         order[i]->process = 1;
+         order_idx[order[i]->uid + 1] = i;
+       }
+      hook = symtab->add_cgraph_removal_hook (remove_cgraph_node_from_order,
+                                             order_idx);
       for (i = nnodes - 1; i >= 0; i--)
        {
+         /* Function could be inlined and removed as unreachable.  */
+         if (!order[i])
+           continue;
+
          struct cgraph_node *node = order[i];
 
          /* Allow possibly removed nodes to be garbage collected.  */
          order[i] = NULL;
          node->process = 0;
-         if (cgraph_function_with_gimple_body_p (node))
-           {
-             push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
-             callback (data);
-             free_dominance_info (CDI_DOMINATORS);
-             free_dominance_info (CDI_POST_DOMINATORS);
-             pop_cfun ();
-             ggc_collect ();
-           }
+         if (node->has_gimple_body_p ())
+           callback (DECL_STRUCT_FUNCTION (node->decl), data);
        }
+      symtab->remove_cgraph_removal_hook (hook);
     }
   ggc_free (order);
   order = NULL;
@@ -1775,12 +1735,16 @@ do_per_function_toporder (void (*callback) (void *data), void *data)
 /* Helper function to perform function body dump.  */
 
 static void
-execute_function_dump (void *data ATTRIBUTE_UNUSED)
+execute_function_dump (function *fn, void *data)
 {
-  if (dump_file && current_function_decl)
+  opt_pass *pass = (opt_pass *)data;
+
+  if (dump_file)
     {
-      if (cfun->curr_properties & PROP_trees)
-        dump_function_to_file (current_function_decl, dump_file, dump_flags);
+      push_cfun (fn);
+
+      if (fn->curr_properties & PROP_trees)
+        dump_function_to_file (fn->decl, dump_file, dump_flags);
       else
        print_rtl_with_bb (dump_file, get_insns (), dump_flags);
 
@@ -1788,9 +1752,18 @@ execute_function_dump (void *data ATTRIBUTE_UNUSED)
         close the file before aborting.  */
       fflush (dump_file);
 
-      if ((cfun->curr_properties & PROP_cfg)
+      if ((fn->curr_properties & PROP_cfg)
          && (dump_flags & TDF_GRAPH))
-       print_graph_cfg (dump_file_name, cfun);
+       {
+         if (!pass->graph_dump_initialized)
+           {
+             clean_graph_dump_file (dump_file_name);
+             pass->graph_dump_initialized = true;
+           }
+         print_graph_cfg (dump_file_name, fn);
+       }
+
+      pop_cfun ();
     }
 }
 
@@ -1804,12 +1777,13 @@ static struct profile_record *profile_record;
 static void
 check_profile_consistency (int index, int subpass, bool run)
 {
+  pass_manager *passes = g->get_passes ();
   if (index == -1)
     return;
   if (!profile_record)
     profile_record = XCNEWVEC (struct profile_record,
-                              passes_by_id_size);
-  gcc_assert (index < passes_by_id_size && index >= 0);
+                              passes->passes_by_id_size);
+  gcc_assert (index < passes->passes_by_id_size && index >= 0);
   gcc_assert (subpass < 2);
   profile_record[index].run |= run;
   account_profile_record (&profile_record[index], subpass);
@@ -1819,6 +1793,12 @@ check_profile_consistency (int index, int subpass, bool run)
 
 void
 dump_profile_report (void)
+{
+  g->get_passes ()->dump_profile_report ();
+}
+
+void
+pass_manager::dump_profile_report () const
 {
   int i, j;
   int last_freq_in = 0, last_count_in = 0, last_freq_out = 0, last_count_out = 0;
@@ -1883,7 +1863,7 @@ dump_profile_report (void)
                fprintf (stderr, "      ");
 
              /* Size/time units change across gimple and RTL.  */
-             if (i == pass_expand.pass.static_pass_number)
+             if (i == pass_expand_1->static_pass_number)
                fprintf (stderr, "|----------");
              else
                {
@@ -1914,13 +1894,16 @@ dump_profile_report (void)
 /* Perform all TODO actions that ought to be done on each function.  */
 
 static void
-execute_function_todo (void *data)
+execute_function_todo (function *fn, void *data)
 {
+  bool from_ipa_pass = (cfun == NULL);
   unsigned int flags = (size_t)data;
-  flags &= ~cfun->last_verified;
+  flags &= ~fn->last_verified;
   if (!flags)
     return;
 
+  push_cfun (fn);
+
   /* Always cleanup the CFG before trying to update SSA.  */
   if (flags & TODO_cleanup_cfg)
     {
@@ -1940,7 +1923,6 @@ execute_function_todo (void *data)
     {
       unsigned update_flags = flags & TODO_update_ssa_any;
       update_ssa (update_flags);
-      cfun->last_verified &= ~TODO_verify_ssa;
     }
 
   if (flag_tree_pta && (flags & TODO_rebuild_alias))
@@ -1956,30 +1938,59 @@ execute_function_todo (void *data)
     rebuild_frequencies ();
 
   if (flags & TODO_rebuild_cgraph_edges)
-    rebuild_cgraph_edges ();
+    cgraph_edge::rebuild_edges ();
 
   /* If we've seen errors do not bother running any verifiers.  */
-  if (seen_error ())
-    return;
-
-#if defined ENABLE_CHECKING
-  if (flags & TODO_verify_ssa
-      || (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA)))
+  if (!seen_error ())
     {
-      verify_gimple_in_cfg (cfun);
-      verify_ssa (true);
-    }
-  else if (flags & TODO_verify_stmts)
-    verify_gimple_in_cfg (cfun);
-  if (flags & TODO_verify_flow)
-    verify_flow_info ();
-  if (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA))
-    verify_loop_closed_ssa (false);
-  if (flags & TODO_verify_rtl_sharing)
-    verify_rtl_sharing ();
+#if defined ENABLE_CHECKING
+      dom_state pre_verify_state = dom_info_state (fn, CDI_DOMINATORS);
+      dom_state pre_verify_pstate = dom_info_state (fn, CDI_POST_DOMINATORS);
+
+      if (flags & TODO_verify_il)
+       {
+         if (cfun->curr_properties & PROP_trees)
+           {
+             if (cfun->curr_properties & PROP_cfg)
+               /* IPA passes leave stmts to be fixed up, so make sure to
+                  not verify stmts really throw.  */
+               verify_gimple_in_cfg (cfun, !from_ipa_pass);
+             else
+               verify_gimple_in_seq (gimple_body (cfun->decl));
+           }
+         if (cfun->curr_properties & PROP_ssa)
+           /* IPA passes leave stmts to be fixed up, so make sure to
+              not verify SSA operands whose verifier will choke on that.  */
+           verify_ssa (true, !from_ipa_pass);
+         /* IPA passes leave basic-blocks unsplit, so make sure to
+            not trip on that.  */
+         if ((cfun->curr_properties & PROP_cfg)
+             && !from_ipa_pass)
+           verify_flow_info ();
+         if (current_loops
+             && loops_state_satisfies_p (LOOP_CLOSED_SSA))
+           verify_loop_closed_ssa (false);
+         if (cfun->curr_properties & PROP_rtl)
+           verify_rtl_sharing ();
+       }
+
+      /* Make sure verifiers don't change dominator state.  */
+      gcc_assert (dom_info_state (fn, CDI_DOMINATORS) == pre_verify_state);
+      gcc_assert (dom_info_state (fn, CDI_POST_DOMINATORS) == pre_verify_pstate);
 #endif
+    }
+
+  fn->last_verified = flags & TODO_verify_all;
+
+  pop_cfun ();
 
-  cfun->last_verified = flags & TODO_verify_all;
+  /* For IPA passes make sure to release dominator info, it can be
+     computed by non-verifying TODOs.  */
+  if (from_ipa_pass)
+    {
+      free_dominance_info (fn, CDI_DOMINATORS);
+      free_dominance_info (fn, CDI_POST_DOMINATORS);
+    }
 }
 
 /* Perform all TODO actions.  */
@@ -1999,7 +2010,8 @@ execute_todo (unsigned int flags)
 
   statistics_fini_pass ();
 
-  do_per_function (execute_function_todo, (void *)(size_t) flags);
+  if (flags)
+    do_per_function (execute_function_todo, (void *)(size_t) flags);
 
   /* Always remove functions just as before inlining: IPA passes might be
      interested to see bodies of extern inline functions that are not inlined
@@ -2008,13 +2020,13 @@ execute_todo (unsigned int flags)
   if (flags & TODO_remove_functions)
     {
       gcc_assert (!cfun);
-      symtab_remove_unreachable_nodes (true, dump_file);
+      symtab->remove_unreachable_nodes (dump_file);
     }
 
   if ((flags & TODO_dump_symtab) && dump_file && !current_function_decl)
     {
       gcc_assert (!cfun);
-      dump_symtab (dump_file);
+      symtab_node::dump_table (dump_file);
       /* Flush the file.  If verification fails, we won't be able to
         close the file before aborting.  */
       fflush (dump_file);
@@ -2040,9 +2052,9 @@ verify_interpass_invariants (void)
 /* Clear the last verified flag.  */
 
 static void
-clear_last_verified (void *data ATTRIBUTE_UNUSED)
+clear_last_verified (function *fn, void *data ATTRIBUTE_UNUSED)
 {
-  cfun->last_verified = 0;
+  fn->last_verified = 0;
 }
 
 /* Helper function. Verify that the properties has been turn into the
@@ -2050,10 +2062,10 @@ clear_last_verified (void *data ATTRIBUTE_UNUSED)
 
 #ifdef ENABLE_CHECKING
 static void
-verify_curr_properties (void *data)
+verify_curr_properties (function *fn, void *data)
 {
   unsigned int props = (size_t)data;
-  gcc_assert ((cfun->curr_properties & props) == props);
+  gcc_assert ((fn->curr_properties & props) == props);
 }
 #endif
 
@@ -2061,21 +2073,26 @@ verify_curr_properties (void *data)
 /* This is non-static so that the plugins can use it.  */
 
 bool
-pass_init_dump_file (struct opt_pass *pass)
+pass_init_dump_file (opt_pass *pass)
 {
   /* If a dump file name is present, open it if enabled.  */
   if (pass->static_pass_number != -1)
     {
       timevar_push (TV_DUMP);
-      bool initializing_dump = !dump_initialized_p (pass->static_pass_number);
-      dump_file_name = get_dump_file_name (pass->static_pass_number);
-      dump_start (pass->static_pass_number, &dump_flags);
+      gcc::dump_manager *dumps = g->get_dumps ();
+      bool initializing_dump =
+       !dumps->dump_initialized_p (pass->static_pass_number);
+      dump_file_name = dumps->get_dump_file_name (pass->static_pass_number);
+      dumps->dump_start (pass->static_pass_number, &dump_flags);
       if (dump_file && current_function_decl)
         dump_function_header (dump_file, current_function_decl, dump_flags);
       if (initializing_dump
          && dump_file && (dump_flags & TDF_GRAPH)
          && cfun && (cfun->curr_properties & PROP_cfg))
-       clean_graph_dump_file (dump_file_name);
+       {
+         clean_graph_dump_file (dump_file_name);
+         pass->graph_dump_initialized = true;
+       }
       timevar_pop (TV_DUMP);
       return initializing_dump;
     }
@@ -2087,7 +2104,7 @@ pass_init_dump_file (struct opt_pass *pass)
 /* This is non-static so that plugins can use it.  */
 
 void
-pass_fini_dump_file (struct opt_pass *pass)
+pass_fini_dump_file (opt_pass *pass)
 {
   timevar_push (TV_DUMP);
 
@@ -2098,7 +2115,7 @@ pass_fini_dump_file (struct opt_pass *pass)
       dump_file_name = NULL;
     }
 
-  dump_finish (pass->static_pass_number);
+  g->get_dumps ()->dump_finish (pass->static_pass_number);
   timevar_pop (TV_DUMP);
 }
 
@@ -2106,25 +2123,25 @@ pass_fini_dump_file (struct opt_pass *pass)
    properties. */
 
 static void
-update_properties_after_pass (void *data)
+update_properties_after_pass (function *fn, void *data)
 {
-  struct opt_pass *pass = (struct opt_pass *) data;
-  cfun->curr_properties = (cfun->curr_properties | pass->properties_provided)
-                          & ~pass->properties_destroyed;
+  opt_pass *pass = (opt_pass *) data;
+  fn->curr_properties = (fn->curr_properties | pass->properties_provided)
+                        & ~pass->properties_destroyed;
 }
 
 /* Execute summary generation for all of the passes in IPA_PASS.  */
 
 void
-execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
+execute_ipa_summary_passes (ipa_opt_pass_d *ipa_pass)
 {
   while (ipa_pass)
     {
-      struct opt_pass *pass = &ipa_pass->pass;
+      opt_pass *pass = ipa_pass;
 
       /* Execute all of the IPA_PASSes in the list.  */
-      if (ipa_pass->pass.type == IPA_PASS
-         && (!pass->gate || pass->gate ())
+      if (ipa_pass->type == IPA_PASS
+         && pass->gate (cfun)
          && ipa_pass->generate_summary)
        {
          pass_init_dump_file (pass);
@@ -2133,6 +2150,7 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
          if (pass->tv_id)
            timevar_push (pass->tv_id);
 
+         current_pass = pass;
          ipa_pass->generate_summary ();
 
          /* Stop timevar.  */
@@ -2141,7 +2159,7 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
 
          pass_fini_dump_file (pass);
        }
-      ipa_pass = (struct ipa_opt_pass_d *)ipa_pass->pass.next;
+      ipa_pass = (ipa_opt_pass_d *)ipa_pass->next;
     }
 }
 
@@ -2149,9 +2167,9 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
 
 static void
 execute_one_ipa_transform_pass (struct cgraph_node *node,
-                               struct ipa_opt_pass_d *ipa_pass)
+                               ipa_opt_pass_d *ipa_pass)
 {
-  struct opt_pass *pass = &ipa_pass->pass;
+  opt_pass *pass = ipa_pass;
   unsigned int todo_after = 0;
 
   current_pass = pass;
@@ -2187,7 +2205,8 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
   if (profile_report && cfun && (cfun->curr_properties & PROP_cfg))
     check_profile_consistency (pass->static_pass_number, 1, true);
 
-  do_per_function (execute_function_dump, NULL);
+  if (dump_file)
+    do_per_function (execute_function_dump, NULL);
   pass_fini_dump_file (pass);
 
   current_pass = NULL;
@@ -2205,7 +2224,7 @@ execute_all_ipa_transforms (void)
   struct cgraph_node *node;
   if (!cfun)
     return;
-  node = cgraph_get_node (current_function_decl);
+  node = cgraph_node::get (current_function_decl);
 
   if (node->ipa_transforms_to_apply.exists ())
     {
@@ -2217,27 +2236,13 @@ execute_all_ipa_transforms (void)
     }
 }
 
-/* Callback for do_per_function to apply all IPA transforms.  */
-
-static void
-apply_ipa_transforms (void *data)
-{
-  struct cgraph_node *node = cgraph_get_node (current_function_decl);
-  if (!node->global.inlined_to && node->ipa_transforms_to_apply.exists ())
-    {
-      *(bool *)data = true;
-      execute_all_ipa_transforms();
-      rebuild_cgraph_edges ();
-    }
-}
-
 /* Check if PASS is explicitly disabled or enabled and return
    the gate status.  FUNC is the function to be processed, and
    GATE_STATUS is the gate status determined by pass manager by
    default.  */
 
 static bool
-override_gate_status (struct opt_pass *pass, tree func, bool gate_status)
+override_gate_status (opt_pass *pass, tree func, bool gate_status)
 {
   bool explicitly_enabled = false;
   bool explicitly_disabled = false;
@@ -2258,7 +2263,7 @@ override_gate_status (struct opt_pass *pass, tree func, bool gate_status)
 /* Execute PASS. */
 
 bool
-execute_one_pass (struct opt_pass *pass)
+execute_one_pass (opt_pass *pass)
 {
   unsigned int todo_after = 0;
 
@@ -2275,7 +2280,7 @@ execute_one_pass (struct opt_pass *pass)
 
   /* Check whether gate check should be avoided.
      User controls the value of the gate through the parameter "gate_status". */
-  gate_status = (pass->gate == NULL) ? true : pass->gate();
+  gate_status = pass->gate (cfun);
   gate_status = override_gate_status (pass, current_function_decl, gate_status);
 
   /* Override gate with plugin.  */
@@ -2298,18 +2303,6 @@ execute_one_pass (struct opt_pass *pass)
      executed.  */
   invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass);
 
-  /* SIPLE IPA passes do not handle callgraphs with IPA transforms in it.
-     Apply all trnasforms first.  */
-  if (pass->type == SIMPLE_IPA_PASS)
-    {
-      bool applied = false;
-      do_per_function (apply_ipa_transforms, (void *)&applied);
-      if (applied)
-        symtab_remove_unreachable_nodes (true, dump_file);
-      /* Restore current_pass.  */
-      current_pass = pass;
-    }
-
   if (!quiet_flag && !cfun)
     fprintf (stderr, " <%s>", pass->name ? pass->name : "");
 
@@ -2332,11 +2325,8 @@ execute_one_pass (struct opt_pass *pass)
     timevar_push (pass->tv_id);
 
   /* Do it!  */
-  if (pass->execute)
-    {
-      todo_after = pass->execute ();
-      do_per_function (clear_last_verified, NULL);
-    }
+  todo_after = pass->execute (cfun);
+  do_per_function (clear_last_verified, NULL);
 
   /* Stop timevar.  */
   if (pass->tv_id != TV_NONE)
@@ -2348,21 +2338,23 @@ execute_one_pass (struct opt_pass *pass)
     check_profile_consistency (pass->static_pass_number, 0, true);
 
   /* Run post-pass cleanup and verification.  */
-  execute_todo (todo_after | pass->todo_flags_finish);
+  execute_todo (todo_after | pass->todo_flags_finish | TODO_verify_il);
   if (profile_report && cfun && (cfun->curr_properties & PROP_cfg))
     check_profile_consistency (pass->static_pass_number, 1, true);
 
   verify_interpass_invariants ();
-  do_per_function (execute_function_dump, NULL);
+  if (dump_file)
+    do_per_function (execute_function_dump, pass);
   if (pass->type == IPA_PASS)
     {
       struct cgraph_node *node;
-      FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
-       node->ipa_transforms_to_apply.safe_push ((struct ipa_opt_pass_d *)pass);
+      if (((ipa_opt_pass_d *)pass)->function_transform)
+       FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+         node->ipa_transforms_to_apply.safe_push ((ipa_opt_pass_d *)pass);
     }
 
   if (!current_function_decl)
-    cgraph_process_new_functions ();
+    symtab->process_new_functions ();
 
   pass_fini_dump_file (pass);
 
@@ -2379,36 +2371,61 @@ execute_one_pass (struct opt_pass *pass)
   return true;
 }
 
-void
-execute_pass_list (struct opt_pass *pass)
+static void
+execute_pass_list_1 (opt_pass *pass)
 {
   do
     {
       gcc_assert (pass->type == GIMPLE_PASS
                  || pass->type == RTL_PASS);
       if (execute_one_pass (pass) && pass->sub)
-        execute_pass_list (pass->sub);
+        execute_pass_list_1 (pass->sub);
       pass = pass->next;
     }
   while (pass);
 }
 
+void
+execute_pass_list (function *fn, opt_pass *pass)
+{
+  push_cfun (fn);
+  execute_pass_list_1 (pass);
+  if (fn->cfg)
+    {
+      free_dominance_info (CDI_DOMINATORS);
+      free_dominance_info (CDI_POST_DOMINATORS);
+    }
+  pop_cfun ();
+}
+
+/* Write out all LTO data.  */
+static void
+write_lto (void)
+{
+  timevar_push (TV_IPA_LTO_GIMPLE_OUT);
+  lto_output ();
+  timevar_pop (TV_IPA_LTO_GIMPLE_OUT);
+  timevar_push (TV_IPA_LTO_DECL_OUT);
+  produce_asm_for_decls ();
+  timevar_pop (TV_IPA_LTO_DECL_OUT);
+}
+
 /* Same as execute_pass_list but assume that subpasses of IPA passes
    are local passes. If SET is not NULL, write out summaries of only
    those node in SET. */
 
 static void
-ipa_write_summaries_2 (struct opt_pass *pass, struct lto_out_decl_state *state)
+ipa_write_summaries_2 (opt_pass *pass, struct lto_out_decl_state *state)
 {
   while (pass)
     {
-      struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *)pass;
+      ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *)pass;
       gcc_assert (!current_function_decl);
       gcc_assert (!cfun);
       gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
       if (pass->type == IPA_PASS
          && ipa_pass->write_summary
-         && (!pass->gate || pass->gate ()))
+         && pass->gate (cfun))
        {
          /* If a timevar is present, start it.  */
          if (pass->tv_id)
@@ -2416,6 +2433,7 @@ ipa_write_summaries_2 (struct opt_pass *pass, struct lto_out_decl_state *state)
 
           pass_init_dump_file (pass);
 
+         current_pass = pass;
          ipa_pass->write_summary ();
 
           pass_fini_dump_file (pass);
@@ -2439,14 +2457,17 @@ ipa_write_summaries_2 (struct opt_pass *pass, struct lto_out_decl_state *state)
 static void
 ipa_write_summaries_1 (lto_symtab_encoder_t encoder)
 {
+  pass_manager *passes = g->get_passes ();
   struct lto_out_decl_state *state = lto_new_out_decl_state ();
   state->symtab_node_encoder = encoder;
 
+  lto_output_init_mode_table ();
   lto_push_out_decl_state (state);
 
   gcc_assert (!flag_wpa);
-  ipa_write_summaries_2 (all_regular_ipa_passes, state);
-  ipa_write_summaries_2 (all_lto_gen_passes, state);
+  ipa_write_summaries_2 (passes->all_regular_ipa_passes, state);
+
+  write_lto ();
 
   gcc_assert (lto_get_out_decl_state () == state);
   lto_pop_out_decl_state ();
@@ -2460,27 +2481,30 @@ ipa_write_summaries (void)
 {
   lto_symtab_encoder_t encoder;
   int i, order_pos;
-  struct varpool_node *vnode;
+  varpool_node *vnode;
+  struct cgraph_node *node;
   struct cgraph_node **order;
 
-  if (!flag_generate_lto || seen_error ())
+  if ((!flag_generate_lto && !flag_generate_offload) || seen_error ())
     return;
 
+  select_what_to_stream ();
+
   encoder = lto_symtab_encoder_new (false);
 
   /* Create the callgraph set in the same order used in
      cgraph_expand_all_functions.  This mostly facilitates debugging,
      since it causes the gimple file to be processed in the same order
      as the source code.  */
-  order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
+  order = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count);
   order_pos = ipa_reverse_postorder (order);
-  gcc_assert (order_pos == cgraph_n_nodes);
+  gcc_assert (order_pos == symtab->cgraph_count);
 
   for (i = order_pos - 1; i >= 0; i--)
     {
       struct cgraph_node *node = order[i];
 
-      if (cgraph_function_with_gimple_body_p (node))
+      if (node->has_gimple_body_p ())
        {
          /* When streaming out references to statements as part of some IPA
             pass summary, the statements need to have uids assigned and the
@@ -2488,17 +2512,20 @@ ipa_write_summaries (void)
             ordering then matches the one IPA-passes get in their stmt_fixup
             hooks.  */
 
-         push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
+         push_cfun (DECL_STRUCT_FUNCTION (node->decl));
          renumber_gimple_stmt_uids ();
          pop_cfun ();
        }
-      if (node->analyzed)
-        lto_set_symtab_encoder_in_partition (encoder, (symtab_node)node);
+      if (node->definition && node->need_lto_streaming)
+        lto_set_symtab_encoder_in_partition (encoder, node);
     }
 
+  FOR_EACH_DEFINED_FUNCTION (node)
+    if (node->alias && node->need_lto_streaming)
+      lto_set_symtab_encoder_in_partition (encoder, node);
   FOR_EACH_DEFINED_VARIABLE (vnode)
-    if ((!vnode->alias || vnode->alias_of))
-      lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode);
+    if (vnode->need_lto_streaming)
+      lto_set_symtab_encoder_in_partition (encoder, vnode);
 
   ipa_write_summaries_1 (compute_ltrans_boundary (encoder));
 
@@ -2510,17 +2537,18 @@ ipa_write_summaries (void)
    only those node in SET. */
 
 static void
-ipa_write_optimization_summaries_1 (struct opt_pass *pass, struct lto_out_decl_state *state)
+ipa_write_optimization_summaries_1 (opt_pass *pass,
+                                   struct lto_out_decl_state *state)
 {
   while (pass)
     {
-      struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *)pass;
+      ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *)pass;
       gcc_assert (!current_function_decl);
       gcc_assert (!cfun);
       gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
       if (pass->type == IPA_PASS
          && ipa_pass->write_optimization_summary
-         && (!pass->gate || pass->gate ()))
+         && pass->gate (cfun))
        {
          /* If a timevar is present, start it.  */
          if (pass->tv_id)
@@ -2528,6 +2556,7 @@ ipa_write_optimization_summaries_1 (struct opt_pass *pass, struct lto_out_decl_s
 
           pass_init_dump_file (pass);
 
+         current_pass = pass;
          ipa_pass->write_optimization_summary ();
 
           pass_fini_dump_file (pass);
@@ -2554,6 +2583,7 @@ ipa_write_optimization_summaries (lto_symtab_encoder_t encoder)
   lto_symtab_encoder_iterator lsei;
   state->symtab_node_encoder = encoder;
 
+  lto_output_init_mode_table ();
   lto_push_out_decl_state (state);
   for (lsei = lsei_start_function_in_partition (encoder);
        !lsei_end_p (lsei); lsei_next_function_in_partition (&lsei))
@@ -2564,18 +2594,20 @@ ipa_write_optimization_summaries (lto_symtab_encoder_t encoder)
 
         For functions newly born at WPA stage we need to initialize
         the uids here.  */
-      if (node->analyzed
-         && gimple_has_body_p (node->symbol.decl))
+      if (node->definition
+         && gimple_has_body_p (node->decl))
        {
-         push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
+         push_cfun (DECL_STRUCT_FUNCTION (node->decl));
          renumber_gimple_stmt_uids ();
          pop_cfun ();
        }
     }
 
   gcc_assert (flag_wpa);
-  ipa_write_optimization_summaries_1 (all_regular_ipa_passes, state);
-  ipa_write_optimization_summaries_1 (all_lto_gen_passes, state);
+  pass_manager *passes = g->get_passes ();
+  ipa_write_optimization_summaries_1 (passes->all_regular_ipa_passes, state);
+
+  write_lto ();
 
   gcc_assert (lto_get_out_decl_state () == state);
   lto_pop_out_decl_state ();
@@ -2586,17 +2618,17 @@ ipa_write_optimization_summaries (lto_symtab_encoder_t encoder)
    are local passes.  */
 
 static void
-ipa_read_summaries_1 (struct opt_pass *pass)
+ipa_read_summaries_1 (opt_pass *pass)
 {
   while (pass)
     {
-      struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
+      ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass;
 
       gcc_assert (!current_function_decl);
       gcc_assert (!cfun);
       gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
 
-      if (pass->gate == NULL || pass->gate ())
+      if (pass->gate (cfun))
        {
          if (pass->type == IPA_PASS && ipa_pass->read_summary)
            {
@@ -2606,6 +2638,7 @@ ipa_read_summaries_1 (struct opt_pass *pass)
 
              pass_init_dump_file (pass);
 
+             current_pass = pass;
              ipa_pass->read_summary ();
 
              pass_fini_dump_file (pass);
@@ -2623,30 +2656,30 @@ ipa_read_summaries_1 (struct opt_pass *pass)
 }
 
 
-/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes.  */
+/* Read all the summaries for all_regular_ipa_passes.  */
 
 void
 ipa_read_summaries (void)
 {
-  ipa_read_summaries_1 (all_regular_ipa_passes);
-  ipa_read_summaries_1 (all_lto_gen_passes);
+  pass_manager *passes = g->get_passes ();
+  ipa_read_summaries_1 (passes->all_regular_ipa_passes);
 }
 
 /* Same as execute_pass_list but assume that subpasses of IPA passes
    are local passes.  */
 
 static void
-ipa_read_optimization_summaries_1 (struct opt_pass *pass)
+ipa_read_optimization_summaries_1 (opt_pass *pass)
 {
   while (pass)
     {
-      struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
+      ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass;
 
       gcc_assert (!current_function_decl);
       gcc_assert (!cfun);
       gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
 
-      if (pass->gate == NULL || pass->gate ())
+      if (pass->gate (cfun))
        {
          if (pass->type == IPA_PASS && ipa_pass->read_optimization_summary)
            {
@@ -2656,6 +2689,7 @@ ipa_read_optimization_summaries_1 (struct opt_pass *pass)
 
              pass_init_dump_file (pass);
 
+             current_pass = pass;
              ipa_pass->read_optimization_summary ();
 
              pass_fini_dump_file (pass);
@@ -2672,19 +2706,19 @@ ipa_read_optimization_summaries_1 (struct opt_pass *pass)
     }
 }
 
-/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes.  */
+/* Read all the summaries for all_regular_ipa_passes.  */
 
 void
 ipa_read_optimization_summaries (void)
 {
-  ipa_read_optimization_summaries_1 (all_regular_ipa_passes);
-  ipa_read_optimization_summaries_1 (all_lto_gen_passes);
+  pass_manager *passes = g->get_passes ();
+  ipa_read_optimization_summaries_1 (passes->all_regular_ipa_passes);
 }
 
 /* Same as execute_pass_list but assume that subpasses of IPA passes
    are local passes.  */
 void
-execute_ipa_pass_list (struct opt_pass *pass)
+execute_ipa_pass_list (opt_pass *pass)
 {
   do
     {
@@ -2696,7 +2730,8 @@ execute_ipa_pass_list (struct opt_pass *pass)
          if (pass->sub->type == GIMPLE_PASS)
            {
              invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
-             do_per_function_toporder ((void (*)(void *))execute_pass_list,
+             do_per_function_toporder ((void (*)(function *, void *))
+                                         execute_pass_list,
                                        pass->sub);
              invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
            }
@@ -2707,7 +2742,7 @@ execute_ipa_pass_list (struct opt_pass *pass)
            gcc_unreachable ();
        }
       gcc_assert (!current_function_decl);
-      cgraph_process_new_functions ();
+      symtab->process_new_functions ();
       pass = pass->next;
     }
   while (pass);
@@ -2716,16 +2751,16 @@ execute_ipa_pass_list (struct opt_pass *pass)
 /* Execute stmt fixup hooks of all passes in PASS for NODE and STMTS.  */
 
 static void
-execute_ipa_stmt_fixups (struct opt_pass *pass,
-                         struct cgraph_node *node, gimple *stmts)
+execute_ipa_stmt_fixups (opt_pass *pass,
+                        struct cgraph_node *node, gimple *stmts)
 {
   while (pass)
     {
       /* Execute all of the IPA_PASSes in the list.  */
       if (pass->type == IPA_PASS
-         && (!pass->gate || pass->gate ()))
+         && pass->gate (cfun))
        {
-         struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
+         ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass;
 
          if (ipa_pass->stmt_fixup)
            {
@@ -2734,6 +2769,7 @@ execute_ipa_stmt_fixups (struct opt_pass *pass,
              if (pass->tv_id)
                timevar_push (pass->tv_id);
 
+             current_pass = pass;
              ipa_pass->stmt_fixup (node, stmts);
 
              /* Stop timevar.  */
@@ -2753,7 +2789,8 @@ execute_ipa_stmt_fixups (struct opt_pass *pass,
 void
 execute_all_ipa_stmt_fixups (struct cgraph_node *node, gimple *stmts)
 {
-  execute_ipa_stmt_fixups (all_regular_ipa_passes, node, stmts);
+  pass_manager *passes = g->get_passes ();
+  execute_ipa_stmt_fixups (passes->all_regular_ipa_passes, node, stmts);
 }
 
 
@@ -2801,15 +2838,15 @@ bool
 function_called_by_processed_nodes_p (void)
 {
   struct cgraph_edge *e;
-  for (e = cgraph_get_node (current_function_decl)->callers;
+  for (e = cgraph_node::get (current_function_decl)->callers;
        e;
        e = e->next_caller)
     {
-      if (e->caller->symbol.decl == current_function_decl)
+      if (e->caller->decl == current_function_decl)
         continue;
-      if (!cgraph_function_with_gimple_body_p (e->caller))
+      if (!e->caller->has_gimple_body_p ())
         continue;
-      if (TREE_ASM_WRITTEN (e->caller->symbol.decl))
+      if (TREE_ASM_WRITTEN (e->caller->decl))
         continue;
       if (!e->caller->process && !e->caller->global.inlined_to)
        break;
@@ -2817,7 +2854,7 @@ function_called_by_processed_nodes_p (void)
   if (dump_file && e)
     {
       fprintf (dump_file, "Already processed call to:\n");
-      dump_cgraph_node (dump_file, e->caller);
+      e->caller->dump (dump_file);
     }
   return e != NULL;
 }