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 <[email protected]>
>>
>> * 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
>