OSDN Git Service

2009-10-14 Sebastian Pop <sebastian.pop@amd.com>
[pf3gnuchains/gcc-fork.git] / gcc / passes.c
index fbcdc9e..0c39a7a 100644 (file)
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dump.h"
 #include "df.h"
 #include "predict.h"
+#include "lto-streamer.h"
 
 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
@@ -239,7 +240,7 @@ rest_of_type_compilation (tree type, int toplev)
 void
 finish_optimization_passes (void)
 {
-  enum tree_dump_index i;
+  int i;
   struct dump_file_info *dfi;
   char *name;
 
@@ -288,7 +289,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 +314,7 @@ struct rtl_opt_pass pass_postreload =
 {
  {
   RTL_PASS,
-  NULL,                                 /* name */
+  "*all-postreload",                        /* name */
   gate_postreload,                      /* gate */
   NULL,                                 /* execute */
   NULL,                                 /* sub */
@@ -331,7 +332,8 @@ 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;
 
 /* A map from static pass id to optimization pass.  */
 struct opt_pass **passes_by_id;
@@ -372,7 +374,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 +384,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,8 +399,8 @@ 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);
 }
@@ -437,11 +446,11 @@ register_dump_files (struct opt_pass *pass,int 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.  */
@@ -459,25 +468,205 @@ 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;
-    }  
+    } 
+  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)
+{
+  /* 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 three lists as the reference pass could be in one (or all) of
+     them.  */
+  if (!position_pass (pass_info, &all_lowering_passes)
+      && !position_pass (pass_info, &all_small_ipa_passes)
+      && !position_pass (pass_info, &all_regular_ipa_passes)
+      && !position_pass (pass_info, &all_lto_gen_passes)
+      && !position_pass (pass_info, &all_passes))
+    fatal_error
+      ("pass %qs not found but is referenced by new pass %qs",
+       pass_info->reference_pass_name, pass_info->pass->name);
+  else
+    {
+      /* 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 +679,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,7 +698,8 @@ 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);
@@ -524,7 +714,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 +723,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 +736,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 +772,29 @@ 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_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_wpa_fixup);
+  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;
@@ -595,13 +807,6 @@ init_optimization_passes (void)
       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
@@ -624,6 +829,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
@@ -639,8 +849,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);
@@ -651,15 +861,18 @@ init_optimization_passes (void)
          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_dce_loop);
+             NEXT_PASS (pass_lim);
+           }
          NEXT_PASS (pass_iv_canon);
          NEXT_PASS (pass_if_conversion);
          NEXT_PASS (pass_vectorize);
@@ -668,14 +881,15 @@ 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);
          NEXT_PASS (pass_loop_prefetch);
          NEXT_PASS (pass_iv_optimize);
          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);
@@ -701,21 +915,19 @@ init_optimization_passes (void)
       NEXT_PASS (pass_dse);
       NEXT_PASS (pass_forwprop);
       NEXT_PASS (pass_phiopt);
+      NEXT_PASS (pass_fold_builtins);
       NEXT_PASS (pass_tail_calls);
       NEXT_PASS (pass_rename_ssa_copies);
       NEXT_PASS (pass_uncprop);
       NEXT_PASS (pass_local_pure_const);
     }
   NEXT_PASS (pass_cleanup_eh);
+  NEXT_PASS (pass_lower_resx);
   NEXT_PASS (pass_nrv);
   NEXT_PASS (pass_mudflap_2);
-  NEXT_PASS (pass_mark_used_blocks);
   NEXT_PASS (pass_cleanup_cfg_post_optimizing);
   NEXT_PASS (pass_warn_function_noreturn);
 
-/*  NEXT_PASS (pass_del_ssa);
-  NEXT_PASS (pass_free_datastructures);
-  NEXT_PASS (pass_free_cfg_annotations);*/
   NEXT_PASS (pass_expand);
 
   NEXT_PASS (pass_rest_of_compilation);
@@ -733,8 +945,14 @@ init_optimization_passes (void)
       NEXT_PASS (pass_df_initialize_opt);
       NEXT_PASS (pass_cse);
       NEXT_PASS (pass_rtl_fwprop);
-      NEXT_PASS (pass_gcse);
+      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.  */
@@ -750,11 +968,10 @@ init_optimization_passes (void)
          *p = NULL;
        }
       NEXT_PASS (pass_web);
-      NEXT_PASS (pass_jump_bypass);
+      NEXT_PASS (pass_rtl_cprop);
       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);
