LTO/WHOPR summary streaming fixes

Richard Guenther rguenther@suse.de
Tue Oct 20 15:05:00 GMT 2009


On Tue, 20 Oct 2009, Jan Hubicka wrote:

> Hi,
> this patch fixes summary generation issues with LTO and WHOPR.  The main changes are:
> 
>   1) We used to re-compute all summaries at LTO read in.  This is not correct, we should
>      use what we wrote into disk.
>   2) We used to write summaries into ltrans files and re-execute all IPA passes.  This is
>      wrong since all decisions should've been mae at WPA
>   3) Jump functions are not streamed out.
>      Note that I did not include patch to stream in/out indirect call notes.  This is not
>      needed for testsuite so I want to handle this independently.
>   4) ipa-reference was saving summaries only for overwrittable functions.
> 
> Note that whopr is still somewhat broken.  We now apply the inline plan
> changes, but other passes are not run and we now lose some optimization by
> not re-doing all IPA passes at ltrans stage.  I have incremental patches for this,
> I am just trying to avoid snowballing effect.
> 
> I've bootstrapped/regtested earlier vesion of this patch on x86_64-linux and I
> am re-testing current version.  I think I can approve myself all changes except
> for the streaming part.  OK?

It looks good to me.  Let me build a piece of SPEC2006 with the patch,
I'll report on IRC before I leave today.

Thanks,
Richard.

> Honza
> 
> 	* ipa-cp.c (ipcp_write_summary, ipcp_read_summary): New functions.
> 	(pass_ipa_cp): Register them.
> 	* 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_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.
> 	* ipa-prop.h (ipa_prop_write_jump_functions,
> 	ipa_prop_read_jump_functions): Declare.
> 	* 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.
> Index: ipa-cp.c
> ===================================================================
> *** ipa-cp.c	(revision 152974)
> --- ipa-cp.c	(working copy)
> *************** ipcp_generate_summary (void)
> *** 1276,1281 ****
> --- 1276,1295 ----
>     ipcp_init_stage ();
>   }
>   
> + /* Write ipcp summary.  */
> + 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 */
> --- 1322,1329 ----
>     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: 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,1119 ----
>     bool redo_always_inline = true;
>     int initial_size = 0;
>   
> !   cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
>   
>     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);
>   
> --- 1922,1927 ----
> *************** inline_transform (struct cgraph_node *no
> *** 1976,1981 ****
> --- 1966,1999 ----
>     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.  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 */
> --- 2013,2020 ----
>     | 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: ipa-prop.c
> ===================================================================
> *** ipa-prop.c	(revision 152974)
> --- ipa-prop.c	(working copy)
> *************** along with GCC; see the file COPYING3.  
> *** 33,38 ****
> --- 33,39 ----
>   #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;
> *************** ipa_dump_param_adjustments (FILE *file, 
> *** 1875,1877 ****
> --- 1876,2102 ----
>     VEC_free (tree, heap, parms);
>   }
>   
> + /* Stream out jump function JUMP_FUNC.  */
> + 
> + static void
> + ipa_write_jump_function (struct output_block *ob,
> + 			 struct ipa_jump_func *jump_func)
> + {
> +   struct bitpack_d *bp;
> + 
> +   bp = bitpack_create ();
> +   bp_pack_value (bp, jump_func->type, 3);
> +   lto_output_bitpack (ob->main_stream, bp);
> +   bitpack_delete (bp);
> + 
> +   switch (jump_func->type)
> +     {
> +     case IPA_JF_UNKNOWN:
> +       break;
> +     case IPA_JF_CONST:
> +       lto_output_tree (ob, jump_func->value.constant, false);
> +       break;
> +     case IPA_JF_PASS_THROUGH:
> +       lto_output_tree (ob, jump_func->value.pass_through.operand, false);
> +       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, false);
> +       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, false);
> +       lto_output_tree (ob, jump_func->value.member_cst.delta, false);
> +       break;
> +     }
> + }
> + 
> + /* Read in jump function JUMP_FUNC.  */
> + 
> + static void
> + ipa_read_jump_function (struct lto_input_block *ib,
> + 			struct ipa_jump_func *jump_func)
> + {
> +   struct bitpack_d *bp;
> + 
> +   bp = lto_input_bitpack (ib);
> +   jump_func->type = (enum jump_func_type) bp_unpack_value (bp, 3);
> +   bitpack_delete (bp);
> + 
> +   switch (jump_func->type)
> +     {
> +     case IPA_JF_UNKNOWN:
> +       break;
> +     case IPA_JF_CONST:
> +       jump_func->value.constant = lto_input_tree (ib, false);
> +       break;
> +     case IPA_JF_PASS_THROUGH:
> +       jump_func->value.pass_through.operand = lto_input_tree (ib, false);
> +       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, false);
> +       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, false);
> +       jump_func->value.member_cst.delta = lto_input_tree (ib, false);
> +       break;
> +     }
> +   bitpack_delete (bp);
> + }
> + 
> + /* Stream out node info.  */
> + 
> + static void
> + ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
> + {
> +   struct bitpack_d *bp;
> +   int node_ref;
> +   lto_cgraph_encoder_t encoder;
> +   struct ipa_node_params *info = IPA_NODE_REF (node);
> +   int j;
> +   struct cgraph_edge *e;
> + 
> +   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);
> +   gcc_assert (info->uses_analysis_done);
> +   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);
> +       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.  */
> + 
> + static void
> + ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node)
> + {
> +   struct ipa_node_params *info = IPA_NODE_REF (node);
> +   struct bitpack_d *bp;
> +   int k;
> +   struct cgraph_edge *e;
> + 
> +   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);
> +   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);
> +       for (k = 0; k < ipa_get_cs_argument_count (args); k++)
> + 	ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k));
> +     }
> + }
> + 
> + /* Write jump functions.  */
> + 
> + 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;
> + 
> +   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);
> +     }
> +   destroy_output_block (ob);
> + }
> + 
> + /* 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++]))
> +     {
> +       const char *data;
> +       size_t len;
> +       struct lto_input_block *ib
> + 	= lto_create_simple_input_block (file_data, 
> + 					 LTO_section_ipa_pure_const, 
> + 					 &data, &len);
> +       if (ib)
> + 	{
> + 	  unsigned int i;
> + 	  unsigned int count = lto_input_uleb128 (ib);
> + 
> + 	  for (i = 0; i < count; i++)
> + 	    {
> + 	      unsigned int index;
> + 	      struct cgraph_node *node;
> + 	      lto_cgraph_encoder_t encoder;
> + 
> + 	      index = lto_input_uleb128 (ib);
> + 	      encoder = file_data->cgraph_node_encoder;
> + 	      node = lto_cgraph_encoder_deref (encoder, index);
> + 	      ipa_read_node_info (ib, node);
> + 	    }
> + 
> + 	  lto_destroy_simple_input_block (file_data, 
> + 					  LTO_section_ipa_pure_const, 
> + 					  ib, data, len);
> + 	}
> +     }
> + }
> Index: ipa-prop.h
> ===================================================================
> *** ipa-prop.h	(revision 152974)
> --- ipa-prop.h	(working copy)
> *************** ipa_parm_adjustment_vec ipa_combine_adju
> *** 508,513 ****
> --- 508,516 ----
>   						 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);
> + 
>   /* From tree-sra.c:  */
>   bool build_ref_for_offset (tree *, tree, HOST_WIDE_INT, tree, bool);
>   
> 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,
> 
> 

-- 
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex



More information about the Gcc-patches mailing list