[PATCH 1/N] Clean-up usage of ipa_fn_summary and ipa_call_summary summaries.

Jan Hubicka hubicka@ucw.cz
Fri Jun 15 15:05:00 GMT 2018


> Hi.
> 
> This is first part of IPA summary conversion clean-up. It removes ::get_create and
> uses ::get for ipa-inline related symbol (and call) summaries. I'm planning to
> investigate also other summaries.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?
> Martin
> 
> gcc/ChangeLog:
> 
> 2018-06-15  Martin Liska  <mliska@suse.cz>
> 
> 	* config/i386/i386.c (ix86_can_inline_p): Do not use
>         ipa_fn_summaries::get_create.
> 	* ipa-cp.c (ipcp_cloning_candidate_p): Replace get_create with
>         get.
> 	(devirtualization_time_bonus): Likewise.
> 	(ipcp_propagate_stage): Likewise.
> 	* ipa-fnsummary.c (redirect_to_unreachable): Likewise.
> 	(edge_set_predicate): Likewise.
> 	(evaluate_conditions_for_known_args): Likewise.
> 	(evaluate_properties_for_edge): Likewise.
> 	(ipa_call_summary::reset): Tranform to ...
> 	(ipa_call_summary::~ipa_call_summary): ... this.
> 	(ipa_fn_summary::reset): Transform to ...
> 	(ipa_fn_summary::~ipa_fn_summary): ... this.
> 	(ipa_fn_summary_t::remove): Rename to ...
> 	(ipa_fn_summary_t::remove_callees): ... this.
> 	(ipa_fn_summary_t::duplicate): Use placement new
>         instead of memory copy.
> 	(ipa_call_summary_t::duplicate): Likewise.
> 	(ipa_call_summary_t::remove): Remove.
> 	(dump_ipa_call_summary): Change get_create to get.
> 	(ipa_dump_fn_summary): Dump only when summary exists.
> 	(analyze_function_body): Use symbol_summary::get instead
>         of get_create.
> 	(compute_fn_summary): Likewise.
> 	(estimate_edge_devirt_benefit): Likewise.
> 	(estimate_edge_size_and_time): Likewise.
> 	(inline_update_callee_summaries): Likewise.
> 	(remap_edge_change_prob): Likewise.
> 	(remap_edge_summaries): Likewise.
> 	(ipa_merge_fn_summary_after_inlining): Likewise.
> 	(write_ipa_call_summary): Likewise.
> 	(ipa_fn_summary_write): Likewise.
> 	(ipa_free_fn_summary): Likewise.
> 	* ipa-fnsummary.h (struct GTY): Add new ctor and copy ctor.
> 	(struct ipa_call_summary): Likewise.
> 	* ipa-icf.c (sem_function::merge): Use symbol_summary::get instead
>         of get_create.
> 	* ipa-inline-analysis.c (do_estimate_edge_time): Likewise.
> 	(estimate_size_after_inlining): Likewise.
> 	(estimate_growth): Likewise.
> 	(growth_likely_positive): Likewise.
> 	* ipa-inline-transform.c (clone_inlined_nodes): Likewise.
> 	(inline_call): Likewise.
> 	* ipa-inline.c (caller_growth_limits): Likewise.
> 	(can_inline_edge_p): Likewise.
> 	(can_inline_edge_by_limits_p): Likewise.
> 	(compute_uninlined_call_time): Likewise.
> 	(compute_inlined_call_time): Likewise.
> 	(want_inline_small_function_p): Likewise.
> 	(edge_badness): Likewise.
> 	(update_caller_keys): Likewise.
> 	(update_callee_keys): Likewise.
> 	(inline_small_functions): Likewise.
> 	(inline_to_all_callers_1): Likewise.
> 	(dump_overall_stats): Likewise.
> 	(early_inline_small_functions): Likewise.
> 	(early_inliner): Likewise.
> 	* ipa-profile.c (ipa_propagate_frequency_1): Likewise.
> 	* ipa-prop.c (ipa_make_edge_direct_to_target): Likewise.
> 	* ipa-pure-const.c (malloc_candidate_p): Likewise.
> 	* ipa-split.c (execute_split_functions): Likewise.
> 	* symbol-summary.h: Likewise.
> 	* tree-sra.c (ipa_sra_preliminary_function_checks): Likewise.
> 

OK with changes marked below.

> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index 95cfa05ce61..a40ee0d1258 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -5760,6 +5760,7 @@ ix86_can_inline_p (tree caller, tree callee)
>        && lookup_attribute ("always_inline",
>  			   DECL_ATTRIBUTES (callee)));
>  
> +  cgraph_node *callee_node = cgraph_node::get (callee);
>    /* Callee's isa options should be a subset of the caller's, i.e. a SSE4
>       function can inline a SSE2 function but a SSE2 function can't inline
>       a SSE4 function.  */
> @@ -5789,8 +5790,8 @@ ix86_can_inline_p (tree caller, tree callee)
>  	      for multi-versioning call optimization, so beware of
>  	      ipa_fn_summaries not available.  */
>  	   && (! ipa_fn_summaries
> -	       || ipa_fn_summaries->get_create
> -	       (cgraph_node::get (callee))->fp_expressions))
> +	       || ipa_fn_summaries->get (callee_node) == NULL
> +	       || ipa_fn_summaries->get (callee_node)->fp_expressions))
>      ret = false;
>  
>    else if (!always_inline
> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
> index 435c9ee1638..c192e84f452 100644
> --- a/gcc/ipa-cp.c
> +++ b/gcc/ipa-cp.c
> @@ -736,7 +736,7 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
>    init_caller_stats (&stats);
>    node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, false);
>  
> -  if (ipa_fn_summaries->get_create (node)->self_size < stats.n_calls)
> +  if (ipa_fn_summaries->get (node)->self_size < stats.n_calls)
>      {
>        if (dump_file)
>  	fprintf (dump_file, "Considering %s for cloning; code might shrink.\n",
> @@ -2583,7 +2583,7 @@ devirtualization_time_bonus (struct cgraph_node *node,
>        callee = callee->function_symbol (&avail);
>        if (avail < AVAIL_AVAILABLE)
>  	continue;
> -      isummary = ipa_fn_summaries->get_create (callee);
> +      isummary = ipa_fn_summaries->get (callee);
>        if (!isummary->inlinable)
>  	continue;
>  
> @@ -3287,8 +3287,9 @@ ipcp_propagate_stage (struct ipa_topo_info *topo)
>  				   ipa_get_param_count (info));
>  	initialize_node_lattices (node);
>        }
> -    if (node->definition && !node->alias)
> -      overall_size += ipa_fn_summaries->get_create (node)->self_size;
> +    ipa_fn_summary *s = ipa_fn_summaries->get (node);
> +    if (node->definition && !node->alias && s != NULL)
> +      overall_size += s->self_size;

I wonder how possibly we can get NULL here? That seems like bug to me...
>      max_count = max_count.max (node->count.ipa ());
>    }
>  
> diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
> index e40b537bf61..6061a470f38 100644
> --- a/gcc/ipa-fnsummary.c
> +++ b/gcc/ipa-fnsummary.c
> @@ -241,7 +241,7 @@ redirect_to_unreachable (struct cgraph_edge *e)
>      e->make_direct (target);
>    else
>      e->redirect_callee (target);
> -  struct ipa_call_summary *es = ipa_call_summaries->get_create (e);
> +  struct ipa_call_summary *es = ipa_call_summaries->get (e);
>    e->inline_failed = CIF_UNREACHABLE;
>    e->count = profile_count::zero ();
>    es->call_stmt_size = 0;
> @@ -266,7 +266,7 @@ edge_set_predicate (struct cgraph_edge *e, predicate *predicate)
>        && (!e->speculative || e->callee))
>      e = redirect_to_unreachable (e);
>  
> -  struct ipa_call_summary *es = ipa_call_summaries->get_create (e);
> +  struct ipa_call_summary *es = ipa_call_summaries->get (e);
>    if (predicate && *predicate != true)
>      {
>        if (!es->predicate)
> @@ -328,7 +328,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
>  {
>    clause_t clause = inline_p ? 0 : 1 << predicate::not_inlined_condition;
>    clause_t nonspec_clause = 1 << predicate::not_inlined_condition;
> -  struct ipa_fn_summary *info = ipa_fn_summaries->get_create (node);
> +  struct ipa_fn_summary *info = ipa_fn_summaries->get (node);
>    int i;
>    struct condition *c;
>  
> @@ -428,7 +428,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>  			      vec<ipa_agg_jump_function_p> *known_aggs_ptr)
>  {
>    struct cgraph_node *callee = e->callee->ultimate_alias_target ();
> -  struct ipa_fn_summary *info = ipa_fn_summaries->get_create (callee);
> +  struct ipa_fn_summary *info = ipa_fn_summaries->get (callee);
>    vec<tree> known_vals = vNULL;
>    vec<ipa_agg_jump_function_p> known_aggs = vNULL;
>  
> @@ -445,7 +445,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>      {
>        struct ipa_node_params *caller_parms_info, *callee_pi;
>        struct ipa_edge_args *args = IPA_EDGE_REF (e);
> -      struct ipa_call_summary *es = ipa_call_summaries->get_create (e);
> +      struct ipa_call_summary *es = ipa_call_summaries->get (e);
>        int i, count = ipa_get_cs_argument_count (args);
>  
>        if (e->caller->global.inlined_to)
> @@ -535,66 +535,34 @@ ipa_fn_summary_alloc (void)
>    ipa_call_summaries = new ipa_call_summary_t (symtab, false);
>  }
>  
> -/* We are called multiple time for given function; clear
> -   data from previous run so they are not cumulated.  */
> -
> -void
> -ipa_call_summary::reset ()
> +ipa_call_summary::~ipa_call_summary ()
>  {
> -  call_stmt_size = call_stmt_time = 0;
> -  is_return_callee_uncaptured = false;
>    if (predicate)
>      edge_predicate_pool.remove (predicate);
> -  predicate = NULL;
> +
>    param.release ();
>  }
>  
> -/* We are called multiple time for given function; clear
> -   data from previous run so they are not cumulated.  */
> -
> -void
> -ipa_fn_summary::reset (struct cgraph_node *node)
> +ipa_fn_summary::~ipa_fn_summary ()
>  {
> -  struct cgraph_edge *e;
> -
> -  self_size = 0;
> -  estimated_stack_size = 0;
> -  estimated_self_stack_size = 0;
> -  stack_frame_offset = 0;
> -  size = 0;
> -  time = 0;
> -  growth = 0;
> -  scc_no = 0;
>    if (loop_iterations)
> -    {
> -      edge_predicate_pool.remove (loop_iterations);
> -      loop_iterations = NULL;
> -    }
> +    edge_predicate_pool.remove (loop_iterations);
>    if (loop_stride)
> -    {
> -      edge_predicate_pool.remove (loop_stride);
> -      loop_stride = NULL;
> -    }
> +    edge_predicate_pool.remove (loop_stride);
>    if (array_index)
> -    {
> -      edge_predicate_pool.remove (array_index);
> -      array_index = NULL;
> -    }
> +    edge_predicate_pool.remove (array_index);
>    vec_free (conds);
>    vec_free (size_time_table);
> -  for (e = node->callees; e; e = e->next_callee)
> -    ipa_call_summaries->get_create (e)->reset ();
> -  for (e = node->indirect_calls; e; e = e->next_callee)
> -    ipa_call_summaries->get_create (e)->reset ();
> -  fp_expressions = false;
>  }
>  
> -/* Hook that is called by cgraph.c when a node is removed.  */
> -
>  void
> -ipa_fn_summary_t::remove (cgraph_node *node, ipa_fn_summary *info)
> +ipa_fn_summary_t::remove_callees (cgraph_node *node)
>  {
> -  info->reset (node);
> +  cgraph_edge *e;
> +  for (e = node->callees; e; e = e->next_callee)
> +    ipa_call_summaries->remove (e);
> +  for (e = node->indirect_calls; e; e = e->next_callee)
> +    ipa_call_summaries->remove (e);
>  }
>  
>  /* Same as remap_predicate_after_duplication but handle hint predicate *P.
> @@ -625,7 +593,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
>  			     ipa_fn_summary *,
>  			     ipa_fn_summary *info)
>  {
> -  memcpy (info, ipa_fn_summaries->get_create (src), sizeof (ipa_fn_summary));
> +  new (info) ipa_fn_summary (*ipa_fn_summaries->get (src));
>    /* TODO: as an optimization, we may avoid copying conditions
>       that are known to be false or true.  */
>    info->conds = vec_safe_copy (info->conds);
> @@ -779,7 +747,7 @@ ipa_call_summary_t::duplicate (struct cgraph_edge *src,
>  			       struct ipa_call_summary *srcinfo,
>  			       struct ipa_call_summary *info)
>  {
> -  *info = *srcinfo;
> +  new (info) ipa_call_summary (*srcinfo);
>    info->predicate = NULL;
>    edge_set_predicate (dst, srcinfo->predicate);
>    info->param = srcinfo->param.copy ();
> @@ -792,17 +760,6 @@ ipa_call_summary_t::duplicate (struct cgraph_edge *src,
>      }
>  }
>  
> -
> -/* Keep edge cache consistent across edge removal.  */
> -
> -void
> -ipa_call_summary_t::remove (struct cgraph_edge *,
> -			    struct ipa_call_summary *sum)
> -{
> -  sum->reset ();
> -}
> -
> -
>  /* Dump edge summaries associated to NODE and recursively to all clones.
>     Indent by INDENT.  */
>  
> @@ -813,21 +770,23 @@ dump_ipa_call_summary (FILE *f, int indent, struct cgraph_node *node,
>    struct cgraph_edge *edge;
>    for (edge = node->callees; edge; edge = edge->next_callee)
>      {
> -      struct ipa_call_summary *es = ipa_call_summaries->get_create (edge);
> +      struct ipa_call_summary *es = ipa_call_summaries->get (edge);
>        struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
>        int i;
>  
>        fprintf (f,
> -	       "%*s%s/%i %s\n%*s  loop depth:%2i freq:%4.2f size:%2i"
> -	       " time: %2i callee size:%2i stack:%2i",
> +	       "%*s%s/%i %s\n%*s  loop depth:%2i freq:%4.2f size:%2i time: %2i",
>  	       indent, "", callee->name (), callee->order,
>  	       !edge->inline_failed
>  	       ? "inlined" : cgraph_inline_failed_string (edge-> inline_failed),
>  	       indent, "", es->loop_depth, edge->sreal_frequency ().to_double (),
> -	       es->call_stmt_size, es->call_stmt_time,
> -	       (int) (ipa_fn_summaries->get_create (callee)->size
> -		      / ipa_fn_summary::size_scale),
> -	       (int) ipa_fn_summaries->get_create (callee)->estimated_stack_size);
> +	       es->call_stmt_size, es->call_stmt_time);
> +
> +      ipa_fn_summary *s = ipa_fn_summaries->get (callee);
> +      if (s != NULL)
> +	fprintf (f, "callee size:%2i stack:%2i",
> +		 (int) (s->size / ipa_fn_summary::size_scale),
> +		 (int) s->estimated_stack_size);
>  
>        if (es->predicate)
>  	{
> @@ -862,7 +821,7 @@ dump_ipa_call_summary (FILE *f, int indent, struct cgraph_node *node,
>      }
>    for (edge = node->indirect_calls; edge; edge = edge->next_callee)
>      {
> -      struct ipa_call_summary *es = ipa_call_summaries->get_create (edge);
> +      struct ipa_call_summary *es = ipa_call_summaries->get (edge);
>        fprintf (f, "%*sindirect call loop depth:%2i freq:%4.2f size:%2i"
>  	       " time: %2i",
>  	       indent, "",
> @@ -885,63 +844,67 @@ ipa_dump_fn_summary (FILE *f, struct cgraph_node *node)
>  {
>    if (node->definition)
>      {
> -      struct ipa_fn_summary *s = ipa_fn_summaries->get_create (node);
> -      size_time_entry *e;
> -      int i;
> -      fprintf (f, "IPA function summary for %s/%i", node->name (),
> -	       node->order);
> -      if (DECL_DISREGARD_INLINE_LIMITS (node->decl))
> -	fprintf (f, " always_inline");
> -      if (s->inlinable)
> -	fprintf (f, " inlinable");
> -      if (s->fp_expressions)
> -	fprintf (f, " fp_expression");
> -      fprintf (f, "\n  global time:     %f\n", s->time.to_double ());
> -      fprintf (f, "  self size:       %i\n", s->self_size);
> -      fprintf (f, "  global size:     %i\n", s->size);
> -      fprintf (f, "  min size:       %i\n", s->min_size);
> -      fprintf (f, "  self stack:      %i\n",
> -	       (int) s->estimated_self_stack_size);
> -      fprintf (f, "  global stack:    %i\n", (int) s->estimated_stack_size);
> -      if (s->growth)
> -	fprintf (f, "  estimated growth:%i\n", (int) s->growth);
> -      if (s->scc_no)
> -	fprintf (f, "  In SCC:          %i\n", (int) s->scc_no);
> -      for (i = 0; vec_safe_iterate (s->size_time_table, i, &e); i++)
> +      struct ipa_fn_summary *s = ipa_fn_summaries->get (node);
> +      if (s != NULL)
>  	{
> -	  fprintf (f, "    size:%f, time:%f",
> -		   (double) e->size / ipa_fn_summary::size_scale,
> -		   e->time.to_double ());
> -	  if (e->exec_predicate != true)
> +	  size_time_entry *e;
> +	  int i;
> +	  fprintf (f, "IPA function summary for %s", node->dump_name ());
> +	  if (DECL_DISREGARD_INLINE_LIMITS (node->decl))
> +	    fprintf (f, " always_inline");
> +	  if (s->inlinable)
> +	    fprintf (f, " inlinable");
> +	  if (s->fp_expressions)
> +	    fprintf (f, " fp_expression");
> +	  fprintf (f, "\n  global time:     %f\n", s->time.to_double ());
> +	  fprintf (f, "  self size:       %i\n", s->self_size);
> +	  fprintf (f, "  global size:     %i\n", s->size);
> +	  fprintf (f, "  min size:       %i\n", s->min_size);
> +	  fprintf (f, "  self stack:      %i\n",
> +		   (int) s->estimated_self_stack_size);
> +	  fprintf (f, "  global stack:    %i\n", (int) s->estimated_stack_size);
> +	  if (s->growth)
> +	    fprintf (f, "  estimated growth:%i\n", (int) s->growth);
> +	  if (s->scc_no)
> +	    fprintf (f, "  In SCC:          %i\n", (int) s->scc_no);
> +	  for (i = 0; vec_safe_iterate (s->size_time_table, i, &e); i++)
> +	    {
> +	      fprintf (f, "    size:%f, time:%f",
> +		       (double) e->size / ipa_fn_summary::size_scale,
> +		       e->time.to_double ());
> +	      if (e->exec_predicate != true)
> +		{
> +		  fprintf (f, ",  executed if:");
> +		  e->exec_predicate.dump (f, s->conds, 0);
> +		}
> +	      if (e->exec_predicate != e->nonconst_predicate)
> +		{
> +		  fprintf (f, ",  nonconst if:");
> +		  e->nonconst_predicate.dump (f, s->conds, 0);
> +		}
> +	      fprintf (f, "\n");
> +	    }
> +	  if (s->loop_iterations)
>  	    {
> -	      fprintf (f, ",  executed if:");
> -	      e->exec_predicate.dump (f, s->conds, 0);
> +	      fprintf (f, "  loop iterations:");
> +	      s->loop_iterations->dump (f, s->conds);
>  	    }
> -	  if (e->exec_predicate != e->nonconst_predicate)
> +	  if (s->loop_stride)
>  	    {
> -	      fprintf (f, ",  nonconst if:");
> -	      e->nonconst_predicate.dump (f, s->conds, 0);
> +	      fprintf (f, "  loop stride:");
> +	      s->loop_stride->dump (f, s->conds);
>  	    }
> +	  if (s->array_index)
> +	    {
> +	      fprintf (f, "  array index:");
> +	      s->array_index->dump (f, s->conds);
> +	    }
> +	  fprintf (f, "  calls:\n");
> +	  dump_ipa_call_summary (f, 4, node, s);
>  	  fprintf (f, "\n");
>  	}
> -      if (s->loop_iterations)
> -	{
> -	  fprintf (f, "  loop iterations:");
> -	  s->loop_iterations->dump (f, s->conds);
> -	}
> -      if (s->loop_stride)
> -	{
> -	  fprintf (f, "  loop stride:");
> -	  s->loop_stride->dump (f, s->conds);
> -	}
> -      if (s->array_index)
> -	{
> -	  fprintf (f, "  array index:");
> -	  s->array_index->dump (f, s->conds);
> -	}
> -      fprintf (f, "  calls:\n");
> -      dump_ipa_call_summary (f, 4, node, s);
> -      fprintf (f, "\n");
> +      else
> +	fprintf (f, "IPA summary for %s is missing.\n", node->dump_name ());
>      }
>  }
>  
> @@ -2363,7 +2326,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
>  	    }
>  	  free (body);
>  	}
> -      ipa_fn_summary *s = ipa_fn_summaries->get_create (node);
> +      ipa_fn_summary *s = ipa_fn_summaries->get (node);
>        set_hint_predicate (&s->loop_iterations, loop_iterations);
>        set_hint_predicate (&s->loop_stride, loop_stride);
>        scev_finalize ();
> @@ -2383,7 +2346,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
>  	  e->aux = NULL;
>  	}
>      }
> -  ipa_fn_summary *s = ipa_fn_summaries->get_create (node);
> +  ipa_fn_summary *s = ipa_fn_summaries->get (node);
>    s->time = time;
>    s->self_size = size;
>    nonconstant_names.release ();
> @@ -2419,8 +2382,10 @@ compute_fn_summary (struct cgraph_node *node, bool early)
>    if (!ipa_fn_summaries)
>      ipa_fn_summary_alloc ();
>  
> +  /* Create a new ipa_fn_summary.  */
> +  ((ipa_fn_summary_t *)ipa_fn_summaries)->remove_callees (node);
> +  ipa_fn_summaries->remove (node);
>    info = ipa_fn_summaries->get_create (node);
> -  info->reset (node);
>  
>    /* Estimate the stack size for the function if we're optimizing.  */
>    self_stack_size = optimize && !node->thunk.thunk_p
> @@ -2575,7 +2540,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
>    callee = callee->function_symbol (&avail);
>    if (avail < AVAIL_AVAILABLE)
>      return false;
> -  isummary = ipa_fn_summaries->get_create (callee);
> +  isummary = ipa_fn_summaries->get (callee);
>    return isummary->inlinable;
>  }
>  
> @@ -2594,7 +2559,7 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size,
>  			     vec<ipa_agg_jump_function_p> known_aggs,
>  			     ipa_hints *hints)
>  {
> -  struct ipa_call_summary *es = ipa_call_summaries->get_create (e);
> +  struct ipa_call_summary *es = ipa_call_summaries->get (e);
>    int call_size = es->call_stmt_size;
>    int call_time = es->call_stmt_time;
>    int cur_size;
> @@ -2851,9 +2816,8 @@ static void
>  inline_update_callee_summaries (struct cgraph_node *node, int depth)
>  {
>    struct cgraph_edge *e;
> -  ipa_fn_summary *callee_info = ipa_fn_summaries->get_create (node);
> -  ipa_fn_summary *caller_info
> -    = ipa_fn_summaries->get_create (node->callers->caller);
> +  ipa_fn_summary *callee_info = ipa_fn_summaries->get (node);
> +  ipa_fn_summary *caller_info = ipa_fn_summaries->get (node->callers->caller);
>    HOST_WIDE_INT peak;
>  
>    callee_info->stack_frame_offset
> @@ -2862,7 +2826,7 @@ inline_update_callee_summaries (struct cgraph_node *node, int depth)
>    peak = callee_info->stack_frame_offset
>      + callee_info->estimated_self_stack_size;
>  
> -  ipa_fn_summary *s = ipa_fn_summaries->get_create (node->global.inlined_to);
> +  ipa_fn_summary *s = ipa_fn_summaries->get (node->global.inlined_to);
>    if (s->estimated_stack_size < peak)
>      s->estimated_stack_size = peak;
>    ipa_propagate_frequency (node);
> @@ -2870,10 +2834,10 @@ inline_update_callee_summaries (struct cgraph_node *node, int depth)
>      {
>        if (!e->inline_failed)
>  	inline_update_callee_summaries (e->callee, depth);
> -      ipa_call_summaries->get_create (e)->loop_depth += depth;
> +      ipa_call_summaries->get (e)->loop_depth += depth;
>      }
>    for (e = node->indirect_calls; e; e = e->next_callee)
> -    ipa_call_summaries->get_create (e)->loop_depth += depth;
> +    ipa_call_summaries->get (e)->loop_depth += depth;
>  }
>  
>  /* Update change_prob of EDGE after INLINED_EDGE has been inlined.
> @@ -2890,9 +2854,9 @@ remap_edge_change_prob (struct cgraph_edge *inlined_edge,
>      {
>        int i;
>        struct ipa_edge_args *args = IPA_EDGE_REF (edge);
> -      struct ipa_call_summary *es = ipa_call_summaries->get_create (edge);
> +      struct ipa_call_summary *es = ipa_call_summaries->get (edge);
>        struct ipa_call_summary *inlined_es
> -	= ipa_call_summaries->get_create (inlined_edge);
> +	= ipa_call_summaries->get (inlined_edge);
>  
>        for (i = 0; i < ipa_get_cs_argument_count (args); i++)
>  	{
> @@ -2939,7 +2903,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
>    struct cgraph_edge *e, *next;
>    for (e = node->callees; e; e = next)
>      {
> -      struct ipa_call_summary *es = ipa_call_summaries->get_create (e);
> +      struct ipa_call_summary *es = ipa_call_summaries->get (e);
>        predicate p;
>        next = e->next_callee;
>  
> @@ -2965,7 +2929,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
>      }
>    for (e = node->indirect_calls; e; e = next)
>      {
> -      struct ipa_call_summary *es = ipa_call_summaries->get_create (e);
> +      struct ipa_call_summary *es = ipa_call_summaries->get (e);
>        predicate p;
>        next = e->next_callee;
>  
> @@ -3015,10 +2979,10 @@ remap_hint_predicate (struct ipa_fn_summary *info,
>  void
>  ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
>  {
> -  ipa_fn_summary *callee_info = ipa_fn_summaries->get_create (edge->callee);
> +  ipa_fn_summary *callee_info = ipa_fn_summaries->get (edge->callee);
>    struct cgraph_node *to = (edge->caller->global.inlined_to
>  			    ? edge->caller->global.inlined_to : edge->caller);
> -  struct ipa_fn_summary *info = ipa_fn_summaries->get_create (to);
> +  struct ipa_fn_summary *info = ipa_fn_summaries->get (to);
>    clause_t clause = 0;	/* not_inline is known to be false.  */
>    size_time_entry *e;
>    vec<int> operand_map = vNULL;
> @@ -3026,7 +2990,7 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
>    int i;
>    predicate toplev_predicate;
>    predicate true_p = true;
> -  struct ipa_call_summary *es = ipa_call_summaries->get_create (edge);
> +  struct ipa_call_summary *es = ipa_call_summaries->get (edge);
>  
>    if (es->predicate)
>      toplev_predicate = *es->predicate;
> @@ -3115,7 +3079,7 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
>  			&callee_info->array_index,
>  			operand_map, offset_map, clause, &toplev_predicate);
>  
> -  ipa_call_summary *s = ipa_call_summaries->get_create (edge);
> +  ipa_call_summary *s = ipa_call_summaries->get (edge);
>    inline_update_callee_summaries (edge->callee, s->loop_depth);
>  
>    /* We do not maintain predicates of inlined edges, free it.  */
> @@ -3390,7 +3354,7 @@ ipa_fn_summary_read (void)
>  static void
>  write_ipa_call_summary (struct output_block *ob, struct cgraph_edge *e)
>  {
> -  struct ipa_call_summary *es = ipa_call_summaries->get_create (e);
> +  struct ipa_call_summary *es = ipa_call_summaries->get (e);
>    int i;
>  
>    streamer_write_uhwi (ob, es->call_stmt_size);
> @@ -3438,7 +3402,7 @@ ipa_fn_summary_write (void)
>        cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
>        if (cnode && cnode->definition && !cnode->alias)
>  	{
> -	  struct ipa_fn_summary *info = ipa_fn_summaries->get_create (cnode);
> +	  struct ipa_fn_summary *info = ipa_fn_summaries->get (cnode);
>  	  struct bitpack_d bp;
>  	  struct cgraph_edge *edge;
>  	  int i;
> @@ -3513,7 +3477,7 @@ ipa_free_fn_summary (void)
>      return;
>    FOR_EACH_DEFINED_FUNCTION (node)
>      if (!node->alias)
> -      ipa_fn_summaries->get_create (node)->reset (node);
> +      ipa_fn_summaries->remove (node);
>    ipa_fn_summaries->release ();
>    ipa_fn_summaries = NULL;
>    ipa_call_summaries->release ();
> diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h
> index c2187510cb6..9e795944236 100644
> --- a/gcc/ipa-fnsummary.h
> +++ b/gcc/ipa-fnsummary.h
> @@ -87,6 +87,34 @@ struct GTY(()) size_time_entry
>  /* Function inlining information.  */
>  struct GTY(()) ipa_fn_summary
>  {
> +  /* Keep all field empty so summary dumping works during its computation.
> +     This is useful for debugging.  */
> +  ipa_fn_summary ()
> +    : estimated_self_stack_size (0), self_size (0), min_size (0),
> +      inlinable (false), single_caller (false),
> +      fp_expressions (false), estimated_stack_size (false),
> +      stack_frame_offset (false), time (0), size (0), conds (NULL),
> +      size_time_table (NULL), loop_iterations (NULL), loop_stride (NULL),
> +      array_index (NULL), growth (0), scc_no (0)
> +  {
> +  }
> +
> +  /* Copy constructor.  */
> +  ipa_fn_summary (const ipa_fn_summary &s)
> +    : estimated_self_stack_size (s.estimated_self_stack_size),
> +    self_size (s.self_size), min_size (s.min_size),
> +    inlinable (s.inlinable), single_caller (s.single_caller),
> +    fp_expressions (s.fp_expressions),
> +    estimated_stack_size (s.estimated_stack_size),
> +    stack_frame_offset (s.stack_frame_offset), time (s.time), size (s.size),
> +    conds (s.conds), size_time_table (s.size_time_table),
> +    loop_iterations (s.loop_iterations), loop_stride (s.loop_stride),
> +    array_index (s.array_index), growth (s.growth), scc_no (s.scc_no)
> +  {}
> +
> +  /* Default constructor.  */
> +  ~ipa_fn_summary ();
> +
>    /* Information about the function body itself.  */
>  
>    /* Estimated stack frame consumption by the function.  */
> @@ -138,24 +166,9 @@ struct GTY(()) ipa_fn_summary
>    /* Number of SCC on the beginning of inlining process.  */
>    int scc_no;
>  
> -  /* Keep all field empty so summary dumping works during its computation.
> -     This is useful for debugging.  */
> -  ipa_fn_summary ()
> -    : estimated_self_stack_size (0), self_size (0), min_size (0),
> -      inlinable (false), single_caller (false),
> -      fp_expressions (false), estimated_stack_size (false),
> -      stack_frame_offset (false), time (0), size (0), conds (NULL),
> -      size_time_table (NULL), loop_iterations (NULL), loop_stride (NULL),
> -      array_index (NULL), growth (0), scc_no (0)
> -    {
> -    }
> -
>    /* Record time and size under given predicates.  */
>    void account_size_time (int, sreal, const predicate &, const predicate &);
>  
> -  /* Reset summary to empty state.  */
> -  void reset (struct cgraph_node *node);
> -
>    /* We keep values scaled up, so fractional sizes can be accounted.  */
>    static const int size_scale = 2;
>  };
> @@ -174,9 +187,15 @@ public:
>      return summary;
>    }
>  
> +  /* Remove ipa_fn_summary for all callees of NODE.  */
> +  void remove_callees (cgraph_node *node);
>  
>    virtual void insert (cgraph_node *, ipa_fn_summary *);
> -  virtual void remove (cgraph_node *node, ipa_fn_summary *);
> +  virtual void remove (cgraph_node *node, ipa_fn_summary *)
> +  {
> +    remove_callees (node);
> +  }
> +
>    virtual void duplicate (cgraph_node *src, cgraph_node *dst,
>  			  ipa_fn_summary *src_data, ipa_fn_summary *dst_data);
>  };
> @@ -186,6 +205,25 @@ extern GTY(()) function_summary <ipa_fn_summary *> *ipa_fn_summaries;
>  /* Information kept about callgraph edges.  */
>  struct ipa_call_summary
>  {
> +  /* Keep all field empty so summary dumping works during its computation.
> +     This is useful for debugging.  */
> +  ipa_call_summary ()
> +    : predicate (NULL), param (vNULL), call_stmt_size (0), call_stmt_time (0),
> +      loop_depth (0), is_return_callee_uncaptured (false)
> +    {
> +    }
> +
> +  /* Copy constructor.  */
> +  ipa_call_summary (const ipa_call_summary &s):
> +    predicate (s.predicate), param (s.param), call_stmt_size (s.call_stmt_size),
> +    call_stmt_time (s.call_stmt_time), loop_depth (s.loop_depth),
> +    is_return_callee_uncaptured (s.is_return_callee_uncaptured)
> +  {
> +  }
> +
> +  /* Default destructor.  */
> +  ~ipa_call_summary ();
> +
>    class predicate *predicate;
>    /* Vector indexed by parameters.  */
>    vec<inline_param_summary> param;
> @@ -196,17 +234,6 @@ struct ipa_call_summary
>    unsigned int loop_depth;
>    /* Indicates whether the caller returns the value of it's callee.  */
>    bool is_return_callee_uncaptured;
> -
> -  /* Keep all field empty so summary dumping works during its computation.
> -     This is useful for debugging.  */
> -  ipa_call_summary ()
> -    : predicate (NULL), param (vNULL), call_stmt_size (0), call_stmt_time (0),
> -      loop_depth (0)
> -    {
> -    }
> -
> -  /* Reset inline summary to empty state.  */
> -  void reset ();
>  };
>  
>  class ipa_call_summary_t: public call_summary <ipa_call_summary *>
> @@ -215,8 +242,6 @@ public:
>    ipa_call_summary_t (symbol_table *symtab, bool ggc):
>      call_summary <ipa_call_summary *> (symtab, ggc) {}
>  
> -  /* Hook that is called by summary when an edge is duplicated.  */
> -  virtual void remove (cgraph_edge *cs, ipa_call_summary *);
>    /* Hook that is called by summary when an edge is duplicated.  */
>    virtual void duplicate (cgraph_edge *src, cgraph_edge *dst,
>  			  ipa_call_summary *src_data,
> diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
> index bededc3bbd5..90d1e17e5cd 100644
> --- a/gcc/ipa-icf.c
> +++ b/gcc/ipa-icf.c
> @@ -1199,7 +1199,8 @@ sem_function::merge (sem_item *alias_item)
>  		     "can not create wrapper of stdarg function.\n");
>  	}
>        else if (ipa_fn_summaries
> -	       && ipa_fn_summaries->get_create (alias)->self_size <= 2)
> +	       && ipa_fn_summaries->get (alias) != NULL
> +	       && ipa_fn_summaries->get (alias)->self_size <= 2)