@@ -768,13 +985,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;
@@ -823,8 +1037,13 @@ 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_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, 
@@ -845,13 +1064,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)
+       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 ();
@@ -890,7 +1113,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;
@@ -955,7 +1178,6 @@ execute_function_todo (void *data)
       if (!(flags & TODO_update_address_taken))
        execute_update_addresses_taken (true);
       compute_may_aliases ();
-      cfun->curr_properties |= PROP_alias;
     }
   
   if (flags & TODO_remove_unused_locals)
@@ -1154,19 +1376,10 @@ 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 *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)
+void
+execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
 {
   while (ipa_pass)
     {
@@ -1174,13 +1387,24 @@ execute_ipa_summary_passes (struct ipa_opt_pass *ipa_pass)
 
       /* Execute all of the IPA_PASSes in the list.  */
       if (ipa_pass->pass.type == IPA_PASS 
-         && (!pass->gate || pass->gate ()))
+         && (!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 *)ipa_pass->pass.next;
+      ipa_pass = (struct ipa_opt_pass_d *)ipa_pass->pass.next;
     }
 }
 
@@ -1188,7 +1412,7 @@ execute_ipa_summary_passes (struct ipa_opt_pass *ipa_pass)
 
 static void
 execute_one_ipa_transform_pass (struct cgraph_node *node,
-                               struct ipa_opt_pass *ipa_pass)
+                               struct ipa_opt_pass_d *ipa_pass)
 {
   struct opt_pass *pass = &ipa_pass->pass;
   unsigned int todo_after = 0;
@@ -1226,6 +1450,32 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
   current_pass = NULL;
 }
 
+/* For the current function, execute all ipa transforms. */
+
+void
+execute_all_ipa_transforms (void)
+{
+  struct cgraph_node *node;
+  if (!cfun)
+    return;
+  node = cgraph_node (current_function_decl);
+  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;
+    }
+}
+
+/* Execute PASS. */
+
 static bool
 execute_one_pass (struct opt_pass *pass)
 {
@@ -1239,21 +1489,6 @@ 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);
-
-      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.  */
@@ -1263,9 +1498,6 @@ execute_one_pass (struct opt_pass *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;
@@ -1313,7 +1545,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 ();
@@ -1344,26 +1582,177 @@ execute_pass_list (struct opt_pass *pass)
 }
 
 /* Same as execute_pass_list but assume that subpasses of IPA passes
-   are local 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);
+
+  if (!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
-execute_ipa_pass_list (struct opt_pass *pass)
+ipa_write_summaries (void)
 {
-  bool summaries_generated = false;
-  do
+  cgraph_node_set set;
+  struct cgraph_node **order;
+  int i, order_pos;
+  if (!flag_generate_lto || errorcount || sorrycount)
+    return;
+
+  lto_new_extern_inline_states ();
+  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);
+  lto_delete_extern_inline_states ();
+
+  free (order);
+  ggc_free (set);
+}
+
+
+/* Write all the summaries for the cgraph nodes in SET.  If SET is
+   NULL, write out all summaries of all nodes. */
+
+void
+ipa_write_summaries_of_cgraph_node_set (cgraph_node_set set)
+{
+  if (flag_generate_lto && !(errorcount || sorrycount))
+    ipa_write_summaries_1 (set);
+}
+
+/* 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->type == IPA_PASS && (!pass->gate || pass->gate ()))
+
+      if (pass->gate == NULL || pass->gate ())
        {
-         if (!summaries_generated)
+         if (pass->type == IPA_PASS && ipa_pass->read_summary)
            {
-             if (!quiet_flag && !cfun)
-               fprintf (stderr, " <summary generate>");
-             execute_ipa_summary_passes ((struct ipa_opt_pass *) pass);
+             /* 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);
            }
-         summaries_generated = true;
+
+         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
+ipa_read_summaries (void)
+{
+  if (!flag_ltrans)
+    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.  */
+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)
@@ -1375,13 +1764,90 @@ execute_ipa_pass_list (struct opt_pass *pass)
          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");
+}
+
+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.  */
@@ -1393,7 +1859,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;