public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* LTO/WHOPR summary streaming fixes
@ 2009-10-20 15:01 Jan Hubicka
  2009-10-20 15:05 ` Richard Guenther
  2009-10-20 15:06 ` Diego Novillo
  0 siblings, 2 replies; 20+ messages in thread
From: Jan Hubicka @ 2009-10-20 15:01 UTC (permalink / raw)
  To: martinj, rguenther, gcc-patches, dnovillo

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,

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 15:01 LTO/WHOPR summary streaming fixes Jan Hubicka
@ 2009-10-20 15:05 ` Richard Guenther
  2009-10-20 15:17   ` Richard Guenther
  2009-10-20 15:06 ` Diego Novillo
  1 sibling, 1 reply; 20+ messages in thread
From: Richard Guenther @ 2009-10-20 15:05 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Martin Jambor, Diego Novillo

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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 15:01 LTO/WHOPR summary streaming fixes Jan Hubicka
  2009-10-20 15:05 ` Richard Guenther
@ 2009-10-20 15:06 ` Diego Novillo
  2009-10-20 15:10   ` Jan Hubicka
  1 sibling, 1 reply; 20+ messages in thread
From: Diego Novillo @ 2009-10-20 15:06 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: martinj, rguenther, gcc-patches

On Tue, Oct 20, 2009 at 10:53, Jan Hubicka <hubicka@ucw.cz> wrote:

> + /* Write ipcp summary.  */
> + static void
> + ipcp_write_summary (cgraph_node_set set)

Document SET.  Blank line after comment.

> + {
> +   ipa_prop_write_jump_functions (set);
> + }
> +
> + /* Read ipcp summary.  */
> + static void

Blank line after comment.

>
> !       execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_regular_ipa_passes);
> !     }

Watch line wrapping.

> + static void
> + inline_write_summary (cgraph_node_set set)

SET needs documenting.

> + /* Stream out jump function JUMP_FUNC.  */
> +

OB needs documenting.

> +
> + /* Read in jump function JUMP_FUNC.  */
> +

IB needs documenting.

> +   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);

Watch line wraping.

> +       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);

You are deleting BP twice.

> + }
> +
> + /* Stream out node info.  */
> +

NODE and OB need documenting.

> +
> +   /* Note that flags will need to be read in the opposite
> +      order as we are pushing the bitflags into FLAGS.  */

This comment does not apply anymore (probably a left over from
old code?).  Bitpacks are packed/unpacked in the same order.

> +
> + /* Srtream in node info.  */

s/Srtream/Stream/
NODE and IB need documenting.

> +
> + /* Write jump functions.  */

SET needs documenting.

> +       struct lto_input_block *ib
> +       = lto_create_simple_input_block (file_data,
> +                                        LTO_section_ipa_pure_const,
> +                                        &data, &len);

I wonder if it makes sense to have simple_input_block anymore.
Do they offer any significant advantage over regular input_block?

Patch looks OK otherwise.


Diego.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 15:06 ` Diego Novillo
@ 2009-10-20 15:10   ` Jan Hubicka
  2009-10-20 15:12     ` Diego Novillo
  0 siblings, 1 reply; 20+ messages in thread
From: Jan Hubicka @ 2009-10-20 15:10 UTC (permalink / raw)
  To: Diego Novillo; +Cc: Jan Hubicka, martinj, rguenther, gcc-patches

> On Tue, Oct 20, 2009 at 10:53, Jan Hubicka <hubicka@ucw.cz> wrote:
> 
> > + /* Write ipcp summary.  */
> > + static void
> > + ipcp_write_summary (cgraph_node_set set)
> 
> Document SET.  Blank line after comment.
> 
> > + {
> > +   ipa_prop_write_jump_functions (set);
> > + }
> > +
> > + /* Read ipcp summary.  */
> > + static void
> 
> Blank line after comment.

Note that whole ipacp file follows the scheme without empty line
after function comment. We probably should reformat it, but since Martin has
number of pending patches here, we probably could wait for next stage1?

Honza

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 15:10   ` Jan Hubicka
@ 2009-10-20 15:12     ` Diego Novillo
  2009-10-20 16:18       ` Martin Jambor
  0 siblings, 1 reply; 20+ messages in thread
From: Diego Novillo @ 2009-10-20 15:12 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: rguenther, gcc-patches, Martin Jambor

2009/10/20 Jan Hubicka <hubicka@ucw.cz>:

> Note that whole ipacp file follows the scheme without empty line
> after function comment. We probably should reformat it, but since Martin has
> number of pending patches here, we probably could wait for next stage1?

No need to wait until the next stage1.  Formatting fixes can be done
in stage3 too.  But, sure, if Martin has other patches, he can roll
them in.


Diego.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 15:05 ` Richard Guenther
@ 2009-10-20 15:17   ` Richard Guenther
  2009-10-20 15:22     ` Richard Guenther
  0 siblings, 1 reply; 20+ messages in thread
From: Richard Guenther @ 2009-10-20 15:17 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Martin Jambor, Diego Novillo

On Tue, 20 Oct 2009, Richard Guenther wrote:

> 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.

Even trivial files now ICE with

alloca.c:202:1: internal compiler error: in ipa_write_node_info, at 
ipa-prop.c:1977

Richard.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 15:17   ` Richard Guenther
@ 2009-10-20 15:22     ` Richard Guenther
  2009-10-20 21:28       ` Jan Hubicka
  0 siblings, 1 reply; 20+ messages in thread
