OSDN Git Service

* ipa-cp.c (ipcp_write_summary, ipcp_read_summary): New functions.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 22 Oct 2009 10:02:29 +0000 (10:02 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 22 Oct 2009 10:02:29 +0000 (10:02 +0000)
(pass_ipa_cp): Register them.
(ipcp_init_stage): Analyze all functions for whopr/lto.
(ipcp_propagate_stage): Skip external calls.
(ipcp_iterate_stage): Call ipa_update_after_lto_read if needed.
* ipa-reference.c (write_node_summary_p): Fix thinko about availability.
* cgraphunit.c (ipa_passes): When in lto, ne er produce new summaries;
when in ltrans, skip executing of ipa passes since everything should've
been done.
* ipa-inline.c (cgraph_decide_inlining): Remove FIXMEs.
(inline_generate_summary): Likewise.
(inline_read_summary): New function.
(inline_write_summary): New function.
(pass_ipa_inline): Register new hooks.
* ipa-prop.c: Inlcude lto-streamer.h
(ipa_edge_args_vector): Update declaration.
(ipa_count_arguments, ipa_compute_jump_functions,
ipa_free_edge_args_substructures): Move ipa_edge_args_vector into ggc.
(ipa_write_jump_function, ipa_read_jump_function, ipa_write_node_info,
ipa_read_node_info): New static functions.
(ipa_prop_write_jump_functions, ipa_prop_read_jump_functions): Update.
(duplicate_array): Use xmalloc.
(duplicate_ggc_array): New.
(ipa_edge_duplication_hook): Use it.
(ipa_update_after_lto_read): New function.
* ipa-prop.h (ipa_prop_write_jump_functions,
ipa_prop_read_jump_functions): Declare.
(ipa_pass_through_data, ipa_ancestor_jf_data, ipa_member_ptr_cst,
jump_func_value, ipa_member_ptr_cst, ipa_edge_args): Add GTY markers.
(ipa_edge_args_vector): Move into GGC.
(ipa_check_create_edge_args): Update.
(ipa_update_after_lto_read): New.
* passes.c (ipa_write_summaries_1): When in wpa, do not write summaries.
(ipa_read_summaries): When in ltrans, so not read summaries.
* lto-streamer.c (lto_get_section_name): Add LTO_section_jump_functions.
* lto-streamer.h (LTO_section_jump_functions): New section.
(produce_asm): Declare.
* lto-cgraph.c (output_cgraph): Output edges in reverse order.
* lto-streamer-out.c (produce_asm): Export.
* lto-streamer-in.c: Include tree-pass.h
(input_function): Free dominance info when done.
(lto_read_body): Push ipa_inline in ltrans stage.
* gengtype.c (open_base_files): Add ipa-prop.h into includes.
* Makefile.in (GTFILES): Add ipa-prop.h

* lto.c (lto_fixup_jump_functions): New function.
(lto_fixup_decls): Use it.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@153449 138bc75d-0d04-0410-961f-82ee72b054a4

17 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/cgraphunit.c
gcc/gengtype.c
gcc/ipa-cp.c
gcc/ipa-inline.c
gcc/ipa-prop.c
gcc/ipa-prop.h
gcc/ipa-reference.c
gcc/lto-cgraph.c
gcc/lto-streamer-in.c
gcc/lto-streamer-out.c
gcc/lto-streamer.c
gcc/lto-streamer.h
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/passes.c

index 107ade7..d686d0d 100644 (file)
@@ -1,3 +1,50 @@
+2009-10-22  Jan Hubicka  <jh@suse.cz>
+
+       * ipa-cp.c (ipcp_write_summary, ipcp_read_summary): New functions.
+       (pass_ipa_cp): Register them.
+       (ipcp_init_stage): Analyze all functions for whopr/lto.
+       (ipcp_propagate_stage): Skip external calls.
+       (ipcp_iterate_stage): Call ipa_update_after_lto_read if needed.
+       * ipa-reference.c (write_node_summary_p): Fix thinko about availability.
+       * cgraphunit.c (ipa_passes): When in lto, ne er produce new summaries;
+       when in ltrans, skip executing of ipa passes since everything should've
+       been done.
+       * ipa-inline.c (cgraph_decide_inlining): Remove FIXMEs.
+       (inline_generate_summary): Likewise.
+       (inline_read_summary): New function.
+       (inline_write_summary): New function.
+       (pass_ipa_inline): Register new hooks.
+       * ipa-prop.c: Inlcude lto-streamer.h
+       (ipa_edge_args_vector): Update declaration.
+       (ipa_count_arguments, ipa_compute_jump_functions,
+       ipa_free_edge_args_substructures): Move ipa_edge_args_vector into ggc.
+       (ipa_write_jump_function, ipa_read_jump_function, ipa_write_node_info,
+       ipa_read_node_info): New static functions.
+       (ipa_prop_write_jump_functions, ipa_prop_read_jump_functions): Update.
+       (duplicate_array): Use xmalloc.
+       (duplicate_ggc_array): New.
+       (ipa_edge_duplication_hook): Use it.
+       (ipa_update_after_lto_read): New function.
+       * ipa-prop.h (ipa_prop_write_jump_functions,
+       ipa_prop_read_jump_functions): Declare.
+       (ipa_pass_through_data, ipa_ancestor_jf_data, ipa_member_ptr_cst,
+       jump_func_value, ipa_member_ptr_cst, ipa_edge_args): Add GTY markers.
+       (ipa_edge_args_vector): Move into GGC.
+       (ipa_check_create_edge_args): Update.
+       (ipa_update_after_lto_read): New.
+       * passes.c (ipa_write_summaries_1): When in wpa, do not write summaries.
+       (ipa_read_summaries): When in ltrans, so not read summaries.
+       * lto-streamer.c (lto_get_section_name): Add LTO_section_jump_functions.
+       * lto-streamer.h (LTO_section_jump_functions): New section.
+       (produce_asm): Declare.
+       * lto-cgraph.c (output_cgraph): Output edges in reverse order.
+       * lto-streamer-out.c (produce_asm): Export.
+       * lto-streamer-in.c: Include tree-pass.h
+       (input_function): Free dominance info when done.
+       (lto_read_body): Push ipa_inline in ltrans stage.
+       * gengtype.c (open_base_files): Add ipa-prop.h into includes.
+       * Makefile.in (GTFILES): Add ipa-prop.h
+
 2009-10-22  Matthias Klose  <doko@ubuntu.com>
 
        * doc/install.texi: Document --enable-browser-plugin.
index 3d24ac3..750da6b 100644 (file)
@@ -3585,6 +3585,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/tree-ssa-structalias.c \
   $(srcdir)/lto-symtab.c \
   $(srcdir)/tree-ssa-alias.h \
+  $(srcdir)/ipa-prop.h \
   @all_gtfiles@
 
 # Compute the list of GT header files from the corresponding C sources,
index 47ee7d9..7b8b738 100644 (file)
@@ -1375,15 +1375,16 @@ ipa_passes (void)
       set_cfun (NULL);
       current_function_decl = NULL;
       cgraph_process_new_functions ();
-    }
 
