OSDN Git Service

* config.gcc (powerpc-*-linux*): Merge variants.
[pf3gnuchains/gcc-fork.git] / gcc / passes.c
index b8ed3e6..3d7b18c 100644 (file)
@@ -1,6 +1,6 @@
 /* Top level of GCC compilers (cc1, cc1plus, etc.)
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -180,7 +180,7 @@ rest_of_decl_compilation (tree decl,
       /* Don't output anything when a tentative file-scope definition
         is seen.  But at end of compilation, do output code for them.
 
-        We do output all variables when unit-at-a-time is active and rely on
+        We do output all variables and rely on
         callgraph code to defer them except for forward declarations
         (see gcc.c-torture/compile/920624-1.c) */
       if ((at_end
@@ -333,6 +333,37 @@ struct rtl_opt_pass pass_postreload =
 /* The root of the compilation pass tree, once constructed.  */
 struct opt_pass *all_passes, *all_ipa_passes, *all_lowering_passes;
 
+/* 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)
+{
+  pass->static_pass_number = id;
+  if (passes_by_id_size <= id)
+    {
+      passes_by_id = XRESIZEVEC (struct 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;
+    }
+  passes_by_id[id] = pass;
+}
+
+/* Return the pass with the static pass number ID.  */
+
+struct opt_pass *
+get_pass_for_id (int id)
+{
+  if (id >= passes_by_id_size)
+    return NULL;
+  return passes_by_id[id];
+}
+
 /* Iterate over the pass tree allocating dump file numbers.  We want
    to do this depth first, and independent of whether the pass is
    enabled or not.  */
@@ -343,7 +374,7 @@ register_one_dump_file (struct opt_pass *pass)
   char *dot_name, *flag_name, *glob_name;
   const char *prefix;
   char num[10];
-  int flags;
+  int flags, id;
 
   /* See below in next_pass_1.  */
   num[0] = '\0';
@@ -352,7 +383,7 @@ register_one_dump_file (struct opt_pass *pass)
                         ? 1 : pass->static_pass_number));
 
   dot_name = concat (".", pass->name, num, NULL);
-  if (pass->type == SIMPLE_IPA_PASS)
+  if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
     prefix = "ipa-", flags = TDF_IPA;
   else if (pass->type == GIMPLE_PASS)
     prefix = "tree-", flags = TDF_TREE;
@@ -361,8 +392,8 @@ register_one_dump_file (struct opt_pass *pass)
 
   flag_name = concat (prefix, pass->name, num, NULL);
   glob_name = concat (prefix, pass->name, NULL);
-  pass->static_pass_number = dump_register (dot_name, flag_name, glob_name,
-                                            flags);
+  id = dump_register (dot_name, flag_name, glob_name, flags);
+  set_pass_for_id (id, pass);
 }
 
 /* Recursive worker function for register_dump_files.  */
@@ -375,7 +406,7 @@ register_dump_files_1 (struct opt_pass *pass, int properties)
       int new_properties = (properties | pass->properties_provided)
                           & ~pass->properties_destroyed;
 
-      if (pass->name)
+      if (pass->name && pass->name[0] != '*')
         register_one_dump_file (pass);
 
       if (pass->sub)
