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