-  execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_regular_ipa_passes);
+      execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_regular_ipa_passes);
+    }
   execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_lto_gen_passes);
 
   if (!in_lto_p)
     ipa_write_summaries ();
 
-  execute_ipa_pass_list (all_regular_ipa_passes);
+  if (!flag_ltrans)
+    execute_ipa_pass_list (all_regular_ipa_passes);
 
   bitmap_obstack_release (NULL);
 }
index 8e882f1..32abf6e 100644 (file)
@@ -1571,7 +1571,7 @@ open_base_files (void)
       "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h",
       "tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h",
       "cfglayout.h", "except.h", "output.h", "gimple.h", "cfgloop.h",
-      "target.h", NULL
+      "target.h", "ipa-prop.h", NULL
     };
     const char *const *ifp;
     outf_p gtype_desc_c;
index 7e499ca..4166e78 100644 (file)
@@ -614,7 +614,9 @@ ipcp_init_stage (void)
       /* building jump functions  */
       for (cs = node->callees; cs; cs = cs->next_callee)
        {
-         if (!cs->callee->analyzed)
+         /* We do not need to bother analyzing calls to unknown
+            functions unless they may become known during lto/whopr.  */
+         if (!cs->callee->analyzed && !flag_lto && !flag_whopr)
            continue;
          ipa_count_arguments (cs);
          if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
@@ -696,7 +698,9 @@ ipcp_propagate_stage (void)
          struct ipa_node_params *callee_info = IPA_NODE_REF (cs->callee);
          struct ipa_edge_args *args = IPA_EDGE_REF (cs);
 
-         if (ipa_is_called_with_var_arguments (callee_info))
+         if (ipa_is_called_with_var_arguments (callee_info)
+             || !cs->callee->analyzed
+             || ipa_is_called_with_var_arguments (callee_info))
            continue;
 
          count = ipa_get_cs_argument_count (args);
@@ -727,6 +731,10 @@ ipcp_iterate_stage (void)
 
   if (dump_file)
     fprintf (dump_file, "\nIPA iterate stage:\n\n");
+
+  if (in_lto_p)
+    ipa_update_after_lto_read ();
+
   for (node = cgraph_nodes; node; node = node->next)
     {
       ipcp_initialize_node_lattices (node);
@@ -1276,6 +1284,20 @@ ipcp_generate_summary (void)
   ipcp_init_stage ();
 }
 
+/* Write ipcp summary for nodes in SET.  */
+static void
+ipcp_write_summary (cgraph_node_set set)
+{
+  ipa_prop_write_jump_functions (set);
+}
+
+/* Read ipcp summary.  */
+static void
+ipcp_read_summary (void)
+{
+  ipa_prop_read_jump_functions ();
+}
+
 /* Gate for IPCP optimization.  */
 static bool
 cgraph_gate_cp (void)
@@ -1308,8 +1330,8 @@ struct ipa_opt_pass_d pass_ipa_cp =
   TODO_remove_functions /* todo_flags_finish */
  },
  ipcp_generate_summary,                        /* generate_summary */
NULL,                                 /* write_summary */
NULL,                                 /* read_summary */
ipcp_write_summary,                   /* write_summary */
ipcp_read_summary,                    /* read_summary */
  NULL,                                 /* function_read_summary */
  0,                                    /* TODOs */
  NULL,                                 /* function_transform */
index 18e440a..9e1bc9f 100644 (file)
@@ -1113,13 +1113,9 @@ cgraph_decide_inlining (void)
   bool redo_always_inline = true;
   int initial_size = 0;
 
-  /* FIXME lto.  We need to rethink how to coordinate different passes. */
-  if (flag_ltrans)
-    return 0;
-
-  /* FIXME lto.  We need to re-think about how the passes get invoked. */
-  if (!flag_wpa)
-    cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
+  cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
+  if (in_lto_p && flag_indirect_inlining)
+    ipa_update_after_lto_read ();
 
   max_count = 0;
   max_benefit = 0;
@@ -1928,10 +1924,6 @@ inline_generate_summary (void)
 {
   struct cgraph_node *node;
 
-  /* FIXME lto.  We should not run any IPA-summary pass in LTRANS mode.  */
-  if (flag_ltrans)
-    return;
-
   function_insertion_hook_holder =
       cgraph_add_function_insertion_hook (&add_new_function, NULL);
 
@@ -1976,6 +1968,34 @@ inline_transform (struct cgraph_node *node)
   return todo | execute_fixup_cfg ();
 }
 
+/* Read inline summary.  Jump functions are shared among ipa-cp
+   and inliner, so when ipa-cp is active, we don't need to write them
+   twice.  */
+
+static void 
+inline_read_summary (void)
+{
+  if (flag_indirect_inlining)
+    {
+      ipa_register_cgraph_hooks ();
+      if (!flag_ipa_cp)
+        ipa_prop_read_jump_functions ();
+    }
+  function_insertion_hook_holder =
+      cgraph_add_function_insertion_hook (&add_new_function, NULL);
+}
+
+/* Write inline summary for node in SET.
+   Jump functions are shared among ipa-cp and inliner, so when ipa-cp is
+   active, we don't need to write them twice.  */
+
+static void 
+inline_write_summary (cgraph_node_set set)
+{
+  if (flag_indirect_inlining && !flag_ipa_cp)
+    ipa_prop_write_jump_functions (set);
+}
+
 struct ipa_opt_pass_d pass_ipa_inline =
 {
  {
@@ -1995,8 +2015,8 @@ struct ipa_opt_pass_d pass_ipa_inline =
   | TODO_remove_functions              /* todo_flags_finish */
  },
  inline_generate_summary,              /* generate_summary */
NULL,                                 /* write_summary */
NULL,                                 /* read_summary */
inline_write_summary,                 /* write_summary */
inline_read_summary,                  /* read_summary */
  NULL,                                 /* function_read_summary */
  0,                                    /* TODOs */
  inline_transform,                     /* function_transform */
index 93c407b..9956fbc 100644 (file)
@@ -33,11 +33,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "flags.h"
 #include "diagnostic.h"
+#include "lto-streamer.h"
 
 /* Vector where the parameter infos are actually stored. */
 VEC (ipa_node_params_t, heap) *ipa_node_params_vector;
 /* Vector where the parameter infos are actually stored. */
-VEC (ipa_edge_args_t, heap) *ipa_edge_args_vector;
+VEC (ipa_edge_args_t, gc) *ipa_edge_args_vector;
 
 /* Holders of ipa cgraph hooks: */
 static struct cgraph_edge_hook_list *edge_removal_hook_holder;
@@ -248,7 +249,7 @@ ipa_count_arguments (struct cgraph_edge *cs)
   arg_num = gimple_call_num_args (stmt);
   if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector)
       <= (unsigned) cgraph_edge_max_uid)
-    VEC_safe_grow_cleared (ipa_edge_args_t, heap,
+    VEC_safe_grow_cleared (ipa_edge_args_t, gc,
                           ipa_edge_args_vector, cgraph_edge_max_uid + 1);
   ipa_set_cs_argument_count (IPA_EDGE_REF (cs), arg_num);
 }
@@ -661,8 +662,8 @@ ipa_compute_jump_functions (struct cgraph_edge *cs)
 
   if (ipa_get_cs_argument_count (arguments) == 0 || arguments->jump_functions)
     return;
-  arguments->jump_functions = XCNEWVEC (struct ipa_jump_func,
-                                       ipa_get_cs_argument_count (arguments));
+  arguments->jump_functions = GGC_CNEWVEC (struct ipa_jump_func,
+                                          ipa_get_cs_argument_count (arguments));
 
   call = cs->call_stmt;
   gcc_assert (is_gimple_call (call));
@@ -1173,7 +1174,7 @@ void
 ipa_free_edge_args_substructures (struct ipa_edge_args *args)
 {
   if (args->jump_functions)
-    free (args->jump_functions);
+    ggc_free (args->jump_functions);
 
   memset (args, 0, sizeof (*args));
 }
