This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: LTO/WHOPR summary streaming fixes
On Thu, 22 Oct 2009, Jan Hubicka wrote:
> Hi,
> this should be final version of patch. Tested on x86_64-linux and also
> Richard kindly tested it works with Spec2006.
> The patch fixes ICE in ipa-cp seen on libquantum. OK?
Ok. I'll think about the fixup problem. I think we can easily delay
cgraph node merging until after fixup, then read in the summaries and
then apply the node merging.
Thanks,
Richard.
> Honza
>
>
> * 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.
> Index: gengtype.c
> ===================================================================
> *** gengtype.c (revision 152974)
> --- gengtype.c (working copy)
> *************** open_base_files (void)
> *** 1571,1577 ****
> "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
> };
> const char *const *ifp;
> outf_p gtype_desc_c;
> --- 1571,1577 ----
> "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", "ipa-prop.h", NULL
> };
> const char *const *ifp;
> outf_p gtype_desc_c;
> Index: ipa-cp.c
> ===================================================================
> *** ipa-cp.c (revision 152974)
> --- ipa-cp.c (working copy)
> *************** ipcp_init_stage (void)
> *** 614,620 ****
> /* building jump functions */
> for (cs = node->callees; cs; cs = cs->next_callee)
> {
> ! if (!cs->callee->analyzed)
> continue;
> ipa_count_arguments (cs);
> if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
> --- 614,622 ----
> /* building jump functions */
> for (cs = node->callees; cs; cs = cs->next_callee)
> {
> ! /* 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))
> *************** ipcp_propagate_stage (void)
> *** 696,702 ****
> 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))
> continue;
>
> count = ipa_get_cs_argument_count (args);
> --- 698,706 ----
> 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)
> ! || !cs->callee->analyzed
> ! || ipa_is_called_with_var_arguments (callee_info))
> continue;
>
> count = ipa_get_cs_argument_count (args);
> *************** ipcp_iterate_stage (void)
> *** 727,732 ****
> --- 731,740 ----
>
> 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);
> *************** ipcp_generate_summary (void)
> *** 1276,1281 ****
> --- 1284,1303 ----
> 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)
> *************** struct ipa_opt_pass_d pass_ipa_cp =
> *** 1308,1315 ****
> TODO_remove_functions /* todo_flags_finish */
> },
> ipcp_generate_summary, /* generate_summary */
> ! NULL, /* write_summary */
> ! NULL, /* read_summary */
> NULL, /* function_read_summary */
> 0, /* TODOs */
> NULL, /* function_transform */
> --- 1330,1337 ----
> TODO_remove_functions /* todo_flags_finish */
> },
> ipcp_generate_summary, /* generate_summary */
> ! ipcp_write_summary, /* write_summary */
> ! ipcp_read_summary, /* read_summary */
> NULL, /* function_read_summary */
> 0, /* TODOs */
> NULL, /* function_transform */
> Index: ipa-reference.c
> ===================================================================
> *** ipa-reference.c (revision 152974)
> --- ipa-reference.c (working copy)
> *************** write_node_summary_p (struct cgraph_node
> *** 1014,1020 ****
> {
> return (node->analyzed
> && node->global.inlined_to == NULL
> ! && cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE
> && get_reference_vars_info (node) != NULL);
> }
>
> --- 1014,1020 ----
> {
> return (node->analyzed
> && node->global.inlined_to == NULL
> ! && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE
> && get_reference_vars_info (node) != NULL);
> }
>
> Index: cgraphunit.c
> ===================================================================
> *** cgraphunit.c (revision 152974)
> --- cgraphunit.c (working copy)
> *************** ipa_passes (void)
> *** 1375,1389 ****
> 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_lto_gen_passes);
>
> if (!in_lto_p)
> ipa_write_summaries ();
>
> ! execute_ipa_pass_list (all_regular_ipa_passes);
>
> bitmap_obstack_release (NULL);
> }
> --- 1375,1390 ----
> 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_lto_gen_passes);
>
> if (!in_lto_p)
> ipa_write_summaries ();
>
> ! if (!flag_ltrans)
> ! execute_ipa_pass_list (all_regular_ipa_passes);
>
> bitmap_obstack_release (NULL);
> }
> Index: lto-cgraph.c
> ===================================================================
> *** lto-cgraph.c (revision 152974)
> --- lto-cgraph.c (working copy)
> *************** output_cgraph (cgraph_node_set set)
> *** 372,379 ****
> 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);
> }
>
> lto_output_uleb128_stream (ob->main_stream, 0);
> --- 372,387 ----
> for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
> {
> node = csi_node (csi);
> ! 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: lto-streamer-out.c
> ===================================================================
> *** lto-streamer-out.c (revision 152974)
> --- lto-streamer-out.c (working copy)
> *************** output_bb (struct output_block *ob, basi
> *** 1762,1768 ****
> /* 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
> produce_asm (struct output_block *ob, tree fn)
> {
> enum lto_section_type section_type = ob->section_type;
> --- 1762,1768 ----
> /* Create the header in the file using OB. If the section type is for
> a function, set FN to the decl for that function. */
>
> ! void
> produce_asm (struct output_block *ob, tree fn)
> {
> enum lto_section_type section_type = ob->section_type;
> Index: ipa-inline.c
> ===================================================================
> *** ipa-inline.c (revision 152974)
> --- ipa-inline.c (working copy)
> *************** cgraph_decide_inlining (void)
> *** 1113,1125 ****
> 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);
>
> max_count = 0;
> max_benefit = 0;
> --- 1113,1121 ----
> bool redo_always_inline = true;
> int initial_size = 0;
>
> ! 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;
> *************** inline_generate_summary (void)
> *** 1928,1937 ****
> {
> 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);
>
> --- 1924,1929 ----
> *************** inline_transform (struct cgraph_node *no
> *** 1976,1981 ****
> --- 1968,2001 ----
> 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 =
> {
> {
> *************** struct ipa_opt_pass_d pass_ipa_inline =
> *** 1995,2002 ****
> | TODO_remove_functions /* todo_flags_finish */
> },
> inline_generate_summary, /* generate_summary */
> ! NULL, /* write_summary */
> ! NULL, /* read_summary */
> NULL, /* function_read_summary */
> 0, /* TODOs */
> inline_transform, /* function_transform */
> --- 2015,2022 ----
> | TODO_remove_functions /* todo_flags_finish */
> },
> inline_generate_summary, /* generate_summary */
> ! inline_write_summary, /* write_summary */
> ! inline_read_summary, /* read_summary */
> NULL, /* function_read_summary */
> 0, /* TODOs */
> inline_transform, /* function_transform */
> Index: lto-streamer-in.c
> ===================================================================
> *** lto-streamer-in.c (revision 152974)
> --- lto-streamer-in.c (working copy)
> *************** along with GCC; see the file COPYING3.
> *** 47,52 ****
> --- 47,53 ----
> #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
> *************** input_function (tree fn_decl, struct dat
> *** 1341,1346 ****
> --- 1342,1349 ----
> 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);
> }
>
> *************** lto_read_body (struct lto_file_decl_data
> *** 1455,1460 ****
> --- 1458,1472 ----
> /* 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: lto/lto.c
> ===================================================================
> *** lto/lto.c (revision 152974)
> --- lto/lto.c (working copy)
> *************** free_decl (const void *p, void *data ATT
> *** 1652,1657 ****
> --- 1652,1704 ----
> 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. */
>
> *************** lto_fixup_decls (struct lto_file_decl_da
> *** 1682,1687 ****
> --- 1729,1736 ----
> 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: ipa-prop.c
> ===================================================================
> *** ipa-prop.c (revision 152974)
> --- ipa-prop.c (working copy)
> *************** along with GCC; see the file COPYING3.
> *** 33,43 ****
> #include "timevar.h"
> #include "flags.h"
> #include "diagnostic.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;
>
> /* Holders of ipa cgraph hooks: */
> static struct cgraph_edge_hook_list *edge_removal_hook_holder;
> --- 33,44 ----
> #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, gc) *ipa_edge_args_vector;
>
> /* Holders of ipa cgraph hooks: */
> static struct cgraph_edge_hook_list *edge_removal_hook_holder;
> *************** ipa_count_arguments (struct cgraph_edge
> *** 248,254 ****
> 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,
> ipa_edge_args_vector, cgraph_edge_max_uid + 1);
> ipa_set_cs_argument_count (IPA_EDGE_REF (cs), arg_num);
> }
> --- 249,255 ----
> 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, gc,
> ipa_edge_args_vector, cgraph_edge_max_uid + 1);
> ipa_set_cs_argument_count (IPA_EDGE_REF (cs), arg_num);
> }
> *************** ipa_compute_jump_functions (struct cgrap
> *** 661,668 ****
>
> 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));
>
> call = cs->call_stmt;
> gcc_assert (is_gimple_call (call));
> --- 662,669 ----
>
> if (ipa_get_cs_argument_count (arguments) == 0 || arguments->jump_functions)
> return;
> ! 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));
> *************** void
> *** 1173,1179 ****
> ipa_free_edge_args_substructures (struct ipa_edge_args *args)
> {
> if (args->jump_functions)
> ! free (args->jump_functions);
>
> memset (args, 0, sizeof (*args));
> }
> --- 1174,1180 ----
> ipa_free_edge_args_substructures (struct ipa_edge_args *args)
> {
> if (args->jump_functions)
> ! ggc_free (args->jump_functions);
>
> memset (args, 0, sizeof (*args));
> }
> *************** ipa_free_all_edge_args (void)
> *** 1191,1197 ****
> i++)
> ipa_free_edge_args_substructures (args);
>
> ! VEC_free (ipa_edge_args_t, heap, ipa_edge_args_vector);
> ipa_edge_args_vector = NULL;
> }
>
> --- 1192,1198 ----
> i++)
> ipa_free_edge_args_substructures (args);
>
> ! VEC_free (ipa_edge_args_t, gc, ipa_edge_args_vector);
> ipa_edge_args_vector = NULL;
> }
>
> *************** duplicate_array (void *src, size_t n)
> *** 1262,1268 ****
> if (!src)
> return NULL;
>
> ! p = xcalloc (1, n);
> memcpy (p, src, n);
> return p;
> }
> --- 1263,1284 ----
> if (!src)
> return NULL;
>
> ! 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;
> }
> *************** ipa_edge_duplication_hook (struct cgraph
> *** 1284,1291 ****
> 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);
> }
>
> /* Hook that is called by cgraph.c when a node is duplicated. */
> --- 1300,1307 ----
> 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_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. */
> *************** ipa_dump_param_adjustments (FILE *file,
> *** 1875,1877 ****
> --- 1891,2173 ----
> 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: ipa-prop.h
> ===================================================================
> *** ipa-prop.h (revision 152974)
> --- ipa-prop.h (working copy)
> *************** enum ipa_lattice_type
> *** 72,78 ****
>
> /* Structure holding data required to describe a pass-through jump function. */
>
> ! struct ipa_pass_through_data
> {
> /* If an operation is to be performed on the original parameter, this is the
> second (constant) operand. */
> --- 72,78 ----
>
> /* Structure holding data required to describe a pass-through jump function. */
>
> ! struct GTY(()) ipa_pass_through_data
> {
> /* If an operation is to be performed on the original parameter, this is the
> second (constant) operand. */
> *************** struct ipa_pass_through_data
> *** 89,95 ****
> /* Structure holding data required to describe and ancestor pass throu
> funkci. */
>
> ! struct ipa_ancestor_jf_data
> {
> /* Offset of the field representing the ancestor. */
> HOST_WIDE_INT offset;
> --- 89,95 ----
> /* Structure holding data required to describe and ancestor pass throu
> funkci. */
>
> ! struct GTY(()) ipa_ancestor_jf_data
> {
> /* Offset of the field representing the ancestor. */
> HOST_WIDE_INT offset;
> *************** struct ipa_ancestor_jf_data
> *** 101,130 ****
>
> /* Structure holding a C++ member pointer constant. Holds a pointer to the
> method and delta offset. */
> ! struct 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
> {
> enum jump_func_type type;
> ! union jump_func_value value;
> };
>
> /* All formal parameters in the program have a cval computed by
> --- 101,128 ----
>
> /* Structure holding a C++ member pointer constant. Holds a pointer to the
> method and delta offset. */
> ! struct GTY(()) ipa_member_ptr_cst
> {
> tree pfn;
> tree delta;
> };
>
> /* 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 GTY (()) ipa_jump_func
> {
> enum jump_func_type type;
> ! /* 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
> *************** ipa_is_called_with_var_arguments (struct
> *** 280,294 ****
> /* 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
> {
> /* 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;
> ! };
>
> /* ipa_edge_args access functions. Please use these to access fields that
> are or will be shared among various passes. */
> --- 278,292 ----
> /* 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. */
> ! 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 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. */
> *************** ipa_get_ith_jump_func (struct ipa_edge_a
> *** 321,338 ****
>
> /* 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);
>
> /* 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;
>
> /* Return the associated parameter/argument info corresponding to the given
> node/edge. */
> --- 319,335 ----
>
> /* Vectors need to have typedefs of structures. */
> typedef struct ipa_node_params ipa_node_params_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, 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 GTY(()) VEC (ipa_edge_args_t, gc) *ipa_edge_args_vector;
>
> /* Return the associated parameter/argument info corresponding to the given
> node/edge. */
> *************** static inline void
> *** 378,389 ****
> ipa_check_create_edge_args (void)
> {
> if (!ipa_edge_args_vector)
> ! ipa_edge_args_vector = VEC_alloc (ipa_edge_args_t, heap,
> 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,
> cgraph_edge_max_uid + 1);
> }
>
> --- 375,386 ----
> ipa_check_create_edge_args (void)
> {
> if (!ipa_edge_args_vector)
> ! 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, gc, ipa_edge_args_vector,
> cgraph_edge_max_uid + 1);
> }
>
> *************** ipa_parm_adjustment_vec ipa_combine_adju
> *** 508,513 ****
> --- 505,514 ----
> 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: Makefile.in
> ===================================================================
> *** Makefile.in (revision 152974)
> --- Makefile.in (working copy)
> *************** GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
> *** 3585,3590 ****
> --- 3585,3591 ----
> $(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: passes.c
> ===================================================================
> *** passes.c (revision 152974)
> --- passes.c (working copy)
> *************** ipa_write_summaries_1 (cgraph_node_set s
> *** 1618,1624 ****
> 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);
> ipa_write_summaries_2 (all_lto_gen_passes, set, state);
>
> gcc_assert (lto_get_out_decl_state () == state);
> --- 1618,1625 ----
> struct lto_out_decl_state *state = lto_new_out_decl_state ();
> lto_push_out_decl_state (state);
>
> ! if (!flag_wpa)
> ! ipa_write_summaries_2 (all_regular_ipa_passes, set, state);
> ipa_write_summaries_2 (all_lto_gen_passes, set, state);
>
> gcc_assert (lto_get_out_decl_state () == state);
> *************** ipa_read_summaries_1 (struct opt_pass *p
> *** 1712,1718 ****
> void
> ipa_read_summaries (void)
> {
> ! ipa_read_summaries_1 (all_regular_ipa_passes);
> ipa_read_summaries_1 (all_lto_gen_passes);
> }
>
> --- 1713,1720 ----
> void
> ipa_read_summaries (void)
> {
> ! if (!flag_ltrans)
> ! ipa_read_summaries_1 (all_regular_ipa_passes);
> ipa_read_summaries_1 (all_lto_gen_passes);
> }
>
> Index: lto-streamer.c
> ===================================================================
> *** lto-streamer.c (revision 152974)
> --- lto-streamer.c (working copy)
> *************** lto_get_section_name (int section_type,
> *** 157,162 ****
> --- 157,165 ----
> 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: lto-streamer.h
> ===================================================================
> *** lto-streamer.h (revision 152974)
> --- lto-streamer.h (working copy)
> *************** enum lto_section_type
> *** 256,261 ****
> --- 256,262 ----
> 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,
> *************** extern struct output_block *create_outpu
> *** 827,832 ****
> --- 828,834 ----
> 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 */
>
>
--
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex