OSDN Git Service

* cgraph.c (cgraph_create_node): Set node frequency to normal.
[pf3gnuchains/gcc-fork.git] / gcc / passes.c
index 28838b5..e503dc6 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, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -84,6 +84,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dump.h"
 #include "df.h"
 #include "predict.h"
+#include "lto-streamer.h"
+#include "plugin.h"
 
 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
@@ -103,7 +105,8 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 
 /* This is used for debugging.  It allows the current pass to printed
-   from anywhere in compilation.  */
+   from anywhere in compilation.
+   The variable current_pass is also used for statistics and plugins.  */
 struct opt_pass *current_pass;
 
 /* Call from anywhere to find out what pass this is.  Useful for
@@ -113,7 +116,7 @@ void
 print_current_pass (FILE *file)
 {
   if (current_pass)
-    fprintf (file, "current pass = %s (%d)\n", 
+    fprintf (file, "current pass = %s (%d)\n",
             current_pass->name, current_pass->static_pass_number);
   else
     fprintf (file, "no current pass.\n");
@@ -125,7 +128,7 @@ void
 debug_pass (void)
 {
   print_current_pass (stderr);
-} 
+}
 
 
 
@@ -288,7 +291,7 @@ struct gimple_opt_pass pass_rest_of_compilation =
 {
  {
   GIMPLE_PASS,
-  NULL,                                 /* name */
+  "*rest_of_compilation",               /* name */
   gate_rest_of_compilation,             /* gate */
   NULL,                                 /* execute */
   NULL,                                 /* sub */
@@ -313,7 +316,7 @@ struct rtl_opt_pass pass_postreload =
 {
  {
   RTL_PASS,
-  NULL,                                 /* name */
+  "*all-postreload",                        /* name */
   gate_postreload,                      /* gate */
   NULL,                                 /* execute */
   NULL,                                 /* sub */
@@ -331,7 +334,13 @@ 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;
+struct opt_pass *all_passes, *all_small_ipa_passes, *all_lowering_passes,
+  *all_regular_ipa_passes, *all_lto_gen_passes;
+
+/* 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;
@@ -372,7 +381,7 @@ void
 register_one_dump_file (struct opt_pass *pass)
 {
   char *dot_name, *flag_name, *glob_name;
-  const char *prefix;
+  const char *name, *prefix;
   char num[10];
   int flags, id;
 
@@ -382,7 +391,14 @@ register_one_dump_file (struct opt_pass *pass)
     sprintf (num, "%d", ((int) pass->static_pass_number < 0
                         ? 1 : pass->static_pass_number));
 
-  dot_name = concat (".", pass->name, num, NULL);
+  /* The name is both used to identify the pass for the purposes of plugins,
+     and to specify dump file name and option.
+     The latter two might want something short which is not quite unique; for
+     that reason, we may have a disambiguating prefix, followed by a space
+     to mark the start of the following dump file name / option string.  */
+  name = strchr (pass->name, ' ');
+  name = name ? name + 1 : pass->name;
+  dot_name = concat (".", name, num, NULL);
   if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
     prefix = "ipa-", flags = TDF_IPA;
   else if (pass->type == GIMPLE_PASS)
@@ -390,15 +406,15 @@ register_one_dump_file (struct opt_pass *pass)
   else
     prefix = "rtl-", flags = TDF_RTL;
 
-  flag_name = concat (prefix, pass->name, num, NULL);
-  glob_name = concat (prefix, pass->name, NULL);
+  flag_name = concat (prefix, name, num, NULL);
+  glob_name = concat (prefix, name, NULL);
   id = dump_register (dot_name, flag_name, glob_name, flags);
   set_pass_for_id (id, pass);
 }
 
 /* Recursive worker function for register_dump_files.  */
 
-static int 
+static int
 register_dump_files_1 (struct opt_pass *pass, int properties)
 {
   do
@@ -426,22 +442,22 @@ register_dump_files_1 (struct opt_pass *pass, int properties)
   return properties;
 }
 
-/* Register the dump files for the pipeline starting at PASS. 
+/* 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 
+static void
 register_dump_files (struct opt_pass *pass,int properties)
 {
   pass->properties_required |= properties;
   register_dump_files_1 (pass, properties);
 }
 
-/* Add a pass to the pass list. Duplicate the pass if it's already
-   in the list.  */
+/* Look at the static_pass_number and duplicate the pass
+   if it is already added to a list. */
 
-static struct opt_pass **
-next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
+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.  */
@@ -449,8 +465,21 @@ next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
     {
       struct opt_pass *new_pass;
 
-      new_pass = XNEW (struct opt_pass);
-      memcpy (new_pass, pass, sizeof (*new_pass));
+      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 ();
+
       new_pass->next = NULL;
 
       new_pass->todo_flags_start &= ~TODO_mark_first_instance;
@@ -459,25 +488,213 @@ next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
          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)
+      if ((pass->name && pass->name[0] != '*') || track_duplicates)
         {
           pass->static_pass_number -= 1;
           new_pass->static_pass_number = -pass->static_pass_number;
        }
-      
-      *list = new_pass;
+      return new_pass;
     }
   else
     {
       pass->todo_flags_start |= TODO_mark_first_instance;
       pass->static_pass_number = -1;
-      *list = pass;
-    }  
-  
+
+      invoke_plugin_callbacks (PLUGIN_NEW_PASS, 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)
+{
+  /* Every pass should have a name so that plugins can refer to them.  */
+  gcc_assert (pass->name != NULL);
+
+  *list = make_pass_instance (pass, false);
+
   return &(*list)->next;
-          
 }
 