@@ -1191,7 +1192,7 @@ ipa_free_all_edge_args (void)
        i++)
     ipa_free_edge_args_substructures (args);
 
-  VEC_free (ipa_edge_args_t, heap, ipa_edge_args_vector);
+  VEC_free (ipa_edge_args_t, gc, ipa_edge_args_vector);
   ipa_edge_args_vector = NULL;
 }
 
@@ -1262,7 +1263,22 @@ duplicate_array (void *src, size_t n)
   if (!src)
     return NULL;
 
-  p = xcalloc (1, n);
+  p = xmalloc (n);
+  memcpy (p, src, n);
+  return p;
+}
+
+/* Like duplicate_array byt in GGC memory.  */
+
+static void *
+duplicate_ggc_array (void *src, size_t n)
+{
+  void *p;
+
+  if (!src)
+    return NULL;
+
+  p = ggc_alloc (n);
   memcpy (p, src, n);
   return p;
 }
@@ -1284,8 +1300,8 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
   arg_count = ipa_get_cs_argument_count (old_args);
   ipa_set_cs_argument_count (new_args, arg_count);
   new_args->jump_functions = (struct ipa_jump_func *)
-    duplicate_array (old_args->jump_functions,
-                    sizeof (struct ipa_jump_func) * arg_count);
+    duplicate_ggc_array (old_args->jump_functions,
+                        sizeof (struct ipa_jump_func) * arg_count);
 }
 
 /* Hook that is called by cgraph.c when a node is duplicated.  */
@@ -1875,3 +1891,283 @@ ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments,
   VEC_free (tree, heap, parms);
 }
 