From: Richard Guenther @ 2009-10-20 15:22 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Martin Jambor, Diego Novillo

On Tue, 20 Oct 2009, Richard Guenther wrote:

> On Tue, 20 Oct 2009, Richard Guenther wrote:
> 
> > 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.
> 
> Even trivial files now ICE with
> 
> alloca.c:202:1: internal compiler error: in ipa_write_node_info, at 
> ipa-prop.c:1977

typedef long unsigned int size_t;
static int stack_dir;
static void find_stack_direction () {
    static char *addr = ((void *)0);
    auto char dummy;
    if (addr == ((void *)0))     {
        addr = &(dummy);
        find_stack_direction ();
    }
}
void * C_alloca (size)      size_t size;
{
  if (stack_dir == 0)     find_stack_direction ();
}

> /space/rguenther/install/lto/bin/gcc -c -O2 -flto  alloca.3.i
alloca.3.i:14:1: internal compiler error: in ipa_write_node_info, at 
ipa-prop.c:1977
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 15:12     ` Diego Novillo
@ 2009-10-20 16:18       ` Martin Jambor
  0 siblings, 0 replies; 20+ messages in thread
From: Martin Jambor @ 2009-10-20 16:18 UTC (permalink / raw)
  To: Diego Novillo; +Cc: Jan Hubicka, rguenther, gcc-patches

Hi,

On Tue, Oct 20, 2009 at 11:09:54AM -0400, Diego Novillo wrote:
> 2009/10/20 Jan Hubicka <hubicka@ucw.cz>:
> 
> > Note that whole ipacp file follows the scheme without empty line
> > after function comment. We probably should reformat it, but since Martin has
> > number of pending patches here, we probably could wait for next stage1?
> 
> No need to wait until the next stage1.  Formatting fixes can be done
> in stage3 too.  But, sure, if Martin has other patches, he can roll
> them in.
> 

The only patch that touches ipa-cp.c (as opposed to ipa-prop.[ch]) in
any way worth mentioning is implementation of true cloning (posted in
August as a work-in-progress patch:
http://gcc.gnu.org/ml/gcc-patches/2009-08/msg00290.html).  Even though
it also specifically adds a fair number of blank lines after function
comments, it certainly isn't stage3 material.  Thus, I'll be happy if
formatting patches for this file could be postponed for a while.
OTOH, there will be other changes to the file that will cause me
conflicts too so I will manage if someone does it soon.  Nevertheless,
as I want to rewrite a big portion of the file, at the moment I do not
intend to go through it and reformat what I will propose to remove
anyway.  Last but not least, new code can be formatted well from the
beginning, that is not an issue at all.

Thanks,

Martin

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 15:22     ` Richard Guenther
@ 2009-10-20 21:28       ` Jan Hubicka
  2009-10-21 17:55         ` Jan Hubicka
  0 siblings, 1 reply; 20+ messages in thread
From: Jan Hubicka @ 2009-10-20 21:28 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Jan Hubicka, gcc-patches, Martin Jambor, Diego Novillo

> 
> > /space/rguenther/install/lto/bin/gcc -c -O2 -flto  alloca.3.i
> alloca.3.i:14:1: internal compiler error: in ipa_write_node_info, at 
> ipa-prop.c:1977

I unfortunately managed to test the patch with checking disabled only.  Fixing
the problem uncovers there are more issues, most importantly we need to save
gimple invariants as part of jump functions (const functions).  With simple
block this is not possible and I am not sure I can get full stream block to
save the data easilly.  I am looking into that now.

Honza
> Please submit a full bug report,
> with preprocessed source if appropriate.
> See <http://gcc.gnu.org/bugs.html> for instructions.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-20 21:28       ` Jan Hubicka
@ 2009-10-21 17:55         ` Jan Hubicka
  2009-10-21 19:42           ` Richard Guenther
  0 siblings, 1 reply; 20+ messages in thread
From: Jan Hubicka @ 2009-10-21 17:55 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Guenther, gcc-patches, Martin Jambor, Diego Novillo

Hi,
I got somewhat lucky in testing previous patch since dumping of jump functions
was pretty much disabled by mismatch in headers of sections and they still got
recomputed due to bug in passmanager change.

This patch finally does the trick, but there are few extra changes in addition
to comment fixes requested by Diego.

  1) I now use produce_asm to get the section output with header.  This makes me
     to re-use function header that gets care of offsets and such.

     Same trick is already done by initializer pool.  Later I would like to
     cleanup the API so we have simple way of creating the output block with
     their own output block header containing the offsets needed and
     functions/decls/summaries can then use the block and embedd whatever
     headers they need into their main block.  But for now I just use that code
     since the patch has too much of snowballing effect.
  2) Added code into lto-stream-in.c to make whopr execute inliner transform method.
     Previously this was completely missed so we got clean run without checking
     only.
  3) There are several bugfixes into streaming in/out the data.
  4) LTO was saving work by not analyzing call to functions external to the unit.
     With LTO we need to analyze everything in hope that at linktime these
     won't be external.
  5) The cgraph during streaming differs from cgraph read back in a way that
     all calls appears in reversed order.  This confuse way I store call site info
     (that is just sequence in callgraph order) and also will make optimizations
     to diverge.  Fixed by streaming all callgraph edges in backward order.

     It might be prettier to output them in normal order and reverse list later,
     but I doubt it makes difference given that the files we produce are complette
     mess at the moment anyway.  I plan to do pass on cgraph streaming and avoid
     streaming unnecesary stuff etc. I can get this prettier then.