+/* List node for an inserted pass instance. We need to keep track of all
+   the newly-added pass instances (with 'added_pass_nodes' defined below)
+   so that we can register their dump files after pass-positioning is finished.
+   Registering dumping files needs to be post-processed or the
+   static_pass_number of the opt_pass object would be modified and mess up
+   the dump file names of future pass instances to be added.  */
+
+struct pass_list_node
+{
+  struct opt_pass *pass;
+  struct pass_list_node *next;
+};
+
+static struct pass_list_node *added_pass_nodes = NULL;
+static struct pass_list_node *prev_added_pass_node;
+
+/* Insert the pass at the proper position. Return true if the pass
+   is successfully added.
+
+   NEW_PASS_INFO - new pass to be inserted
+   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)
+{
+  struct opt_pass *pass = *pass_list, *prev_pass = NULL;
+  bool success = false;
+
+  for ( ; pass; prev_pass = pass, pass = pass->next)
+    {
+      /* Check if the current pass is of the same type as the new pass and
+         matches the name and the instance number of the reference pass.  */
+      if (pass->type == new_pass_info->pass->type
+          && pass->name
+          && !strcmp (pass->name, new_pass_info->reference_pass_name)
+          && ((new_pass_info->ref_pass_instance_number == 0)
+              || (new_pass_info->ref_pass_instance_number ==
+                  pass->static_pass_number)
+              || (new_pass_info->ref_pass_instance_number == 1
+                  && pass->todo_flags_start & TODO_mark_first_instance)))
+        {
+          struct opt_pass *new_pass;
+          struct pass_list_node *new_pass_node;
+
+         new_pass = make_pass_instance (new_pass_info->pass, true);
+
+          /* Insert the new pass instance based on the positioning op.  */
+          switch (new_pass_info->pos_op)
+            {
+              case PASS_POS_INSERT_AFTER:
+                new_pass->next = pass->next;
+                pass->next = new_pass;
+
+               /* Skip newly inserted pass to avoid repeated
+                  insertions in the case where the new pass and the
+                  existing one have the same name.  */
+                pass = new_pass;
+                break;
+              case PASS_POS_INSERT_BEFORE:
+                new_pass->next = pass;
+                if (prev_pass)
+                  prev_pass->next = new_pass;
+                else
+                  *pass_list = new_pass;
+                break;
+              case PASS_POS_REPLACE:
+                new_pass->next = pass->next;
+                if (prev_pass)
+                  prev_pass->next = new_pass;
+                else
+                  *pass_list = new_pass;
+                new_pass->sub = pass->sub;
+                new_pass->tv_id = pass->tv_id;
+                pass = new_pass;
+                break;
+              default:
+                error ("Invalid pass positioning operation");
+                return false;
+            }
+
+          /* Save the newly added pass (instance) in the added_pass_nodes
+             list so that we can register its dump file later. Note that
+             we cannot register the dump file now because doing so will modify
+             the static_pass_number of the opt_pass object and therefore
+             mess up the dump file name of future instances.  */
+          new_pass_node = XCNEW (struct pass_list_node);
+          new_pass_node->pass = new_pass;
+          if (!added_pass_nodes)
+            added_pass_nodes = new_pass_node;
+          else
+            prev_added_pass_node->next = new_pass_node;
+          prev_added_pass_node = new_pass_node;
+
+          success = true;
+        }
+
+      if (pass->sub && position_pass (new_pass_info, &pass->sub))
+        success = true;
+    }
+
+  return success;
+}
+
+/* Hooks a new pass into the pass lists.
+
+   PASS_INFO   - pass information that specifies the opt_pass object,
+                 reference pass, instance number, and how to position
+                 the pass  */
+
+void
+register_pass (struct register_pass_info *pass_info)
+{
+  bool all_instances, success;
+
+  /* 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");
+
+  if (!pass_info->pass->name)
+      fatal_error ("plugin cannot register an unnamed pass");
+
+  if (!pass_info->reference_pass_name)
+      fatal_error
+       ("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
+     all five lists as the reference pass could be in one (or all) of
+     them.  */
+  all_instances = pass_info->ref_pass_instance_number == 0;
+  success = position_pass (pass_info, &all_lowering_passes);
+  if (!success || all_instances)
+    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_passes);
+  if (!success)
+    fatal_error
+      ("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
+     the dump files for the newly added pass and its duplicates (if any).
+     Because the registration of plugin/backend passes happens after the
+     command-line options are parsed, the options that specify single
+     pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
+     passes. Therefore we currently can only enable dumping of
+     new passes when the 'dump-all' flags (e.g. -fdump-tree-all)
+     are specified. While doing so, we also delete the pass_list_node
+     objects created during pass positioning.  */
+  while (added_pass_nodes)
+    {
+      struct pass_list_node *next_node = added_pass_nodes->next;
+      enum tree_dump_index tdi;
+      register_one_dump_file (added_pass_nodes->pass);
+      if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
+          || added_pass_nodes->pass->type == IPA_PASS)
+        tdi = TDI_ipa_all;
+      else if (added_pass_nodes->pass->type == GIMPLE_PASS)
+        tdi = TDI_tree_all;
+      else
+        tdi = TDI_rtl_all;
+      /* Check if dump-all flag is specified.  */
+      if (get_dump_file_info (tdi)->state)
+        get_dump_file_info (added_pass_nodes->pass->static_pass_number)
+            ->state = get_dump_file_info (tdi)->state;
+      XDELETE (added_pass_nodes);
+      added_pass_nodes = next_node;
+    }
+}
 
 /* Construct the pass tree.  The sequencing of passes is driven by
    the cgraph routines:
@@ -490,7 +707,7 @@ next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
    If we are optimizing, cgraph_optimize is then invoked:
 
    cgraph_optimize ()
-       ipa_passes ()                   -> all_ipa_passes
+       ipa_passes ()                   -> all_small_ipa_passes
        cgraph_expand_all_functions ()
            for each node N in the cgraph
               cgraph_expand_function (N)
@@ -509,14 +726,14 @@ init_optimization_passes (void)
     backend might produce already lowered functions that are not processed
     by these passes.  */
   p = &all_lowering_passes;