+/* Stream out jump function JUMP_FUNC to OB.  */
+
+static void
+ipa_write_jump_function (struct output_block *ob,
+                        struct ipa_jump_func *jump_func)
+{
+  lto_output_uleb128_stream (ob->main_stream,
+                            jump_func->type);
+
+  switch (jump_func->type)
+    {
+    case IPA_JF_UNKNOWN:
+      break;
+    case IPA_JF_CONST:
+      lto_output_tree (ob, jump_func->value.constant, true);
+      break;
+    case IPA_JF_PASS_THROUGH:
+      lto_output_tree (ob, jump_func->value.pass_through.operand, true);
+      lto_output_uleb128_stream (ob->main_stream,
+                                jump_func->value.pass_through.formal_id);
+      lto_output_uleb128_stream (ob->main_stream,
+                                jump_func->value.pass_through.operation);
+      break;
+    case IPA_JF_ANCESTOR:
+      lto_output_uleb128_stream (ob->main_stream,
+                                jump_func->value.ancestor.offset);
+      lto_output_tree (ob, jump_func->value.ancestor.type, true);
+      lto_output_uleb128_stream (ob->main_stream,
+                                jump_func->value.ancestor.formal_id);
+      break;
+    case IPA_JF_CONST_MEMBER_PTR:
+      lto_output_tree (ob, jump_func->value.member_cst.pfn, true);
+      lto_output_tree (ob, jump_func->value.member_cst.delta, false);
+      break;
+    }
+}
+
+/* Read in jump function JUMP_FUNC from IB.  */
+
+static void
+ipa_read_jump_function (struct lto_input_block *ib,
+                       struct ipa_jump_func *jump_func,
+                       struct data_in *data_in)
+{
+  jump_func->type = (enum jump_func_type) lto_input_uleb128 (ib);
+
+  switch (jump_func->type)
+    {
+    case IPA_JF_UNKNOWN:
+      break;
+    case IPA_JF_CONST:
+      jump_func->value.constant = lto_input_tree (ib, data_in);
+      break;
+    case IPA_JF_PASS_THROUGH:
+      jump_func->value.pass_through.operand = lto_input_tree (ib, data_in);
+      jump_func->value.pass_through.formal_id = lto_input_uleb128 (ib);
+      jump_func->value.pass_through.operation = (enum tree_code) lto_input_uleb128 (ib);
+      break;
+    case IPA_JF_ANCESTOR:
+      jump_func->value.ancestor.offset = lto_input_uleb128 (ib);
+      jump_func->value.ancestor.type = lto_input_tree (ib, data_in);
+      jump_func->value.ancestor.formal_id = lto_input_uleb128 (ib);
+      break;
+    case IPA_JF_CONST_MEMBER_PTR:
+      jump_func->value.member_cst.pfn = lto_input_tree (ib, data_in);
+      jump_func->value.member_cst.delta = lto_input_tree (ib, data_in);
+      break;
+    }
+}
+
+/* Stream out NODE info to OB.  */
+
+static void
+ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
+{
+  int node_ref;
+  lto_cgraph_encoder_t encoder;
+  struct ipa_node_params *info = IPA_NODE_REF (node);
+  int j;
+  struct cgraph_edge *e;
+  struct bitpack_d *bp;
+
+  encoder = ob->decl_state->cgraph_node_encoder;
+  node_ref = lto_cgraph_encoder_encode (encoder, node);
+  lto_output_uleb128_stream (ob->main_stream, node_ref);
+
+  /* Note that flags will need to be read in the opposite
+     order as we are pushing the bitflags into FLAGS.  */
+  bp = bitpack_create ();
+  bp_pack_value (bp, info->called_with_var_arguments, 1);
+  gcc_assert (info->modification_analysis_done || ipa_get_param_count (info) == 0);
+  gcc_assert (info->uses_analysis_done || ipa_get_param_count (info) == 0);
+  gcc_assert (!info->node_enqueued);
+  gcc_assert (!info->ipcp_orig_node);
+  for (j = 0; j < ipa_get_param_count (info); j++)
+    {
+      bp_pack_value (bp, info->params[j].modified, 1);
+      bp_pack_value (bp, info->params[j].called, 1);
+    }
+  lto_output_bitpack (ob->main_stream, bp);
+  bitpack_delete (bp);
+  for (e = node->callees; e; e = e->next_callee)
+    {
+      struct ipa_edge_args *args = IPA_EDGE_REF (e);
+
+      lto_output_uleb128_stream (ob->main_stream, ipa_get_cs_argument_count (args));
+      for (j = 0; j < ipa_get_cs_argument_count (args); j++)
+       ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j));
+    }
+}
+
+/* Srtream in NODE info from IB.  */
+
+static void
+ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
+                   struct data_in *data_in)
+{
+  struct ipa_node_params *info = IPA_NODE_REF (node);
+  int k;
+  struct cgraph_edge *e;
+  struct bitpack_d *bp;
+
+  ipa_initialize_node_params (node);
+
+  /* Note that the flags must be read in the opposite
+     order in which they were written (the bitflags were
+     pushed into FLAGS).  */
+  bp = lto_input_bitpack (ib);
+  info->called_with_var_arguments = bp_unpack_value (bp, 1);
+  if (ipa_get_param_count (info) != 0)
+    {
+      info->modification_analysis_done = true;
+      info->uses_analysis_done = true;
+    }
+  info->node_enqueued = false;
+  for (k = 0; k < ipa_get_param_count (info); k++)
+    {
+      info->params[k].modified = bp_unpack_value (bp, 1);
+      info->params[k].called = bp_unpack_value (bp, 1);
+    }
+  bitpack_delete (bp);
+  for (e = node->callees; e; e = e->next_callee)
+    {
+      struct ipa_edge_args *args = IPA_EDGE_REF (e);
+      int count = lto_input_uleb128 (ib);
+
+      if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector)
+         <= (unsigned) cgraph_edge_max_uid)
+       VEC_safe_grow_cleared (ipa_edge_args_t, gc,
+                              ipa_edge_args_vector, cgraph_edge_max_uid + 1);
+      ipa_set_cs_argument_count (args, count);
+      if (!count)
+       continue;
+
+      args->jump_functions = GGC_CNEWVEC (struct ipa_jump_func,
+                                         ipa_get_cs_argument_count (args));
+      for (k = 0; k < ipa_get_cs_argument_count (args); k++)
+       ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), data_in);
+    }
+}
+
+/* Write jump functions for nodes in SET.  */
+
+void
+ipa_prop_write_jump_functions (cgraph_node_set set)
+{
+  struct cgraph_node *node;
+  struct output_block *ob = create_output_block (LTO_section_jump_functions);
+  unsigned int count = 0;
+  cgraph_node_set_iterator csi;
+
+  ob->cgraph_node = NULL;
+
+  for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
+    {
+      node = csi_node (csi);
+      if (node->analyzed && IPA_NODE_REF (node) != NULL)
+       count++;
+    }
+
+  lto_output_uleb128_stream (ob->main_stream, count);
+
+  /* Process all of the functions.  */
+  for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
+    {
+      node = csi_node (csi);
+      if (node->analyzed && IPA_NODE_REF (node) != NULL)
+        ipa_write_node_info (ob, node);
+    }
+  lto_output_1_stream (ob->main_stream, 0);
+  produce_asm (ob, NULL);
+  destroy_output_block (ob);
+}
+
+/* Read section in file FILE_DATA of length LEN with data DATA.  */
+
+static void
+ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data,
+                      size_t len)
+{
+  const struct lto_function_header *header =
+    (const struct lto_function_header *) data;
+  const int32_t cfg_offset = sizeof (struct lto_function_header);
+  const int32_t main_offset = cfg_offset + header->cfg_size;
+  const int32_t string_offset = main_offset + header->main_size;
+  struct data_in *data_in;
+  struct lto_input_block ib_main;
+  unsigned int i;
+  unsigned int count;
+
+  LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
+                       header->main_size);
+
+  data_in =
+    lto_data_in_create (file_data, (const char *) data + string_offset,
+                       header->string_size, NULL);
+  count = lto_input_uleb128 (&ib_main);
+
+  for (i = 0; i < count; i++)
+    {
+      unsigned int index;
+      struct cgraph_node *node;
+      lto_cgraph_encoder_t encoder;
+
+      index = lto_input_uleb128 (&ib_main);
+      encoder = file_data->cgraph_node_encoder;
+      node = lto_cgraph_encoder_deref (encoder, index);
+      ipa_read_node_info (&ib_main, node, data_in);
+    }
+  lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data,
+                        len);
+  lto_data_in_delete (data_in);
+}
+
+/* Read ipcp jump functions.  */
+
+void
+ipa_prop_read_jump_functions (void)
+{
+  struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
+  struct lto_file_decl_data *file_data;
+  unsigned int j = 0;
+
+  ipa_check_create_node_params ();
+  ipa_check_create_edge_args ();
+  ipa_register_cgraph_hooks ();
+
+  while ((file_data = file_data_vec[j++]))
+    {
+      size_t len;
+      const char *data = lto_get_section_data (file_data, LTO_section_jump_functions, NULL, &len);
+
+      if (data)
+        ipa_prop_read_section (file_data, data, len);
+    }
+}
+
+/* After merging units, we can get mismatch in argument counts. 
+   Also decl merging might've rendered parameter lists obsolette.
+   Also compute called_with_variable_arg info.  */
+
+void
+ipa_update_after_lto_read (void)
+{
+  struct cgraph_node *node;
+  struct cgraph_edge *cs;
+
+  for (node = cgraph_nodes; node; node = node->next)
+    {
+      if (!node->analyzed)
+       continue;
+      ipa_populate_param_decls (node, IPA_NODE_REF (node));
+      for (cs = node->callees; cs; cs = cs->next_callee)
+       {
+         if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
+             != ipa_get_param_count (IPA_NODE_REF (cs->callee)))
+           ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
+       }
+    }
+}
index 9b5f74f..3500595 100644 (file)
@@ -72,7 +72,7 @@ enum ipa_lattice_type
 
 /* Structure holding data required to describe a pass-through jump function.  */
 
