This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH 1/N] Clean-up usage of ipa_fn_summary and ipa_call_summary summaries.
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: Martin Liška <mliska at suse dot cz>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 15 Jun 2018 17:05:48 +0200
- Subject: Re: [PATCH 1/N] Clean-up usage of ipa_fn_summary and ipa_call_summary summaries.
- References: <1263dd85-811b-94d2-f769-b702ce2ba0da@suse.cz>
> 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