-  NEXT_PASS (pass_remove_useless_stmts);
+  NEXT_PASS (pass_warn_unused_result);
+  NEXT_PASS (pass_diagnose_omp_blocks);
   NEXT_PASS (pass_mudflap_1);
   NEXT_PASS (pass_lower_omp);
   NEXT_PASS (pass_lower_cf);
   NEXT_PASS (pass_refactor_eh);
   NEXT_PASS (pass_lower_eh);
   NEXT_PASS (pass_build_cfg);
-  NEXT_PASS (pass_lower_complex_O0);
   NEXT_PASS (pass_lower_vector);
   NEXT_PASS (pass_warn_function_return);
   NEXT_PASS (pass_build_cgraph_edges);
@@ -524,7 +741,7 @@ init_optimization_passes (void)
   *p = NULL;
 
   /* Interprocedural optimization passes.  */
-  p = &all_ipa_passes;
+  p = &all_small_ipa_passes;
   NEXT_PASS (pass_ipa_function_and_variable_visibility);
   NEXT_PASS (pass_ipa_early_inline);
     {
@@ -533,6 +750,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_inline_parameters);
       NEXT_PASS (pass_rebuild_cgraph_edges);
     }
+  NEXT_PASS (pass_ipa_free_lang_data);
   NEXT_PASS (pass_early_local_passes);
     {
       struct opt_pass **p = &pass_early_local_passes.pass.sub;
@@ -545,20 +763,30 @@ init_optimization_passes (void)
       NEXT_PASS (pass_referenced_vars);
       NEXT_PASS (pass_build_ssa);
       NEXT_PASS (pass_early_warn_uninitialized);
+      /* Note that it is not strictly necessary to schedule an early
+        inline pass here.  However, some test cases (e.g.,
+        g++.dg/other/p334435.C g++.dg/other/i386-1.C) expect extern
+        inline functions to be inlined even at -O0.  This does not
+        happen during the first early inline pass.  */
+      NEXT_PASS (pass_rebuild_cgraph_edges);
+      NEXT_PASS (pass_early_inline);
       NEXT_PASS (pass_all_early_optimizations);
        {
          struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
-         NEXT_PASS (pass_rebuild_cgraph_edges);
-         NEXT_PASS (pass_early_inline);
          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);
+         /* pass_build_ealias 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_ealias);
          NEXT_PASS (pass_sra_early);
          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);
@@ -571,18 +799,28 @@ init_optimization_passes (void)
     }
   NEXT_PASS (pass_ipa_increase_alignment);
   NEXT_PASS (pass_ipa_matrix_reorg);
+  *p = NULL;
+
+  p = &all_regular_ipa_passes;
+  NEXT_PASS (pass_ipa_whole_program_visibility);
   NEXT_PASS (pass_ipa_cp);
   NEXT_PASS (pass_ipa_inline);
   NEXT_PASS (pass_ipa_reference);
-  NEXT_PASS (pass_ipa_pure_const); 
+  NEXT_PASS (pass_ipa_pure_const);
   NEXT_PASS (pass_ipa_type_escape);
   NEXT_PASS (pass_ipa_pta);
-  NEXT_PASS (pass_ipa_struct_reorg);  
+  NEXT_PASS (pass_ipa_struct_reorg);
+  *p = NULL;
+
+  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;
 
   /* These passes are run after IPA passes on every function that is being
      output to the assembler file.  */
   p = &all_passes;
+  NEXT_PASS (pass_lower_eh_dispatch);
   NEXT_PASS (pass_all_optimizations);
     {
       struct opt_pass **p = &pass_all_optimizations.pass.sub;
@@ -617,6 +855,11 @@ init_optimization_passes (void)
       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
@@ -632,8 +875,8 @@ init_optimization_passes (void)
       NEXT_PASS (pass_object_sizes);
       NEXT_PASS (pass_ccp);
       NEXT_PASS (pass_copy_prop);
-      NEXT_PASS (pass_fold_builtins);
       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);
@@ -641,18 +884,22 @@ init_optimization_passes (void)
        {
          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_lim);
-         NEXT_PASS (pass_predcom);
          NEXT_PASS (pass_tree_unswitch);
          NEXT_PASS (pass_scev_cprop);
-         NEXT_PASS (pass_empty_loop);
          NEXT_PASS (pass_record_bounds);
          NEXT_PASS (pass_check_data_deps);
          NEXT_PASS (pass_loop_distribution);
          NEXT_PASS (pass_linear_transform);
          NEXT_PASS (pass_graphite_transforms);
+           {
+             struct opt_pass **p = &pass_graphite_transforms.pass.sub;
+             NEXT_PASS (pass_copy_prop);
+             NEXT_PASS (pass_dce_loop);
+             NEXT_PASS (pass_lim);
+           }
          NEXT_PASS (pass_iv_canon);
          NEXT_PASS (pass_if_conversion);
          NEXT_PASS (pass_vectorize);
@@ -661,6 +908,7 @@ init_optimization_passes (void)
              NEXT_PASS (pass_lower_vector_ssa);
              NEXT_PASS (pass_dce_loop);
            }