-struct ipa_pass_through_data
+struct GTY(()) ipa_pass_through_data
 {
   /* If an operation is to be performed on the original parameter, this is the
      second (constant) operand.  */
@@ -89,7 +89,7 @@ struct ipa_pass_through_data
 /* Structure holding data required to describe and ancestor pass throu
    funkci.  */
 
-struct ipa_ancestor_jf_data
+struct GTY(()) ipa_ancestor_jf_data
 {
   /* Offset of the field representing the ancestor.  */
   HOST_WIDE_INT offset;
@@ -101,30 +101,28 @@ struct ipa_ancestor_jf_data
 
 /* Structure holding a C++ member pointer constant.  Holds a pointer to the
    method and delta offset.  */
-struct ipa_member_ptr_cst
+struct GTY(()) ipa_member_ptr_cst
 {
   tree pfn;
   tree delta;
 };
 
-/* Represents a value of a jump function.  pass_through is used only in jump
-   function context.  constant represents the actual constant in constant jump
-   functions and member_cst holds constant c++ member functions.  */
-union jump_func_value
-{
-  tree constant;
-  struct ipa_pass_through_data pass_through;
-  struct ipa_ancestor_jf_data ancestor;
-  struct ipa_member_ptr_cst member_cst;
-};
-
 /* A jump function for a callsite represents the values passed as actual
    arguments of the callsite. See enum jump_func_type for the various
    types of jump functions supported.  */
-struct ipa_jump_func
+struct GTY (()) ipa_jump_func
 {
   enum jump_func_type type;
-  union jump_func_value value;
+  /* Represents a value of a jump function.  pass_through is used only in jump
+     function context.  constant represents the actual constant in constant jump
+     functions and member_cst holds constant c++ member functions.  */
+  union jump_func_value
+  {
+    tree GTY ((tag ("IPA_JF_CONST"))) constant;
+    struct ipa_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) pass_through;
+    struct ipa_ancestor_jf_data GTY ((tag ("IPA_JF_ANCESTOR"))) ancestor;
+    struct ipa_member_ptr_cst GTY ((tag ("IPA_JF_CONST_MEMBER_PTR"))) member_cst;
+  } GTY ((desc ("%1.type"))) value;
 };
 
 /* All formal parameters in the program have a cval computed by
@@ -280,15 +278,15 @@ ipa_is_called_with_var_arguments (struct ipa_node_params *info)
 /* ipa_edge_args stores information related to a callsite and particularly
    its arguments. It is pointed to by a field in the
    callsite's corresponding cgraph_edge.  */
-struct ipa_edge_args
+typedef struct GTY(()) ipa_edge_args
 {
   /* Number of actual arguments in this callsite.  When set to 0,
      this callsite's parameters would not be analyzed by the different
      stages of IPA CP.  */
   int argument_count;
   /* Array of the callsite's jump function of each parameter.  */
-  struct ipa_jump_func *jump_functions;
-};
+  struct ipa_jump_func GTY ((length ("%h.argument_count"))) *jump_functions;
+} ipa_edge_args_t;
 
 /* ipa_edge_args access functions.  Please use these to access fields that
    are or will be shared among various passes.  */