@@ -416,13 +447,13 @@ next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
      pass is already in the list.  */
   if (pass->static_pass_number)
     {
-      struct opt_pass *new;
+      struct opt_pass *new_pass;
 
-      new = xmalloc (sizeof (*new));
-      memcpy (new, pass, sizeof (*new));
-      new->next = NULL;
+      new_pass = XNEW (struct opt_pass);
+      memcpy (new_pass, pass, sizeof (*new_pass));
+      new_pass->next = NULL;
 
-      new->todo_flags_start &= ~TODO_mark_first_instance;
+      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
@@ -431,10 +462,10 @@ next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
       if (pass->name)
         {
           pass->static_pass_number -= 1;
-          new->static_pass_number = -pass->static_pass_number;
+          new_pass->static_pass_number = -pass->static_pass_number;
        }
       
-      *list = new;
+      *list = new_pass;
     }
   else
     {
@@ -492,9 +523,7 @@ init_optimization_passes (void)
   NEXT_PASS (pass_inline_parameters);
   *p = NULL;
 
-  /* Interprocedural optimization passes. 
-     All these passes are ignored in -fno-unit-at-a-time
-     except for subpasses of early_local_passes.  */
+  /* Interprocedural optimization passes.  */
   p = &all_ipa_passes;
   NEXT_PASS (pass_ipa_function_and_variable_visibility);
   NEXT_PASS (pass_ipa_early_inline);
@@ -507,36 +536,38 @@ init_optimization_passes (void)
   NEXT_PASS (pass_early_local_passes);
     {
       struct opt_pass **p = &pass_early_local_passes.pass.sub;
+      NEXT_PASS (pass_fixup_cfg);
       NEXT_PASS (pass_tree_profile);
       NEXT_PASS (pass_cleanup_cfg);
       NEXT_PASS (pass_init_datastructures);
       NEXT_PASS (pass_expand_omp);
+
+      NEXT_PASS (pass_referenced_vars);
+      NEXT_PASS (pass_reset_cc_flags);
+      NEXT_PASS (pass_build_ssa);
+      NEXT_PASS (pass_early_warn_uninitialized);
       NEXT_PASS (pass_all_early_optimizations);
        {
          struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
-         NEXT_PASS (pass_referenced_vars);
-         NEXT_PASS (pass_reset_cc_flags);
-         NEXT_PASS (pass_build_ssa);
-         NEXT_PASS (pass_expand_omp_ssa);
-         NEXT_PASS (pass_early_warn_uninitialized);
          NEXT_PASS (pass_rebuild_cgraph_edges);
          NEXT_PASS (pass_early_inline);
-         NEXT_PASS (pass_cleanup_cfg);
+         NEXT_PASS (pass_remove_cgraph_callee_edges);
          NEXT_PASS (pass_rename_ssa_copies);
          NEXT_PASS (pass_ccp);
          NEXT_PASS (pass_forwprop);
          NEXT_PASS (pass_update_address_taken);
-         NEXT_PASS (pass_simple_dse);
          NEXT_PASS (pass_sra_early);
          NEXT_PASS (pass_copy_prop);
          NEXT_PASS (pass_merge_phi);
-         NEXT_PASS (pass_dce);
-         NEXT_PASS (pass_update_address_taken);
+         NEXT_PASS (pass_cd_dce);
          NEXT_PASS (pass_simple_dse);
          NEXT_PASS (pass_tail_recursion);
+         NEXT_PASS (pass_convert_switch);
+          NEXT_PASS (pass_cleanup_eh);
           NEXT_PASS (pass_profile);
-         NEXT_PASS (pass_release_ssa_names);
+          NEXT_PASS (pass_local_pure_const);
        }
+      NEXT_PASS (pass_release_ssa_names);
       NEXT_PASS (pass_rebuild_cgraph_edges);
       NEXT_PASS (pass_inline_parameters);
     }
@@ -554,36 +585,39 @@ init_optimization_passes (void)
   /* These passes are run after IPA passes on every function that is being
      output to the assembler file.  */
   p = &all_passes;
-  NEXT_PASS (pass_apply_inline);
   NEXT_PASS (pass_all_optimizations);
     {
       struct opt_pass **p = &pass_all_optimizations.pass.sub;
-      NEXT_PASS (pass_create_structure_vars);
-      /* ??? pass_build_alias is a dummy pass that ensures that we
-        execute TODO_rebuild_alias at this point even if
-        pass_create_structure_vars was disabled.  */
-      NEXT_PASS (pass_build_alias);
-      NEXT_PASS (pass_return_slot);
+      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_update_address_taken);
       NEXT_PASS (pass_rename_ssa_copies);
-
-      /* Initial scalar cleanups.  */
+      NEXT_PASS (pass_complete_unrolli);
       NEXT_PASS (pass_ccp);
+      NEXT_PASS (pass_forwprop);
+      /* Ideally the function call conditional
+        dead code elimination phase can be delayed
+        till later where potentially more opportunities
+        can be found.  Due to lack of good ways to
+        update VDEFs associated with the shrink-wrapped
+        calls, it is better to do the transformation
+        here where memory SSA is not built yet.  */
+      NEXT_PASS (pass_call_cdce);
+      /* pass_build_alias is a dummy pass that ensures that we
+        execute TODO_rebuild_alias at this point.  Re-building
+        alias information also rewrites no longer addressed
+        locals into SSA form if possible.  */
+      NEXT_PASS (pass_build_alias);
+      NEXT_PASS (pass_return_slot);
       NEXT_PASS (pass_phiprop);
       NEXT_PASS (pass_fre);
-      NEXT_PASS (pass_dce);
-      NEXT_PASS (pass_forwprop);
       NEXT_PASS (pass_copy_prop);
       NEXT_PASS (pass_merge_phi);
       NEXT_PASS (pass_vrp);
       NEXT_PASS (pass_dce);
       NEXT_PASS (pass_cselim);
-      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_tree_ifcombine);
       NEXT_PASS (pass_phiopt);
       NEXT_PASS (pass_tail_recursion);