+          NEXT_PASS (pass_predcom);
          NEXT_PASS (pass_complete_unroll);
          NEXT_PASS (pass_slp_vectorize);
          NEXT_PASS (pass_parallelize_loops);
@@ -669,7 +917,6 @@ init_optimization_passes (void)
          NEXT_PASS (pass_tree_loop_done);
        }
       NEXT_PASS (pass_cse_reciprocals);
-      NEXT_PASS (pass_convert_to_rsqrt);
       NEXT_PASS (pass_reassoc);
       NEXT_PASS (pass_vrp);
       NEXT_PASS (pass_dominator);
@@ -686,7 +933,7 @@ init_optimization_passes (void)
         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
@@ -695,12 +942,16 @@ init_optimization_passes (void)
       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_lower_complex_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);
@@ -730,6 +981,7 @@ init_optimization_passes (void)
       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.  */
@@ -749,7 +1001,6 @@ init_optimization_passes (void)
       NEXT_PASS (pass_cse2);
       NEXT_PASS (pass_rtl_dse1);
       NEXT_PASS (pass_rtl_fwprop_addr);
-      NEXT_PASS (pass_reginfo_init);
       NEXT_PASS (pass_inc_dec);
       NEXT_PASS (pass_initialize_regs);
       NEXT_PASS (pass_ud_rtl_dce);
@@ -763,13 +1014,10 @@ init_optimization_passes (void)
       NEXT_PASS (pass_df_initialize_no_opt);
       NEXT_PASS (pass_stack_ptr_mod);
       NEXT_PASS (pass_mode_switching);
-      NEXT_PASS (pass_see);
       NEXT_PASS (pass_match_asm_constraints);
       NEXT_PASS (pass_sms);
       NEXT_PASS (pass_sched);
-      NEXT_PASS (pass_subregs_of_mode_init);
       NEXT_PASS (pass_ira);
