LTO/WHOPR summary streaming fixes

Jan Hubicka hubicka@ucw.cz
Tue Oct 20 15:01:00 GMT 2009


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?

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,



More information about the Gcc-patches mailing list