@@ -321,18 +319,17 @@ ipa_get_ith_jump_func (struct ipa_edge_args *args, int i)
 
 /* Vectors need to have typedefs of structures.  */
 typedef struct ipa_node_params ipa_node_params_t;
-typedef struct ipa_edge_args ipa_edge_args_t;
 
 /* Types of vectors holding the infos.  */
 DEF_VEC_O (ipa_node_params_t);
 DEF_VEC_ALLOC_O (ipa_node_params_t, heap);
 DEF_VEC_O (ipa_edge_args_t);
-DEF_VEC_ALLOC_O (ipa_edge_args_t, heap);
+DEF_VEC_ALLOC_O (ipa_edge_args_t, gc);
 
 /* Vector where the parameter infos are actually stored. */
 extern VEC (ipa_node_params_t, heap) *ipa_node_params_vector;
 /* Vector where the parameter infos are actually stored. */
-extern VEC (ipa_edge_args_t, heap) *ipa_edge_args_vector;
+extern GTY(()) VEC (ipa_edge_args_t, gc) *ipa_edge_args_vector;
 
 /* Return the associated parameter/argument info corresponding to the given
    node/edge.  */
@@ -378,12 +375,12 @@ static inline void
 ipa_check_create_edge_args (void)
 {
   if (!ipa_edge_args_vector)
-    ipa_edge_args_vector = VEC_alloc (ipa_edge_args_t, heap,
+    ipa_edge_args_vector = VEC_alloc (ipa_edge_args_t, gc,
                                      cgraph_edge_max_uid);
 
   if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector)
       <=  (unsigned) cgraph_edge_max_uid)
-    VEC_safe_grow_cleared (ipa_edge_args_t, heap, ipa_edge_args_vector,
+    VEC_safe_grow_cleared (ipa_edge_args_t, gc, ipa_edge_args_vector,
                           cgraph_edge_max_uid + 1);
 }
 
@@ -508,6 +505,10 @@ ipa_parm_adjustment_vec ipa_combine_adjustments (ipa_parm_adjustment_vec,
                                                 ipa_parm_adjustment_vec);
 void ipa_dump_param_adjustments (FILE *, ipa_parm_adjustment_vec, tree);
 
+void ipa_prop_write_jump_functions (cgraph_node_set set);
+void ipa_prop_read_jump_functions (void);
+void ipa_update_after_lto_read (void);
+
 /* From tree-sra.c:  */
 bool build_ref_for_offset (tree *, tree, HOST_WIDE_INT, tree, bool);
 
index 7956846..2e062e4 100644 (file)
@@ -1014,7 +1014,7 @@ write_node_summary_p (struct cgraph_node *node)
 {
   return (node->analyzed 
          && node->global.inlined_to == NULL
-         && cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE
+         && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE
          && get_reference_vars_info (node) != NULL);
 }
 
index fbf0df2..6b340a3 100644 (file)
@@ -372,8 +372,16 @@ output_cgraph (cgraph_node_set set)
   for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
     {
       node = csi_node (csi);
-      for (edge = node->callees; edge; edge = edge->next_callee)
-       lto_output_edge (ob, edge, encoder);
+      if (node->callees)
+        {
+         /* Output edges in backward direction, so the reconstructed callgraph
+            match and it is easy to associate call sites in the IPA pass summaries.  */
+         edge = node->callees;
+         while (edge->next_callee)
+           edge = edge->next_callee;
+         for (; edge; edge = edge->prev_callee)
+           lto_output_edge (ob, edge, encoder);
+       }
     }
 
   lto_output_uleb128_stream (ob->main_stream, 0);
index 4f7551d..f31b319 100644 (file)
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "ipa-utils.h"
 #include "lto-streamer.h"
+#include "tree-pass.h"
 
 /* Data structure used to hash file names in the source_location field.  */
 struct string_slot
@@ -1341,6 +1342,8 @@ input_function (tree fn_decl, struct data_in *data_in,
   fixup_call_stmt_edges (cgraph_node (fn_decl), stmts);
 
   update_ssa (TODO_update_ssa_only_virtuals); 
+  free_dominance_info (CDI_DOMINATORS);
+  free_dominance_info (CDI_POST_DOMINATORS);
   free (stmts);
 }
 
@@ -1455,6 +1458,15 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
       /* Restore decl state */
       file_data->current_decl_state = file_data->global_decl_state;
 
+      /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization
+         summaries computed and needs to apply changes.  At the moment WHOPR only
+         supports inlining, so we can push it here by hand.  In future we need to stream
+         this field into ltrans compilation.  This will also need to move the field
+        from struct function into cgraph node where it belongs.  */
+      if (flag_ltrans && !cgraph_node (fn_decl)->global.inlined_to)
+        VEC_safe_push (ipa_opt_pass, heap,
+                       cfun->ipa_transforms_to_apply,
+                       (ipa_opt_pass)&pass_ipa_inline);
       pop_cfun ();
     }
   else 