-      NEXT_PASS (pass_subregs_of_mode_finish);
       NEXT_PASS (pass_postreload);
        {
          struct opt_pass **p = &pass_postreload.pass.sub;
@@ -818,18 +1066,23 @@ init_optimization_passes (void)
 
   /* Register the passes with the tree dump code.  */
   register_dump_files (all_lowering_passes, PROP_gimple_any);
-  all_lowering_passes->todo_flags_start |= TODO_set_props;
-  register_dump_files (all_ipa_passes, 
+  register_dump_files (all_small_ipa_passes,
                       PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
                       | PROP_cfg);
-  register_dump_files (all_passes, 
+  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_passes,
                       PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
                       | PROP_cfg);
 }
 
 /* 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.  */ 
+   call CALLBACK on the current function.  */
 
 static void
 do_per_function (void (*callback) (void *data), void *data)
@@ -840,13 +1093,17 @@ do_per_function (void (*callback) (void *data), void *data)
     {
       struct cgraph_node *node;
       for (node = cgraph_nodes; node; node = node->next)
-       if (node->analyzed && gimple_has_body_p (node->decl))
+       if (node->analyzed && gimple_has_body_p (node->decl)
+           && (!node->clone_of || node->decl != node->clone_of->decl))
          {
            push_cfun (DECL_STRUCT_FUNCTION (node->decl));
            current_function_decl = node->decl;
            callback (data);
-           free_dominance_info (CDI_DOMINATORS);
-           free_dominance_info (CDI_POST_DOMINATORS);
+           if (!flag_wpa)
+             {
+               free_dominance_info (CDI_DOMINATORS);
+               free_dominance_info (CDI_POST_DOMINATORS);
+             }
            current_function_decl = NULL;
            pop_cfun ();
            ggc_collect ();
@@ -862,9 +1119,9 @@ static GTY ((length ("nnodes"))) struct cgraph_node **order;
 
 /* 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.  */ 
-
-static void
+   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)
 {
   int i;
@@ -885,7 +1142,7 @@ do_per_function_toporder (void (*callback) (void *data), void *data)
          /* Allow possibly removed nodes to be garbage collected.  */
          order[i] = NULL;
          node->process = 0;
-         if (node->analyzed && (node->needed || node->reachable))
+         if (node->analyzed)
            {
              push_cfun (DECL_STRUCT_FUNCTION (node->decl));
              current_function_decl = node->decl;
@@ -924,7 +1181,7 @@ execute_function_todo (void *data)
 
       if (cleanup && (cfun->curr_properties & PROP_ssa))
        flags |= TODO_remove_unused_locals;
-       
+
       /* When cleanup_tree_cfg merges consecutive blocks, it may
         perform some simplistic propagation when removing single
         valued PHI nodes.  This propagation may, in turn, cause the
@@ -941,7 +1198,7 @@ execute_function_todo (void *data)
       update_ssa (update_flags);
       cfun->last_verified &= ~TODO_verify_ssa;
     }
-  
+
   if (flags & TODO_update_address_taken)
     execute_update_addresses_taken (true);
 
@@ -951,7 +1208,7 @@ execute_function_todo (void *data)
        execute_update_addresses_taken (true);
       compute_may_aliases ();
     }
-  
+
   if (flags & TODO_remove_unused_locals)
     remove_unused_locals ();
 
@@ -999,14 +1256,15 @@ execute_function_todo (void *data)
     }
 
 #if defined ENABLE_CHECKING
-  if (flags & TODO_verify_ssa)
+  if (flags & TODO_verify_ssa
+      || (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA)))
     verify_ssa (true);
   if (flags & TODO_verify_flow)
     verify_flow_info ();
   if (flags & TODO_verify_stmts)
     verify_stmts ();
-  if (flags & TODO_verify_loops)
-    verify_loop_closed_ssa ();
+  if (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA))
+    verify_loop_closed_ssa (false);
   if (flags & TODO_verify_rtl_sharing)
     verify_rtl_sharing ();
 #endif
@@ -1051,7 +1309,7 @@ execute_todo (unsigned int flags)
   if (flags & TODO_ggc_collect)
     ggc_collect ();
 
-  /* Now that the dumping has been done, we can get rid of the optional 
+  /* Now that the dumping has been done, we can get rid of the optional
      df problems.  */
   if (flags & TODO_df_finish)
     df_finish_pass ((flags & TODO_df_verify) != 0);
@@ -1089,8 +1347,9 @@ verify_curr_properties (void *data)
 #endif
 
 /* Initialize pass dump file.  */
+/* This is non-static so that the plugins can use it.  */
 
-static bool
+bool
 pass_init_dump_file (struct opt_pass *pass)
 {
   /* If a dump file name is present, open it if enabled.  */
@@ -1102,14 +1361,17 @@ pass_init_dump_file (struct opt_pass *pass)
       if (dump_file && current_function_decl)
        {
          const char *dname, *aname;
+         struct cgraph_node *node = cgraph_node (current_function_decl);
          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
+            node->frequency == NODE_FREQUENCY_HOT
             ? " (hot)"
-            : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
             ? " (unlikely executed)"
+            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+            ? " (executed once)"
             : "");
        }
       return initializing_dump;
@@ -1119,8 +1381,9 @@ pass_init_dump_file (struct opt_pass *pass)
 }
 
 /* Flush PASS dump file.  */
+/* This is non-static so that plugins can use it.  */
 
-static void
+void
 pass_fini_dump_file (struct opt_pass *pass)
 {
   /* Flush and close dump file.  */
@@ -1148,18 +1411,9 @@ update_properties_after_pass (void *data)
                           & ~pass->properties_destroyed;
 }
 
-/* Schedule IPA transform pass DATA for CFUN.  */
-
-static void
-add_ipa_transform_pass (void *data)
-{
-  struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) 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
+void
 execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
 {
   while (ipa_pass)
@@ -1167,11 +1421,22 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *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 ()))
+      if (ipa_pass->pass.type == IPA_PASS
+         && (!pass->gate || pass->gate ())
+         && ipa_pass->generate_summary)
        {
          pass_init_dump_file (pass);
+
+         /* If a timevar is present, start it.  */
+         if (pass->tv_id)
+           timevar_push (pass->tv_id);
+
          ipa_pass->generate_summary ();
+
+         /* Stop timevar.  */
+         if (pass->tv_id)
+           timevar_pop (pass->tv_id);
+
          pass_fini_dump_file (pass);
        }
       ipa_pass = (struct ipa_opt_pass_d *)ipa_pass->pass.next;
@@ -1220,12 +1485,51 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
   current_pass = NULL;
 }
 
-static bool
+/* For the current function, execute all ipa transforms. */
+
+void
+execute_all_ipa_transforms (void)
+{
+  enum cgraph_state old_state = cgraph_state;
+  struct cgraph_node *node;
+  if (!cfun)
+    return;
+  node = cgraph_node (current_function_decl);
+
+  /* Statement verification skip verification of nothorw when
+     state is IPA_SSA because we do not modify function bodies
+     after setting the flag on function.  Instead we leave it
+     to fixup_cfg to do such a transformation.  We need to temporarily
+     change the cgraph state so statement verifier before
+     transform do not fire.  */
+  cgraph_state = CGRAPH_STATE_IPA_SSA;
+
+  if (node->ipa_transforms_to_apply)
+    {
+      unsigned int i;
+
+      for (i = 0; i < VEC_length (ipa_opt_pass, node->ipa_transforms_to_apply);
+          i++)
+       execute_one_ipa_transform_pass (node,
+                                       VEC_index (ipa_opt_pass,
+                                                  node->ipa_transforms_to_apply,
+                                                  i));
+      VEC_free (ipa_opt_pass, heap, node->ipa_transforms_to_apply);
+      node->ipa_transforms_to_apply = NULL;
+    }
+  cgraph_state = old_state;
+}
+
+/* Execute PASS. */
+
+bool
 execute_one_pass (struct opt_pass *pass)
 {
   bool initializing_dump;
   unsigned int todo_after = 0;
 
+  bool gate_status;
+
   /* IPA passes are executed on whole program, so cfun should be NULL.
      Other passes need function context set.  */
   if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
@@ -1233,33 +1537,28 @@ execute_one_pass (struct opt_pass *pass)
   else
     gcc_assert (cfun && current_function_decl);
 
-  if (cfun && cfun->ipa_transforms_to_apply)
-    {
-      unsigned int i;
-      struct cgraph_node *node = cgraph_node (current_function_decl);
+  current_pass = pass;
 
-      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;
-    }
+  /* 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();
 
-  current_pass = pass;
+  /* Override gate with plugin.  */
+  invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status);
 
-  /* See if we're supposed to run this pass.  */
-  if (pass->gate && !pass->gate ())
-    return false;
+  if (!gate_status)
+    {
+      current_pass = NULL;
+      return false;
+    }
+
+  /* Pass execution event trigger: useful to identify passes being
+     executed.  */
+  invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass);
 
   if (!quiet_flag && !cfun)
     fprintf (stderr, " <%s>", pass->name ? pass->name : "");
 