Regtested x86_64-linux, I am bootstrapping now.  OK?

	* 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.
	* 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.
	(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
	(lto_read_body): Push ipa_inline in ltrans stage.
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,705 ----
  	  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)
  	    continue;
  
  	  count = ipa_get_cs_argument_count (args);
*************** ipcp_generate_summary (void)
*** 1276,1281 ****
--- 1279,1298 ----
    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 */
--- 1325,1332 ----
    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,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 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 */
--- 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: 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
*************** lto_read_body (struct lto_file_decl_data
*** 1455,1460 ****
--- 1456,1470 ----
        /* 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)
+ 	 VEC_safe_push (ipa_opt_pass, heap,
+ 			cfun->ipa_transforms_to_apply,
+ 			(ipa_opt_pass)&pass_ipa_inline);
        pop_cfun ();
      }
    else 
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,2134 ----
    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, heap,
+ 			       ipa_edge_args_vector, cgraph_edge_max_uid + 1);
+       ipa_set_cs_argument_count (args, count);
+       if (!count)
+ 	continue;
+ 
+       args->jump_functions = XCNEWVEC (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);
+     }
+ }
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,
*************** 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  */

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-21 17:55         ` Jan Hubicka
@ 2009-10-21 19:42           ` Richard Guenther
  2009-10-21 20:07             ` Jan Hubicka
  0 siblings, 1 reply; 20+ messages in thread
From: Richard Guenther @ 2009-10-21 19:42 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Martin Jambor, Diego Novillo

On Wed, 21 Oct 2009, Jan Hubicka wrote:

> Hi,
> I got somewhat lucky in testing previous patch since dumping of jump functions
> was pretty much disabled by mismatch in headers of sections and they still got
> recomputed due to bug in passmanager change.
> 
> This patch finally does the trick, but there are few extra changes in addition
> to comment fixes requested by Diego.
> 
>   1) I now use produce_asm to get the section output with header.  This makes me
>      to re-use function header that gets care of offsets and such.
> 
>      Same trick is already done by initializer pool.  Later I would like to
>      cleanup the API so we have simple way of creating the output block with
>      their own output block header containing the offsets needed and
>      functions/decls/summaries can then use the block and embedd whatever
>      headers they need into their main block.  But for now I just use that code
>      since the patch has too much of snowballing effect.
>   2) Added code into lto-stream-in.c to make whopr execute inliner transform method.
>      Previously this was completely missed so we got clean run without checking
>      only.
>   3) There are several bugfixes into streaming in/out the data.
>   4) LTO was saving work by not analyzing call to functions external to the unit.
>      With LTO we need to analyze everything in hope that at linktime these
>      won't be external.
>   5) The cgraph during streaming differs from cgraph read back in a way that
>      all calls appears in reversed order.  This confuse way I store call site info
>      (that is just sequence in callgraph order) and also will make optimizations
>      to diverge.  Fixed by streaming all callgraph edges in backward order.
> 
>      It might be prettier to output them in normal order and reverse list later,
>      but I doubt it makes difference given that the files we produce are complette
>      mess at the moment anyway.  I plan to do pass on cgraph streaming and avoid
>      streaming unnecesary stuff etc. I can get this prettier then.
> 
> Regtested x86_64-linux, I am bootstrapping now.  OK?

Looks good, but preliminary SPEC2006 testing reveals a lot of ICEs in

lto1: internal compiler error: in ipcp_lats_are_equal, at ipa-cp.c:225

the assert looks bogus though, I'm testing with it removed.  There's
also

lto1: internal compiler error: Aborted

Richard.

> 	* 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.
> 	* 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.
> 	(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
> 	(lto_read_body): Push ipa_inline in ltrans stage.
> 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,705 ----
>   	  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)
>   	    continue;
>   
>   	  count = ipa_get_cs_argument_count (args);
> *************** ipcp_generate_summary (void)
> *** 1276,1281 ****
> --- 1279,1298 ----
>     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 */
> --- 1325,1332 ----
>     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,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 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 */
> --- 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: 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
> *************** lto_read_body (struct lto_file_decl_data
> *** 1455,1460 ****
> --- 1456,1470 ----
>         /* 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)
> + 	 VEC_safe_push (ipa_opt_pass, heap,
> + 			cfun->ipa_transforms_to_apply,
> + 			(ipa_opt_pass)&pass_ipa_inline);
>         pop_cfun ();
>       }
>     else 
> 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,2134 ----
>     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, heap,
> + 			       ipa_edge_args_vector, cgraph_edge_max_uid + 1);
> +       ipa_set_cs_argument_count (args, count);
> +       if (!count)
> + 	continue;
> + 
> +       args->jump_functions = XCNEWVEC (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);
> +     }
> + }
> 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,
> *************** 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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-21 19:42           ` Richard Guenther
@ 2009-10-21 20:07             ` Jan Hubicka
  2009-10-21 21:24               ` Jan Hubicka
  0 siblings, 1 reply; 20+ messages in thread
From: Jan Hubicka @ 2009-10-21 20:07 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Jan Hubicka, gcc-patches, Martin Jambor, Diego Novillo

> Looks good, but preliminary SPEC2006 testing reveals a lot of ICEs in
> 
> lto1: internal compiler error: in ipcp_lats_are_equal, at ipa-cp.c:225
> 
> the assert looks bogus though, I'm testing with it removed.  There's
> also
> 
> lto1: internal compiler error: Aborted

It is caused for testcases large enough so whole_program pass triggers GGC.
Problem is that originally ipa jump functions used to point to trees from function bodies.
Now while reading back, we create unshared copies.  This is OK, but we need to move the
jump functions into GGC memory.  I am working on it.

Honza

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-21 20:07             ` Jan Hubicka
@ 2009-10-21 21:24               ` Jan Hubicka
  2009-10-22  2:53                 ` Jan Hubicka
  0 siblings, 1 reply; 20+ messages in thread
From: Jan Hubicka @ 2009-10-21 21:24 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Guenther, gcc-patches, Martin Jambor, Diego Novillo

> > Looks good, but preliminary SPEC2006 testing reveals a lot of ICEs in
> > 
> > lto1: internal compiler error: in ipcp_lats_are_equal, at ipa-cp.c:225
> > 
> > the assert looks bogus though, I'm testing with it removed.  There's
> > also
> > 
> > lto1: internal compiler error: Aborted
> 
> It is caused for testcases large enough so whole_program pass triggers GGC.
> Problem is that originally ipa jump functions used to point to trees from function bodies.
> Now while reading back, we create unshared copies.  This is OK, but we need to move the
> jump functions into GGC memory.  I am working on it.

Hi,
this is updated patch (and perhaps final one?).  It solves the memory corruption
and problem with referencing unmerged decls from ipa params array.
Those gets populated as side effect of read-in process from DECL argument lists. But
at this time decls are not shared yet, so we get pointers to wrong memory.  I added
ipa_update_after_lto_read function to solve this that also recompute
flag if function was called with mismathcing arguments.

The patch now builds my testcases quite well, hope SPEC2006 will pass too...

Bootstrapping/regtesting x86_64-linux.


	* 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
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)
*** 738,743 ****
--- 742,750 ----
        ipcp_function_scale_print (dump_file);
      }
  
+   if (in_lto_p)
+     ipa_update_after_lto_read ();
+ 
    ipcp_propagate_stage ();
    if (ipcp_change_tops_to_bottom ())
      /* Some lattices have changed from IPA_TOP to IPA_BOTTOM.
*************** ipcp_generate_summary (void)
*** 1276,1281 ****
--- 1283,1302 ----
    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 */
--- 1329,1336 ----
    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)
!     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: 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.  */
+ 
+ ipa_update_after_lto_read (void)
+ {
+   struct cgraph_node *node;
+   struct cgraph_edge *cs;
+ 
+   for (node = cgraph_nodes; node; node = node->next)
+     {
+       int i;
+       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  */

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-21 21:24               ` Jan Hubicka
@ 2009-10-22  2:53                 ` Jan Hubicka
  2009-10-22  8:55                   ` Richard Guenther
  2009-10-26 20:22                   ` Martin Jambor
  0 siblings, 2 replies; 20+ messages in thread
From: Jan Hubicka @ 2009-10-22  2:53 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Guenther, gcc-patches, Martin Jambor, Diego Novillo

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?

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  */

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-22  2:53                 ` Jan Hubicka
@ 2009-10-22  8:55                   ` Richard Guenther
  2009-10-22 10:27                     ` Richard Guenther
  2009-10-26 20:22                   ` Martin Jambor
  1 sibling, 1 reply; 20+ messages in thread
From: Richard Guenther @ 2009-10-22  8:55 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Martin Jambor, Diego Novillo

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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-22  8:55                   ` Richard Guenther
@ 2009-10-22 10:27                     ` Richard Guenther
  2009-10-22 12:52                       ` Richard Guenther
  0 siblings, 1 reply; 20+ messages in thread
From: Richard Guenther @ 2009-10-22 10:27 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Martin Jambor, Diego Novillo

On Thu, 22 Oct 2009, Richard Guenther wrote:

> 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.

Like this (untested).

Richard.

2009-10-22  Richard Guenther  <rguenther@suse.de>

	* lto-streamer.h (lto_symtab_merge_cgraph_nodes): Declare.
	* lto-symtab.c (lto_symtab_merge): Do not merge the cgraph here.
	(lto_symtab_merge_decls_1): Do not drop non-prevailing entries here.
	(lto_symtab_merge_cgraph_nodes_1): New function.
	(lto_symtab_merge_cgraph_nodes): Likewise.

	lto/
	* lto.c (read_cgraph_and_symbols): Move IPA summary reading
	inbetween decl and type fixup and cgraph merging.

Index: gcc/lto-streamer.h
===================================================================
*** gcc/lto-streamer.h	(revision 153445)
--- gcc/lto-streamer.h	(working copy)
*************** void input_cgraph (void);
*** 843,848 ****
--- 843,849 ----
  extern void lto_symtab_register_decl (tree, ld_plugin_symbol_resolution_t,
  				      struct lto_file_decl_data *);
  extern void lto_symtab_merge_decls (void);
+ extern void lto_symtab_merge_cgraph_nodes (void);
  extern tree lto_symtab_prevailing_decl (tree decl);
  extern enum ld_plugin_symbol_resolution lto_symtab_get_resolution (tree decl);
  extern void lto_symtab_clear_resolution (tree decl);
Index: gcc/lto-symtab.c
===================================================================
*** gcc/lto-symtab.c	(revision 153445)
--- gcc/lto-symtab.c	(working copy)
*************** lto_symtab_merge (lto_symtab_entry_t pre
*** 239,249 ****
    TREE_ADDRESSABLE (prevailing_decl) |= TREE_ADDRESSABLE (decl);
    TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl);
  
-   /* Replace a cgraph node of entry with the prevailing one.  */
-   if (TREE_CODE (decl) == FUNCTION_DECL
-       && (node = cgraph_get_node (decl)) != NULL)
-     lto_cgraph_replace_node (node, cgraph_get_node (prevailing_decl));
- 
    /* The linker may ask us to combine two incompatible symbols.
       Detect this case and notify the caller of required diagnostics.  */
  
--- 239,244 ----
*************** lto_symtab_merge_decls_1 (void **slot, v
*** 599,607 ****
       mismatches.  */
    lto_symtab_merge_decls_2 (slot);
  
-   /* Drop all but the prevailing decl from the symtab.  */
-   prevailing->next = NULL;
- 
    return 1;
  }
  
--- 594,599 ----
*************** lto_symtab_merge_decls (void)
*** 614,619 ****
--- 606,646 ----
    htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL);
  }
  