@@ -593,21 +627,19 @@ init_optimization_passes (void)
       NEXT_PASS (pass_sra);
       NEXT_PASS (pass_rename_ssa_copies);
       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_dse);
       NEXT_PASS (pass_forwprop);
       NEXT_PASS (pass_phiopt);
       NEXT_PASS (pass_object_sizes);
-      NEXT_PASS (pass_store_ccp);
+      NEXT_PASS (pass_ccp);
       NEXT_PASS (pass_copy_prop);
       NEXT_PASS (pass_fold_builtins);
       NEXT_PASS (pass_cse_sincos);
@@ -629,6 +661,7 @@ init_optimization_passes (void)
          NEXT_PASS (pass_check_data_deps);
          NEXT_PASS (pass_loop_distribution);
          NEXT_PASS (pass_linear_transform);
+         NEXT_PASS (pass_graphite_transforms);
          NEXT_PASS (pass_iv_canon);
          NEXT_PASS (pass_if_conversion);
          NEXT_PASS (pass_vectorize);
@@ -648,14 +681,12 @@ init_optimization_passes (void)
       NEXT_PASS (pass_reassoc);
       NEXT_PASS (pass_vrp);
       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_cd_dce);
       NEXT_PASS (pass_tracer);
 
@@ -675,14 +706,17 @@ init_optimization_passes (void)
       NEXT_PASS (pass_tail_calls);
       NEXT_PASS (pass_rename_ssa_copies);
       NEXT_PASS (pass_uncprop);
-      NEXT_PASS (pass_del_ssa);
-      NEXT_PASS (pass_nrv);
-      NEXT_PASS (pass_mark_used_blocks);
-      NEXT_PASS (pass_cleanup_cfg_post_optimizing);
+      NEXT_PASS (pass_local_pure_const);
     }
+  NEXT_PASS (pass_del_ssa);
+  NEXT_PASS (pass_nrv);
+  NEXT_PASS (pass_mark_used_blocks);
+  NEXT_PASS (pass_cleanup_cfg_post_optimizing);
+
   NEXT_PASS (pass_warn_function_noreturn);
   NEXT_PASS (pass_free_datastructures);
   NEXT_PASS (pass_mudflap_2);
+
   NEXT_PASS (pass_free_cfg_annotations);
   NEXT_PASS (pass_expand);
   NEXT_PASS (pass_rest_of_compilation);
@@ -721,15 +755,15 @@ init_optimization_passes (void)
       NEXT_PASS (pass_cse2);
       NEXT_PASS (pass_rtl_dse1);
       NEXT_PASS (pass_rtl_fwprop_addr);
-      NEXT_PASS (pass_regclass_init);
+      NEXT_PASS (pass_reginfo_init);
       NEXT_PASS (pass_inc_dec);
       NEXT_PASS (pass_initialize_regs);
-      NEXT_PASS (pass_outof_cfg_layout_mode);
       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);
@@ -740,8 +774,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_sms);
       NEXT_PASS (pass_sched);
       NEXT_PASS (pass_subregs_of_mode_init);