-  if (pass->todo_flags_start & TODO_set_props)
-    cfun->curr_properties = pass->properties_required;
-
   /* 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;
@@ -1307,7 +1606,13 @@ execute_one_pass (struct opt_pass *pass)
   execute_todo (todo_after | pass->todo_flags_finish);
   verify_interpass_invariants ();
   if (pass->type == IPA_PASS)
-    do_per_function (add_ipa_transform_pass, pass);
+    {
+      struct cgraph_node *node;
+      for (node = cgraph_nodes; node; node = node->next)
+        if (node->analyzed)
+          VEC_safe_push (ipa_opt_pass, heap, node->ipa_transforms_to_apply,
+                        (struct ipa_opt_pass_d *)pass);
+    }
 
   if (!current_function_decl)
     cgraph_process_new_functions ();
@@ -1338,44 +1643,363 @@ execute_pass_list (struct opt_pass *pass)
 }
 
 /* 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, cgraph_node_set set,
+                      struct lto_out_decl_state *state)
+{
+  while (pass)
+    {
+      struct ipa_opt_pass_d *ipa_pass = (struct 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 ()))
+       {
+         /* If a timevar is present, start it.  */
+         if (pass->tv_id)
+           timevar_push (pass->tv_id);
+
+         ipa_pass->write_summary (set);
+
+         /* If a timevar is present, start it.  */
+         if (pass->tv_id)
+           timevar_pop (pass->tv_id);
+       }
+
+      if (pass->sub && pass->sub->type != GIMPLE_PASS)
+       ipa_write_summaries_2 (pass->sub, set, state);
+
+      pass = pass->next;
+    }
+}
+
+/* Helper function of ipa_write_summaries. Creates and destroys the
+   decl state and calls ipa_write_summaries_2 for all passes that have
+   summaries.  SET is the set of nodes to be written.  */
+
+static void
+ipa_write_summaries_1 (cgraph_node_set set)
+{
+  struct lto_out_decl_state *state = lto_new_out_decl_state ();
+  lto_push_out_decl_state (state);
+
+  gcc_assert (!flag_wpa);
+  ipa_write_summaries_2 (all_regular_ipa_passes, set, state);
+  ipa_write_summaries_2 (all_lto_gen_passes, set, state);
+
+  gcc_assert (lto_get_out_decl_state () == state);
+  lto_pop_out_decl_state ();
+  lto_delete_out_decl_state (state);
+}
+
+/* Write out summaries for all the nodes in the callgraph.  */
+
+void
+ipa_write_summaries (void)
+{
+  cgraph_node_set set;
+  struct cgraph_node **order;
+  int i, order_pos;
+
+  if (!flag_generate_lto || errorcount || sorrycount)
+    return;
+
+  set = cgraph_node_set_new ();
+
+  /* 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_pos = cgraph_postorder (order);
+  gcc_assert (order_pos == cgraph_n_nodes);
+
+  for (i = order_pos - 1; i >= 0; i--)
+    {
+      struct cgraph_node *node = order[i];
+
+      if (node->analyzed)
+       {
+         /* When streaming out references to statements as part of some IPA
+            pass summary, the statements need to have uids assigned and the
+            following does that for all the IPA passes here. Naturally, this
+            ordering then matches the one IPA-passes get in their stmt_fixup
+            hooks.  */
+
+         push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+         renumber_gimple_stmt_uids ();
+         pop_cfun ();
+       }
+      cgraph_node_set_add (set, node);
+    }
+
+  ipa_write_summaries_1 (set);
+
+  free (order);
+  ggc_free (set);
+}
+
+/* Same as execute_pass_list but assume that subpasses of IPA passes
+   are local passes. If SET is not NULL, write out optimization summaries of
+   only those node in SET. */
+
+static void
+ipa_write_optimization_summaries_1 (struct opt_pass *pass, cgraph_node_set set,
+                      struct lto_out_decl_state *state)
+{
+  while (pass)
+    {
+      struct ipa_opt_pass_d *ipa_pass = (struct 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 ()))
+       {
+         /* If a timevar is present, start it.  */
+         if (pass->tv_id)
+           timevar_push (pass->tv_id);
+
+         ipa_pass->write_optimization_summary (set);
+
+         /* If a timevar is present, start it.  */
+         if (pass->tv_id)
+           timevar_pop (pass->tv_id);
+       }
+
+      if (pass->sub && pass->sub->type != GIMPLE_PASS)
+       ipa_write_optimization_summaries_1 (pass->sub, set, state);
+
+      pass = pass->next;
+    }
+}
+
+/* Write all the optimization summaries for the cgraph nodes in SET.  If SET is
+   NULL, write out all summaries of all nodes. */
+
+void
+ipa_write_optimization_summaries (cgraph_node_set set)
+{
+  struct lto_out_decl_state *state = lto_new_out_decl_state ();
+  lto_push_out_decl_state (state);
+
+  gcc_assert (flag_wpa);
+  ipa_write_optimization_summaries_1 (all_regular_ipa_passes, set, state);
+  ipa_write_optimization_summaries_1 (all_lto_gen_passes, set, state);
+
+  gcc_assert (lto_get_out_decl_state () == state);
+  lto_pop_out_decl_state ();
+  lto_delete_out_decl_state (state);
+}
+
+/* Same as execute_pass_list but assume that subpasses of IPA passes
    are local passes.  */