+ /* Helper to process the decl chain for the symbol table entry *SLOT.  */
+ 
+ static int
+ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+ {
+   lto_symtab_entry_t e, prevailing = (lto_symtab_entry_t) *slot;
+   struct cgraph_node *prevailing_node;
+ 
+   if (TREE_CODE (prevailing->decl) != FUNCTION_DECL)
+     return 1;
+ 
+   /* Replace the cgraph node of each entry with the prevailing one.  */
+   prevailing_node = cgraph_get_node (prevailing->decl);
+   for (e = prevailing->next; e; e = e->next)
+     {
+       struct cgraph_node *node;
+       if ((node = cgraph_get_node (e->decl)) != NULL)
+ 	lto_cgraph_replace_node (node, prevailing_node);
+     }
+ 
+   /* Drop all but the prevailing decl from the symtab.  */
+   prevailing->next = NULL;
+ 
+   return 1;
+ }
+  
+ /* Merge cgraph nodes according to the symbol merging done by
+    lto_symtab_merge_decls.  */
+ 
+ void
+ lto_symtab_merge_cgraph_nodes (void)
+ {
+   lto_symtab_maybe_init_hash_table ();
+   htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
+ }
  
  /* Given the decl DECL, return the prevailing decl with the same name. */
  
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c	(revision 153445)
--- gcc/lto/lto.c	(working copy)
*************** read_cgraph_and_symbols (unsigned nfiles
*** 1823,1833 ****
    /* Read the callgraph.  */
    input_cgraph ();
  
    /* Read the IPA summary data.  */
    ipa_read_summaries ();
  
!   /* Merge global decls.  */
!   lto_symtab_merge_decls ();
  
    /* Mark cgraph nodes needed in the merged cgraph
       This normally happens in whole-program pass, but for
--- 1823,1842 ----
    /* Read the callgraph.  */
    input_cgraph ();
  
+   /* Merge global decls.  */
+   lto_symtab_merge_decls ();
+ 
+   /* Fixup all decls and types.  */
+   lto_fixup_decls (all_file_decl_data);
+ 
+   /* Free the type hash tables.  */
+   free_gimple_type_tables ();
+ 
    /* Read the IPA summary data.  */
    ipa_read_summaries ();
  
!   /* Finally merge the cgraph according to the decl merging decisions.  */
!   lto_symtab_merge_cgraph_nodes ();
  
    /* Mark cgraph nodes needed in the merged cgraph
       This normally happens in whole-program pass, but for
*************** read_cgraph_and_symbols (unsigned nfiles
*** 1844,1855 ****
  
    timevar_push (TV_IPA_LTO_DECL_IO);
  
-   /* Fixup all decls and types.  */
-   lto_fixup_decls (all_file_decl_data);
- 
-   /* Free the type hash tables.  */
-   free_gimple_type_tables ();
- 
    /* FIXME lto. This loop needs to be changed to use the pass manager to
       call the ipa passes directly.  */
    if (!errorcount)
--- 1853,1858 ----

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-22 10:27                     ` Richard Guenther
@ 2009-10-22 12:52                       ` Richard Guenther
  2009-10-22 13:02                         ` Jan Hubicka
  0 siblings, 1 reply; 20+ messages in thread
From: Richard Guenther @ 2009-10-22 12:52 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, Martin Jambor, Diego Novillo

On Thu, 22 Oct 2009, Richard Guenther wrote:

> On Thu, 22 Oct 2009, Richard Guenther wrote:
> 
> > 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.
> 
> Like this (untested).

Which doesn't (of course) work.  The following sort-of does, with
some extra WHOPR ICEs.

Richard.

2009-10-22  Richard Guenther  <rguenther@suse.de>

	* lto-streamer.h (lto_symtab_merge_cgraph_nodes): Declare.
	* lto-symtab.c (struct lto_symtab_entry_def): Add node member.
	(lto_symtab_merge): Do not merge cgraph nodes here.
	(lto_symtab_resolve_can_prevail_p): Simplify.
	(lto_symtab_resolve_symbols): Store cgraph node.
	(lto_symtab_merge_decls_1): Simplify.  Do not drop non-prevailing
	functions from the symtab.
	(lto_symtab_merge_cgraph_nodes_1): New function.
	(lto_symtab_merge_cgraph_nodes): Likewise.

	lto/
	* lto.c (lto_fixup_jump_functions): Remove.
	(lto_fixup_decls): Do not fixup jump functions.
	(read_cgraph_and_symbols): Schedule cgraph merging after
	summary reading.  Schedule type and decl fixup before
	summary reading.

Index: gcc/lto-symtab.c
===================================================================
*** gcc/lto-symtab.c.orig	2009-10-22 12:56:48.000000000 +0200
--- gcc/lto-symtab.c	2009-10-22 13:42:17.000000000 +0200
*************** struct GTY(()) lto_symtab_entry_def
*** 41,46 ****
--- 41,49 ----
    tree id;
    /* The symbol table entry, a DECL.  */
    tree decl;
+   /* The cgraph node if decl is a function decl.  Filled in during the
+      merging process.  */
+   struct cgraph_node *node;
    /* LTO file-data and symbol resolution for this decl.  */
    struct lto_file_decl_data * GTY((skip (""))) file_data;
    enum ld_plugin_symbol_resolution resolution;
*************** lto_symtab_merge (lto_symtab_entry_t pre
*** 232,249 ****
    tree prevailing_decl = prevailing->decl;
    tree decl = entry->decl;
    tree prevailing_type, type;
-   struct cgraph_node *node;
  
    /* Merge decl state in both directions, we may still end up using
       the new decl.  */
    TREE_ADDRESSABLE (prevailing_decl) |= TREE_ADDRESSABLE (decl);
    TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl);
  
-   /* Replace a cgraph node of entry with the prevailing one.  */
-   if (TREE_CODE (decl) == FUNCTION_DECL
-       && (node = cgraph_get_node (decl)) != NULL)
-     lto_cgraph_replace_node (node, cgraph_get_node (prevailing_decl));
- 
    /* The linker may ask us to combine two incompatible symbols.
       Detect this case and notify the caller of required diagnostics.  */
  
--- 235,246 ----
*************** lto_symtab_resolve_replaceable_p (lto_sy
*** 355,369 ****
  static bool
  lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
  {
-   struct cgraph_node *node;
- 
    if (!TREE_STATIC (e->decl))
      return false;
  
    /* For functions we need a non-discarded body.  */
    if (TREE_CODE (e->decl) == FUNCTION_DECL)
!     return ((node = cgraph_get_node (e->decl))
! 	    && node->analyzed);
  
    /* A variable should have a size.  */
    else if (TREE_CODE (e->decl) == VAR_DECL)
--- 352,363 ----
  static bool
  lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
  {
    if (!TREE_STATIC (e->decl))
      return false;
  
    /* For functions we need a non-discarded body.  */
    if (TREE_CODE (e->decl) == FUNCTION_DECL)
!     return (e->node && e->node->analyzed);
  
    /* A variable should have a size.  */
    else if (TREE_CODE (e->decl) == VAR_DECL)
*************** lto_symtab_resolve_symbols (void **slot)
*** 393,398 ****
--- 387,395 ----
       diagnose ODR violations.  */
    for (; e; e = e->next)
      {
+       if (TREE_CODE (e->decl) == FUNCTION_DECL)
+ 	e->node = cgraph_get_node (e->decl);
+ 
        if (!lto_symtab_resolve_can_prevail_p (e))
  	{
  	  e->resolution = LDPR_RESOLVED_IR;
*************** lto_symtab_merge_decls_1 (void **slot, v
*** 531,537 ****
        prevailing = (lto_symtab_entry_t) *slot;
        /* For functions choose one with a cgraph node.  */
        if (TREE_CODE (prevailing->decl) == FUNCTION_DECL)
! 	while (!cgraph_get_node (prevailing->decl)
  	       && prevailing->next)
  	  prevailing = prevailing->next;
        /* We do not stream varpool nodes, so the first decl has to
--- 528,534 ----
        prevailing = (lto_symtab_entry_t) *slot;
        /* For functions choose one with a cgraph node.  */
        if (TREE_CODE (prevailing->decl) == FUNCTION_DECL)
! 	while (!prevailing->node
  	       && prevailing->next)
  	  prevailing = prevailing->next;
        /* We do not stream varpool nodes, so the first decl has to
*************** lto_symtab_merge_decls_1 (void **slot, v
*** 600,606 ****
    lto_symtab_merge_decls_2 (slot);
  
    /* Drop all but the prevailing decl from the symtab.  */
!   prevailing->next = NULL;
  
    return 1;
  }
--- 597,604 ----
    lto_symtab_merge_decls_2 (slot);
  
    /* Drop all but the prevailing decl from the symtab.  */
!   if (TREE_CODE (prevailing->decl) != FUNCTION_DECL)
!     prevailing->next = NULL;
  
    return 1;
  }
*************** lto_symtab_merge_decls (void)
*** 614,619 ****
--- 612,651 ----
    htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL);
  }
  
+ /* Helper to process the decl chain for the symbol table entry *SLOT.  */
+ 
+ static int
+ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+ {
+   lto_symtab_entry_t e, prevailing = (lto_symtab_entry_t) *slot;
+ 
+   if (!prevailing->next)
+     return 1;
+ 
+   gcc_assert (TREE_CODE (prevailing->decl) == FUNCTION_DECL);
+ 
+   /* Replace the cgraph node of each entry with the prevailing one.  */
+   for (e = prevailing->next; e; e = e->next)
+     {
+       if (e->node != NULL)
+ 	lto_cgraph_replace_node (e->node, prevailing->node);
+     }
+ 
+   /* Drop all but the prevailing decl from the symtab.  */
+   prevailing->next = NULL;
+ 
+   return 1;
+ }
+ 
+ /* Merge cgraph nodes according to the symbol merging done by
+    lto_symtab_merge_decls.  */
+ 
+ void
+ lto_symtab_merge_cgraph_nodes (void)
+ {
+   lto_symtab_maybe_init_hash_table ();
+   htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
+ }
  
  /* Given the decl DECL, return the prevailing decl with the same name. */
  
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c.orig	2009-10-22 12:57:41.000000000 +0200
--- gcc/lto/lto.c	2009-10-22 13:42:38.000000000 +0200
*************** lto_fixup_state_aux (void **slot, void *
*** 1635,1687 ****
    return 1;
  }
  
- /* 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.  */
  
--- 1635,1640 ----
*************** lto_fixup_decls (struct lto_file_decl_da
*** 1710,1717 ****
        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_destroy (seen);
  }
--- 1663,1668 ----
*************** read_cgraph_and_symbols (unsigned nfiles
*** 1851,1861 ****
    /* Read the callgraph.  */
    input_cgraph ();
  
    /* Read the IPA summary data.  */
    ipa_read_summaries ();
  
!   /* Merge global decls.  */
!   lto_symtab_merge_decls ();
  
    /* Mark cgraph nodes needed in the merged cgraph
       This normally happens in whole-program pass, but for
--- 1802,1819 ----
    /* Read the callgraph.  */
    input_cgraph ();
  
+   /* Merge global decls.  */
+   lto_symtab_merge_decls ();
+ 
+   /* Fixup all decls and types and free the type hash tables.  */
+   lto_fixup_decls (all_file_decl_data);
+   free_gimple_type_tables ();
+ 
    /* Read the IPA summary data.  */
    ipa_read_summaries ();
  
!   /* Finally merge the cgraph according to the decl merging decisions.  */
!   lto_symtab_merge_cgraph_nodes ();
  
    /* Mark cgraph nodes needed in the merged cgraph
       This normally happens in whole-program pass, but for
*************** read_cgraph_and_symbols (unsigned nfiles
*** 1872,1883 ****
  
    timevar_push (TV_IPA_LTO_DECL_IO);
  
-   /* Fixup all decls and types.  */
-   lto_fixup_decls (all_file_decl_data);
- 
-   /* Free the type hash tables.  */
-   free_gimple_type_tables ();
- 
    /* FIXME lto. This loop needs to be changed to use the pass manager to
       call the ipa passes directly.  */
    if (!errorcount)
--- 1830,1835 ----
Index: gcc/lto-streamer.h
===================================================================
*** gcc/lto-streamer.h.orig	2009-10-22 12:56:48.000000000 +0200
--- gcc/lto-streamer.h	2009-10-22 13:41:57.000000000 +0200
*************** void input_cgraph (void);
*** 845,850 ****
--- 845,851 ----
  extern void lto_symtab_register_decl (tree, ld_plugin_symbol_resolution_t,
  				      struct lto_file_decl_data *);
  extern void lto_symtab_merge_decls (void);
+ extern void lto_symtab_merge_cgraph_nodes (void);
  extern tree lto_symtab_prevailing_decl (tree decl);
  extern enum ld_plugin_symbol_resolution lto_symtab_get_resolution (tree decl);
  

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-22 12:52                       ` Richard Guenther
@ 2009-10-22 13:02                         ` Jan Hubicka
  0 siblings, 0 replies; 20+ messages in thread
From: Jan Hubicka @ 2009-10-22 13:02 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Jan Hubicka, gcc-patches, Martin Jambor, Diego Novillo

> On Thu, 22 Oct 2009, Richard Guenther wrote:
> 
> > On Thu, 22 Oct 2009, Richard Guenther wrote:
> > 
> > > 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.
> > 
> > Like this (untested).
> 
> Which doesn't (of course) work.  The following sort-of does, with
> some extra WHOPR ICEs.

Thanks,
I will shortly test and send patch disabling indirect inlining at WPA stage (so we don't
get into confussion with jump functions). In order to do indirect inlining at WPA we
will need to fix WPA's dealing with passes to not run inliner manually (so we skip reading
of summaries that happens in ipa-cp or inliner depending on -fipa-cp flag) and
to add streaming of indirect call summaries Martin promised to work on.

THe patch makes sense to me, so it would be nice to get it into mainline so we can
fix ipa-reference WRT -fwhole-program.

Honza

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-22  2:53                 ` Jan Hubicka
  2009-10-22  8:55                   ` Richard Guenther
@ 2009-10-26 20:22                   ` Martin Jambor
  2009-10-26 22:30                     ` Jan Hubicka
  1 sibling, 1 reply; 20+ messages in thread
From: Martin Jambor @ 2009-10-26 20:22 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

Hi,

sorry for replying this late but I haven't managed to read the patch
earlier.  OTOH, I only have one question and two rather minor
comments.

On Thu, Oct 22, 2009 at 02:39:00AM +0200, Jan Hubicka wrote:
> Index: ipa-cp.c
> ===================================================================
> *** ipa-cp.c	(revision 152974)
> --- ipa-cp.c	(working copy)

...

> *************** 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;

ipa_is_called_with_var_arguments is tested twice which does not make
any sense, I'll try to remember to clean this up when I get to
modifying the file.

>   
>   	  count = ipa_get_cs_argument_count (args);

...

> Index: ipa-prop.c
> ===================================================================
> *** ipa-prop.c	(revision 152974)
> --- ipa-prop.c	(working copy)

...

> *************** 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).  */

I am puzzled by this comment (and the corresponding one in the
previous function).  No matter for how long I stare at the code I
don't see what is read "in the opposite order."  All corresponding
loops loop in the same direction, modified and called flags are also
read in the same order... What is it?

> +   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);

This vector growth is either unnecessary or wrong.  My guess is that
it is unnecessary as I don't see anything later in the loop which can
create new edges.  If I am wrong and it is necessary then 1) calling
ipa_check_create_edge_args() would probably be nicer, and more
importantly 2) the local variable args must be initialized after the
vector is grown because it is invalidated if the vector gets
relocated.  So which is it?

Otherwise, thanks a lot for demonstrating how the streaming works (and
making it work in the first place!),

Martin


> +       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  */

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: LTO/WHOPR summary streaming fixes
  2009-10-26 20:22                   ` Martin Jambor
@ 2009-10-26 22:30                     ` Jan Hubicka
  0 siblings, 0 replies; 20+ messages in thread
From: Jan Hubicka @ 2009-10-26 22:30 UTC (permalink / raw)
  To: Jan Hubicka, gcc-patches

> > + 
> > +   /* Note that the flags must be read in the opposite
> > +      order in which they were written (the bitflags were
> > +      pushed into FLAGS).  */
> 
> I am puzzled by this comment (and the corresponding one in the
> previous function).  No matter for how long I stare at the code I
> don't see what is read "in the opposite order."  All corresponding
> loops loop in the same direction, modified and called flags are also
> read in the same order... What is it?

Ah, it is pasto from ipa-pure-const (that have same nonsense in it)
> 
> This vector growth is either unnecessary or wrong.  My guess is that
> it is unnecessary as I don't see anything later in the loop which can
> create new edges.  If I am wrong and it is necessary then 1) calling
> ipa_check_create_edge_args() would probably be nicer, and more
> importantly 2) the local variable args must be initialized after the
> vector is grown because it is invalidated if the vector gets
> relocated.  So which is it?

Hmm, I was under impression that the argument array gets allocated here.
It is possible it happens earlier.

Honza

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2009-10-26 22:15 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-10-20 15:01 LTO/WHOPR summary streaming fixes Jan Hubicka
2009-10-20 15:05 ` Richard Guenther
2009-10-20 15:17   ` Richard Guenther
2009-10-20 15:22     ` Richard Guenther
2009-10-20 21:28       ` Jan Hubicka
2009-10-21 17:55         ` Jan Hubicka
2009-10-21 19:42           ` Richard Guenther
2009-10-21 20:07             ` Jan Hubicka
2009-10-21 21:24               ` Jan Hubicka
2009-10-22  2:53                 ` Jan Hubicka
2009-10-22  8:55                   ` Richard Guenther
2009-10-22 10:27                     ` Richard Guenther
2009-10-22 12:52                       ` Richard Guenther
2009-10-22 13:02                         ` Jan Hubicka
2009-10-26 20:22                   ` Martin Jambor
2009-10-26 22:30                     ` Jan Hubicka
2009-10-20 15:06 ` Diego Novillo
2009-10-20 15:10   ` Jan Hubicka
2009-10-20 15:12     ` Diego Novillo
2009-10-20 16:18       ` Martin Jambor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).