aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2009-10-22 10:02:29 +0000
committerJan Hubicka <jh@suse.cz>2009-10-22 10:02:29 +0000
commite2087c1a88ed2fc5cd757ac02f2047a4d0c83c8e (patch)
treedc0c5b1f5b9348db2afad23ab409cf18702d1173
parent82b22c88e810873176113669f2d29fe031d55b29 (diff)
* 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 * lto.c (lto_fixup_jump_functions): New function. (lto_fixup_decls): Use it. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@153449 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog47
-rw-r--r--gcc/Makefile.in1
-rw-r--r--gcc/cgraphunit.c7
-rw-r--r--gcc/gengtype.c2
-rw-r--r--gcc/ipa-cp.c30
-rw-r--r--gcc/ipa-inline.c46
-rw-r--r--gcc/ipa-prop.c314
-rw-r--r--gcc/ipa-prop.h49
-rw-r--r--gcc/ipa-reference.c2
-rw-r--r--gcc/lto-cgraph.c12
-rw-r--r--gcc/lto-streamer-in.c12
-rw-r--r--gcc/lto-streamer-out.c2
-rw-r--r--gcc/lto-streamer.c3
-rw-r--r--gcc/lto-streamer.h2
-rw-r--r--gcc/lto/ChangeLog5
-rw-r--r--gcc/lto/lto.c49
-rw-r--r--gcc/passes.c6
17 files changed, 529 insertions, 60 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 107ade70aef..d686d0db7be 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 3d24ac35ca3..750da6b645c 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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,
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 47ee7d9ebcd..7b8b738ed1f 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -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);
}
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 8e882f171f9..32abf6eff12 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -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;
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 7e499ca27fa..4166e78d61c 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -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 */
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 18e440a60fe..9e1bc9f4883 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -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 */
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 93c407b0826..9956fbc53b7 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -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));
+ }
+ }
+}
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 9b5f74f87ad..35005954deb 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -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);
diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index 795684692bf..2e062e45eaa 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -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);
}
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index fbf0df21c24..6b340a37d58 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -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);
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 4f7551d0d17..f31b3195a7e 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -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
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 737206cb8f6..40bba1e7121 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -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;
diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c
index 36172c03131..5b925db504e 100644
--- a/gcc/lto-streamer.c
+++ b/gcc/lto-streamer.c
@@ -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);
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 4d90ecb0d0c..260d773f300 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -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 */
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index 938d32cb2ef..a53a8c04e79 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -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
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 2b674c176ac..a8ad9e369b9 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -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);
diff --git a/gcc/passes.c b/gcc/passes.c
index 2d11c1f6987..db368f057db 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -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);
}