+
+static void
+ipa_read_summaries_1 (struct opt_pass *pass)
+{
+  while (pass)
+    {
+      struct ipa_opt_pass_d *ipa_pass = (struct 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->type == IPA_PASS && ipa_pass->read_summary)
+           {
+             /* If a timevar is present, start it.  */
+             if (pass->tv_id)
+               timevar_push (pass->tv_id);
+
+             ipa_pass->read_summary ();
+
+             /* Stop timevar.  */
+             if (pass->tv_id)
+               timevar_pop (pass->tv_id);
+           }
+
+         if (pass->sub && pass->sub->type != GIMPLE_PASS)
+           ipa_read_summaries_1 (pass->sub);
+       }
+      pass = pass->next;
+    }
+}
+
+
+/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes.  */
+
 void
-execute_ipa_pass_list (struct opt_pass *pass)
+ipa_read_summaries (void)
 {
-  bool summaries_generated = false;
-  do
+  ipa_read_summaries_1 (all_regular_ipa_passes);
+  ipa_read_summaries_1 (all_lto_gen_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)
+{
+  while (pass)
     {
+      struct ipa_opt_pass_d *ipa_pass = (struct 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 && (!pass->gate || pass->gate ()))
+
+      if (pass->gate == NULL || pass->gate ())
        {
-         if (!summaries_generated)
+         if (pass->type == IPA_PASS && ipa_pass->read_optimization_summary)
            {
-             if (!quiet_flag && !cfun)
-               fprintf (stderr, " <summary generate>");
-             execute_ipa_summary_passes ((struct ipa_opt_pass_d *) pass);
+             /* If a timevar is present, start it.  */
+             if (pass->tv_id)
+               timevar_push (pass->tv_id);
+
+             ipa_pass->read_optimization_summary ();
+
+             /* Stop timevar.  */
+             if (pass->tv_id)
+               timevar_pop (pass->tv_id);
            }
-         summaries_generated = true;
+
+         if (pass->sub && pass->sub->type != GIMPLE_PASS)
+           ipa_read_optimization_summaries_1 (pass->sub);
        }
+      pass = pass->next;
+    }
+}
+
+/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_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);
+}
+
+/* Same as execute_pass_list but assume that subpasses of IPA passes
+   are local passes.  */
+void
+execute_ipa_pass_list (struct opt_pass *pass)
+{
+  do
+    {
+      gcc_assert (!current_function_decl);
+      gcc_assert (!cfun);
+      gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
       if (execute_one_pass (pass) && pass->sub)
        {
          if (pass->sub->type == GIMPLE_PASS)
-           do_per_function_toporder ((void (*)(void *))execute_pass_list,
-                                     pass->sub);
+           {
+             invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
+             do_per_function_toporder ((void (*)(void *))execute_pass_list,
+                                       pass->sub);
+             invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
+           }
          else if (pass->sub->type == SIMPLE_IPA_PASS
                   || pass->sub->type == IPA_PASS)
            execute_ipa_pass_list (pass->sub);
          else
            gcc_unreachable ();
        }
-      if (!current_function_decl)
-       cgraph_process_new_functions ();
+      gcc_assert (!current_function_decl);
+      cgraph_process_new_functions ();
       pass = pass->next;
     }
   while (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)
+{
+  while (pass)
+    {
+      /* Execute all of the IPA_PASSes in the list.  */
+      if (pass->type == IPA_PASS
+         && (!pass->gate || pass->gate ()))
+       {
+         struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
+
+         if (ipa_pass->stmt_fixup)
+           {
+             pass_init_dump_file (pass);
+             /* If a timevar is present, start it.  */
+             if (pass->tv_id)
+               timevar_push (pass->tv_id);
+
+             ipa_pass->stmt_fixup (node, stmts);
+
+             /* Stop timevar.  */
+             if (pass->tv_id)
+               timevar_pop (pass->tv_id);
+             pass_fini_dump_file (pass);
+           }
+         if (pass->sub)
+           execute_ipa_stmt_fixups (pass->sub, node, stmts);
+       }
+      pass = pass->next;
+    }
+}
+
+/* Execute stmt fixup hooks of all IPA passes for NODE and STMTS.  */
+
+void
+execute_all_ipa_stmt_fixups (struct cgraph_node *node, gimple *stmts)
+{
+  execute_ipa_stmt_fixups (all_regular_ipa_passes, node, stmts);
+}
+
+
+extern void debug_properties (unsigned int);
+extern void dump_properties (FILE *, unsigned int);
+
+void
+dump_properties (FILE *dump, unsigned int props)
+{
+  fprintf (dump, "Properties:\n");
+  if (props & PROP_gimple_any)
+    fprintf (dump, "PROP_gimple_any\n");
+  if (props & PROP_gimple_lcf)
+    fprintf (dump, "PROP_gimple_lcf\n");
+  if (props & PROP_gimple_leh)
+    fprintf (dump, "PROP_gimple_leh\n");
+  if (props & PROP_cfg)
+    fprintf (dump, "PROP_cfg\n");
+  if (props & PROP_referenced_vars)
+    fprintf (dump, "PROP_referenced_vars\n");
+  if (props & PROP_ssa)
+    fprintf (dump, "PROP_ssa\n");
+  if (props & PROP_no_crit_edges)
+    fprintf (dump, "PROP_no_crit_edges\n");
+  if (props & PROP_rtl)
+    fprintf (dump, "PROP_rtl\n");
+  if (props & PROP_gimple_lomp)
+    fprintf (dump, "PROP_gimple_lomp\n");
+  if (props & PROP_gimple_lcx)
+    fprintf (dump, "PROP_gimple_lcx\n");
+}
+
+void
+debug_properties (unsigned int props)
+{
+  dump_properties (stderr, props);
+}
+
 /* 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.  */
@@ -1387,7 +2011,7 @@ function_called_by_processed_nodes_p (void)
     {
       if (e->caller->decl == current_function_decl)
         continue;
-      if (!e->caller->analyzed || (!e->caller->needed && !e->caller->reachable))
+      if (!e->caller->analyzed)
         continue;
       if (TREE_ASM_WRITTEN (e->caller->decl))
         continue;