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 + + * 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 * 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 + + * lto.c (lto_fixup_jump_functions): New function. + (lto_fixup_decls): Use it. + 2009-10-16 Richard Guenther 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); }