-      NEXT_PASS (pass_local_alloc);
-      NEXT_PASS (pass_global_alloc);
+      NEXT_PASS (pass_ira);
       NEXT_PASS (pass_subregs_of_mode_finish);
       NEXT_PASS (pass_postreload);
        {
@@ -752,7 +785,6 @@ init_optimization_passes (void)
          NEXT_PASS (pass_branch_target_load_optimize1);
          NEXT_PASS (pass_thread_prologue_and_epilogue);
          NEXT_PASS (pass_rtl_dse2);
-         NEXT_PASS (pass_rtl_seqabstr);
          NEXT_PASS (pass_stack_adjustments);
          NEXT_PASS (pass_peephole2);
          NEXT_PASS (pass_if_after_reload);
@@ -848,14 +880,17 @@ do_per_function_toporder (void (*callback) (void *data), void *data)
   else
     {
       gcc_assert (!order);
-      order = ggc_alloc (sizeof (*order) * cgraph_n_nodes);
+      order = GGC_NEWVEC (struct cgraph_node *, cgraph_n_nodes);
       nnodes = cgraph_postorder (order);
       for (i = nnodes - 1; i >= 0; i--)
+        order[i]->process = 1;
+      for (i = nnodes - 1; i >= 0; i--)
        {
          struct cgraph_node *node = order[i];
 
          /* Allow possibly removed nodes to be garbage collected.  */
          order[i] = NULL;
+         node->process = 0;
          if (node->analyzed && (node->needed || node->reachable))
            {
              push_cfun (DECL_STRUCT_FUNCTION (node->decl));
@@ -885,7 +920,9 @@ execute_function_todo (void *data)
   flags &= ~cfun->last_verified;
   if (!flags)
     return;
-  
+
+  statistics_fini_pass ();
+
   /* Always cleanup the CFG before trying to update SSA.  */
   if (flags & TODO_cleanup_cfg)
     {
@@ -920,12 +957,10 @@ execute_function_todo (void *data)
   if (flags & TODO_remove_unused_locals)
     remove_unused_locals ();
 
-  if ((flags & TODO_dump_func)
-      && dump_file && current_function_decl)
+  if ((flags & TODO_dump_func) && dump_file && current_function_decl)
     {
       if (cfun->curr_properties & PROP_trees)
-        dump_function_to_file (current_function_decl,
-                               dump_file, dump_flags);
+        dump_function_to_file (current_function_decl, dump_file, dump_flags);
       else
        {
          if (dump_flags & TDF_SLIM)
@@ -936,7 +971,7 @@ execute_function_todo (void *data)
           else
            print_rtl (dump_file, get_insns ());
 
-         if (cfun->curr_properties & PROP_cfg
+         if ((cfun->curr_properties & PROP_cfg)
              && graph_dump_format != no_graph
              && (dump_flags & TDF_GRAPH))
            print_rtl_graph_with_bb (dump_file_name, get_insns ());
@@ -1000,11 +1035,14 @@ execute_todo (unsigned int flags)
      to analyze side effects.  The full removal is done just at the end
      of IPA pass queue.  */
   if (flags & TODO_remove_functions)
-    cgraph_remove_unreachable_nodes (true, dump_file);
+    {
+      gcc_assert (!cfun);
+      cgraph_remove_unreachable_nodes (true, dump_file);
+    }
 
-  if ((flags & TODO_dump_cgraph)
-      && dump_file && !current_function_decl)
+  if ((flags & TODO_dump_cgraph) && dump_file && !current_function_decl)
     {
+      gcc_assert (!cfun);
       dump_cgraph (dump_file);
       /* Flush the file.  If verification fails, we won't be able to
         close the file before aborting.  */
@@ -1012,9 +1050,7 @@ execute_todo (unsigned int flags)
     }
 
   if (flags & TODO_ggc_collect)
-    {
-      ggc_collect ();
-    }
+    ggc_collect ();
 
   /* Now that the dumping has been done, we can get rid of the optional 
      df problems.  */
@@ -1053,16 +1089,138 @@ verify_curr_properties (void *data)
 }
 #endif
 
+/* Initialize pass dump file.  */
+
+static bool
+pass_init_dump_file (struct opt_pass *pass)
+{
+  /* If a dump file name is present, open it if enabled.  */
+  if (pass->static_pass_number != -1)
+    {
+      bool initializing_dump = !dump_initialized_p (pass->static_pass_number);
+      dump_file_name = get_dump_file_name (pass->static_pass_number);
+      dump_file = dump_begin (pass->static_pass_number, &dump_flags);
+      if (dump_file && current_function_decl)
+       {
+         const char *dname, *aname;
+         dname = lang_hooks.decl_printable_name (current_function_decl, 2);
+         aname = (IDENTIFIER_POINTER
+                  (DECL_ASSEMBLER_NAME (current_function_decl)));
+         fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
+            cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+            ? " (hot)"
+            : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+            ? " (unlikely executed)"
+            : "");
+       }
+      return initializing_dump;
+    }
+  else
+    return false;
+}
+
+/* Flush PASS dump file.  */
+
+static void
+pass_fini_dump_file (struct opt_pass *pass)
+{
+  /* Flush and close dump file.  */
+  if (dump_file_name)
+    {
+      free (CONST_CAST (char *, dump_file_name));
+      dump_file_name = NULL;
+    }
+
+  if (dump_file)
+    {
+      dump_end (pass->static_pass_number, dump_file);
+      dump_file = NULL;
+    }
+}
+
 /* After executing the pass, apply expected changes to the function
    properties. */
+
 static void
 update_properties_after_pass (void *data)
 {
-  struct opt_pass *pass = data;
+  struct opt_pass *pass = (struct opt_pass *) data;
   cfun->curr_properties = (cfun->curr_properties | pass->properties_provided)
                           & ~pass->properties_destroyed;
 }
 
+/* Schedule IPA transform pass DATA for CFUN.  */
+
+static void
+add_ipa_transform_pass (void *data)
+{
+  struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *) data;
+  VEC_safe_push (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply, ipa_pass);
+}
+
+/* Execute summary generation for all of the passes in IPA_PASS.  */
+
+static void
+execute_ipa_summary_passes (struct ipa_opt_pass *ipa_pass)
+{
+  while (ipa_pass)
+    {
+      struct opt_pass *pass = &ipa_pass->pass;
+
+      /* Execute all of the IPA_PASSes in the list.  */
+      if (ipa_pass->pass.type == IPA_PASS 
+         && (!pass->gate || pass->gate ()))
+       {
+         pass_init_dump_file (pass);
+         ipa_pass->generate_summary ();
+         pass_fini_dump_file (pass);
+       }
+      ipa_pass = (struct ipa_opt_pass *)ipa_pass->pass.next;
+    }
+}
+
+/* Execute IPA_PASS function transform on NODE.  */
+
+static void
+execute_one_ipa_transform_pass (struct cgraph_node *node,
+                               struct ipa_opt_pass *ipa_pass)
+{
+  struct opt_pass *pass = &ipa_pass->pass;
+  unsigned int todo_after = 0;
+
+  current_pass = pass;
+  if (!ipa_pass->function_transform)
+    return;
+
+  /* Note that the folders should only create gimple expressions.
+     This is a hack until the new folder is ready.  */
+  in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0;
+
+  pass_init_dump_file (pass);
+
+  /* Run pre-pass verification.  */
+  execute_todo (ipa_pass->function_transform_todo_flags_start);
+
+  /* If a timevar is present, start it.  */
+  if (pass->tv_id)
+    timevar_push (pass->tv_id);
+
+  /* Do it!  */
+  todo_after = ipa_pass->function_transform (node);
+
+  /* Stop timevar.  */
+  if (pass->tv_id)
+    timevar_pop (pass->tv_id);
+
+  /* Run post-pass cleanup and verification.  */
+  execute_todo (todo_after);
+  verify_interpass_invariants ();
+
+  pass_fini_dump_file (pass);
+
+  current_pass = NULL;
+}
+
 static bool
 execute_one_pass (struct opt_pass *pass)
 {
@@ -1070,17 +1228,29 @@ execute_one_pass (struct opt_pass *pass)
   unsigned int todo_after = 0;
 
   /* IPA passes are executed on whole program, so cfun should be NULL.
-     Ohter passes needs function context set.  */
-  if (pass->type == SIMPLE_IPA_PASS)
+     Other passes need function context set.  */
+  if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
     gcc_assert (!cfun && !current_function_decl);
   else
+    gcc_assert (cfun && current_function_decl);
+
+  if (cfun && cfun->ipa_transforms_to_apply)
     {
-      gcc_assert (cfun && current_function_decl);
-      gcc_assert (!(cfun->curr_properties & PROP_trees)
-                 || pass->type != RTL_PASS);
+      unsigned int i;
+      struct cgraph_node *node = cgraph_node (current_function_decl);
+
+      for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply);
+          i++)
+       execute_one_ipa_transform_pass (node,
+                                       VEC_index (ipa_opt_pass,
+                                                  cfun->ipa_transforms_to_apply,
+                                                  i));
+      VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
+      cfun->ipa_transforms_to_apply = NULL;
     }
 
   current_pass = pass;
+
   /* See if we're supposed to run this pass.  */
   if (pass->gate && !pass->gate ())
     return false;
@@ -1103,28 +1273,7 @@ execute_one_pass (struct opt_pass *pass)
                   (void *)(size_t)pass->properties_required);
 #endif
 
-  /* If a dump file name is present, open it if enabled.  */
-  if (pass->static_pass_number != -1)
-    {
-      initializing_dump = !dump_initialized_p (pass->static_pass_number);
-      dump_file_name = get_dump_file_name (pass->static_pass_number);
-      dump_file = dump_begin (pass->static_pass_number, &dump_flags);
-      if (dump_file && current_function_decl)
-       {
-         const char *dname, *aname;
-         dname = lang_hooks.decl_printable_name (current_function_decl, 2);
-         aname = (IDENTIFIER_POINTER
-                  (DECL_ASSEMBLER_NAME (current_function_decl)));
-         fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
-            cfun->function_frequency == FUNCTION_FREQUENCY_HOT
-            ? " (hot)"
-            : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
-            ? " (unlikely executed)"
-            : "");
-       }
-    }
-  else
-    initializing_dump = false;
+  initializing_dump = pass_init_dump_file (pass);
 
   /* If a timevar is present, start it.  */
   if (pass->tv_id)
@@ -1146,6 +1295,7 @@ execute_one_pass (struct opt_pass *pass)
   if (initializing_dump
       && dump_file
       && graph_dump_format != no_graph
+      && cfun
       && (cfun->curr_properties & (PROP_cfg | PROP_rtl))
          == (PROP_cfg | PROP_rtl))
     {
@@ -1157,26 +1307,19 @@ execute_one_pass (struct opt_pass *pass)
   /* Run post-pass cleanup and verification.  */
   execute_todo (todo_after | pass->todo_flags_finish);
   verify_interpass_invariants ();
+  if (pass->type == IPA_PASS)
+    do_per_function (add_ipa_transform_pass, pass);
 
   if (!current_function_decl)
     cgraph_process_new_functions ();
 
-  /* Flush and close dump file.  */
-  if (dump_file_name)
-    {
-      free (CONST_CAST (char *, dump_file_name));
-      dump_file_name = NULL;
-    }
+  pass_fini_dump_file (pass);
 
-  if (dump_file)
-    {
-      dump_end (pass->static_pass_number, dump_file);
-      dump_file = NULL;
-    }
+  if (pass->type != SIMPLE_IPA_PASS && pass->type != IPA_PASS)
+    gcc_assert (!(cfun->curr_properties & PROP_trees)
+               || pass->type != RTL_PASS);
 
   current_pass = NULL;
-  /* Reset in_gimple_form to not break non-unit-at-a-time mode.  */
-  in_gimple_form = false;
 
   return true;
 }
@@ -1200,17 +1343,29 @@ execute_pass_list (struct opt_pass *pass)
 void
 execute_ipa_pass_list (struct opt_pass *pass)
 {
+  bool summaries_generated = false;
   do
     {
       gcc_assert (!current_function_decl);
       gcc_assert (!cfun);
-      gcc_assert (pass->type == SIMPLE_IPA_PASS);
+      gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
+      if (pass->type == IPA_PASS && (!pass->gate || pass->gate ()))
+       {
+         if (!summaries_generated)
+           {
+             if (!quiet_flag && !cfun)
+               fprintf (stderr, " <summary generate>");
+             execute_ipa_summary_passes ((struct ipa_opt_pass *) pass);
+           }
+         summaries_generated = true;
+       }
       if (execute_one_pass (pass) && pass->sub)
        {
          if (pass->sub->type == GIMPLE_PASS)
            do_per_function_toporder ((void (*)(void *))execute_pass_list,
                                      pass->sub);
-         else if (pass->sub->type == SIMPLE_IPA_PASS)
+         else if (pass->sub->type == SIMPLE_IPA_PASS
+                  || pass->sub->type == IPA_PASS)
            execute_ipa_pass_list (pass->sub);
          else
            gcc_unreachable ();
@@ -1221,4 +1376,31 @@ execute_ipa_pass_list (struct opt_pass *pass)
     }
   while (pass);
 }
+
+/* Called by local passes to see if function is called by already processed nodes.
+   Because we process nodes in topological order, this means that function is
+   in recursive cycle or we introduced new direct calls.  */
+bool
+function_called_by_processed_nodes_p (void)
+{
+  struct cgraph_edge *e;
+  for (e = cgraph_node (current_function_decl)->callers; e; e = e->next_caller)
+    {
+      if (e->caller->decl == current_function_decl)
+        continue;
+      if (!e->caller->analyzed || (!e->caller->needed && !e->caller->reachable))
+        continue;
+      if (TREE_ASM_WRITTEN (e->caller->decl))
+        continue;
+      if (!e->caller->process && !e->caller->global.inlined_to)
+       break;
+    }
+  if (dump_file && e)
+    {
+      fprintf (dump_file, "Already processed call to:\n");
+      dump_cgraph_node (dump_file, e->caller);
+    }
+  return e != NULL;
+}
+
 #include "gt-passes.h"