On 06/15/2018 05:05 PM, Jan Hubicka wrote: >> 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...
Hello. ICEs on: $ cat ice.ii #pragma GCC optimize 0 int main() {} $ ./xgcc -B. -O2 ice.ii during IPA pass: cp ice.ii:2:13: internal compiler error: Segmentation fault int main() {} ^ 0xdbb6bf crash_signal /home/marxin/Programming/gcc/gcc/toplev.c:324 0x7ffff6d8ba6f ??? /usr/src/debug/glibc-2.27-5.1.x86_64/signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0 0x15edd82 ipcp_propagate_stage /home/marxin/Programming/gcc/gcc/ipa-cp.c:3292 0x15f049a ipcp_driver /home/marxin/Programming/gcc/gcc/ipa-cp.c:5081 0x15f049a execute /home/marxin/Programming/gcc/gcc/ipa-cp.c:5172 >> 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? Can't that also ICE for similar reason as IPA CP? >> @@ -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. Will do. >> @@ -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 :) Will do. Martin >> >> /* 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 >