index 737206c..40bba1e 100644 (file)
@@ -1762,7 +1762,7 @@ output_bb (struct output_block *ob, basic_block bb, struct function *fn)
 /* Create the header in the file using OB.  If the section type is for
    a function, set FN to the decl for that function.  */
 
-static void
+void
 produce_asm (struct output_block *ob, tree fn)
 {
   enum lto_section_type section_type = ob->section_type;
index 36172c0..5b925db 100644 (file)
@@ -157,6 +157,9 @@ lto_get_section_name (int section_type, const char *name)
     case LTO_section_cgraph:
       return concat (LTO_SECTION_NAME_PREFIX, ".cgraph", NULL);
 
+    case LTO_section_jump_functions:
+      return concat (LTO_SECTION_NAME_PREFIX, ".jmpfuncs", NULL);
+
     case LTO_section_ipa_pure_const:
       return concat (LTO_SECTION_NAME_PREFIX, ".pureconst", NULL);
 
index 4d90ecb..260d773 100644 (file)
@@ -256,6 +256,7 @@ enum lto_section_type
   LTO_section_function_body,
   LTO_section_static_initializer,
   LTO_section_cgraph,
+  LTO_section_jump_functions,
   LTO_section_ipa_pure_const,
   LTO_section_ipa_reference,
   LTO_section_symtab,
@@ -827,6 +828,7 @@ extern struct output_block *create_output_block (enum lto_section_type);
 extern void destroy_output_block (struct output_block *);
 extern void lto_output_tree (struct output_block *, tree, bool);
 extern void lto_output_bitpack (struct lto_output_stream *, struct bitpack_d *);
+extern void produce_asm (struct output_block *ob, tree fn);
 
 
 /* In lto-cgraph.c  */
index 938d32c..a53a8c0 100644 (file)
@@ -1,3 +1,8 @@
+2009-10-22  Jan Hubicka  <jh@suse.cz>
+
+       * lto.c (lto_fixup_jump_functions): New function.
+       (lto_fixup_decls): Use it.
+
 2009-10-16  Richard Guenther  <rguenther@suse.de>
 
        PR lto/41715
index 2b674c1..a8ad9e3 100644 (file)
@@ -1652,6 +1652,53 @@ free_decl (const void *p, void *data ATTRIBUTE_UNUSED)
   return true;
 }
 
+/* Fixup pointers in jump functions.
+   TODO: We need some generic solution that will allow tree pointers in
+   function summaries.  */
+static void
+lto_fixup_jump_functions (lto_fixup_data_t * data)
+{
+  struct cgraph_node *node;
+  struct cgraph_edge *cs;
+
+  for (node = cgraph_nodes; node; node = node->next)
+    {
+      if (!node->analyzed)
+       continue;
+      for (cs = node->callees; cs; cs = cs->next_callee)
+       {
+         int i;
+         struct ipa_edge_args *args = IPA_EDGE_REF (cs);
+         for (i = 0; i < ipa_get_cs_argument_count (args); i++)
+           {
+             struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i);
+             switch (jf->type)
+               {
+               case IPA_JF_UNKNOWN:
+                 break;
+               case IPA_JF_CONST:
+                 walk_tree (&jf->value.constant, lto_fixup_tree, data, NULL);
+                 break;
+               case IPA_JF_PASS_THROUGH:
+                 walk_tree (&jf->value.pass_through.operand, lto_fixup_tree,
+                            data, NULL);
+                 break;
+               case IPA_JF_ANCESTOR:
+                 walk_tree (&jf->value.ancestor.type, lto_fixup_tree, data,
+                            NULL);
+                 break;
+               case IPA_JF_CONST_MEMBER_PTR:
+                 walk_tree (&jf->value.member_cst.pfn, lto_fixup_tree, data,
+                            NULL);
+                 walk_tree (&jf->value.member_cst.delta, lto_fixup_tree,
+                            data, NULL);
+                 break;
+               }
+           }
+       }
+    }
+}
+
 /* Fix the decls from all FILES. Replaces each decl with the corresponding
    prevailing one.  */
 
@@ -1682,6 +1729,8 @@ lto_fixup_decls (struct lto_file_decl_data **files)
       if (decl != saved_decl)
        VEC_replace (tree, lto_global_var_decls, i, decl);
     }
+  if (ipa_edge_args_vector)
+    lto_fixup_jump_functions (&data);
 
   pointer_set_traverse (free_list, free_decl, NULL);
   pointer_set_destroy (free_list);
index 2d11c1f..db368f0 100644 (file)
@@ -1618,7 +1618,8 @@ 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);
 
-  ipa_write_summaries_2 (all_regular_ipa_passes, set, 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);
@@ -1712,7 +1713,8 @@ ipa_read_summaries_1 (struct opt_pass *pass)
 void
 ipa_read_summaries (void)
 {
-  ipa_read_summaries_1 (all_regular_ipa_passes);
+  if (!flag_ltrans)
+    ipa_read_summaries_1 (all_regular_ipa_passes);
   ipa_read_summaries_1 (all_lto_gen_passes);
 }