Alias is the target we merge to. In what sictuation it can be unanalyzed?
> @@ -364,7 +364,8 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
>        e->inline_failed = CIF_TARGET_OPTION_MISMATCH;
>        inlinable = false;
>      }
> -  else if (!ipa_fn_summaries->get_create (callee)->inlinable)
> +  else if (ipa_fn_summaries->get (callee) == NULL
> +	   || !ipa_fn_summaries->get (callee)->inlinable)

Please add comment here that we can enounter not-yet-analyzed function during
early inlining on callgraphs with strongly connected components.
> @@ -2655,8 +2660,8 @@ early_inline_small_functions (struct cgraph_node *node)
>    for (e = node->callees; e; e = e->next_callee)
>      {
>        struct cgraph_node *callee = e->callee->ultimate_alias_target ();
> -      if (!ipa_fn_summaries->get_create (callee)->inlinable
> -	  || !e->inline_failed)
> +      ipa_fn_summary *s = ipa_fn_summaries->get (callee);
> +      if (s == NULL || !s->inlinable || !e->inline_failed)
>  	continue;

And here too :)
>  
>        /* Do not consider functions not declared inline.  */
> @@ -2790,11 +2795,14 @@ early_inliner (function *fun)
>  	  for (edge = node->callees; edge; edge = edge->next_callee)
>  	    {
>  	      /* We have no summary for new bound store calls yet.  */
> -	      ipa_call_summary *es = ipa_call_summaries->get_create (edge);
> -	      es->call_stmt_size
> -		= estimate_num_insns (edge->call_stmt, &eni_size_weights);
> -	      es->call_stmt_time
> -		= estimate_num_insns (edge->call_stmt, &eni_time_weights);
> +	      ipa_call_summary *es = ipa_call_summaries->get (edge);
> +	      if (es != NULL)
> +		{
> +		  es->call_stmt_size
> +		    = estimate_num_insns (edge->call_stmt, &eni_size_weights);
> +		  es->call_stmt_time
> +		    = estimate_num_insns (edge->call_stmt, &eni_time_weights);
> +		}

This loop should add missing summaries (as comment explains) so you want to use get_create.

Honza



More information about the Gcc-patches mailing list