+2018-06-19 Martin Liska <mliska@suse.cz>
+
+ * config/i386/i386.c (ix86_can_inline_p): Do not use
+ ipa_fn_summaries::get_create.
+ * ipa-cp.c (ipcp_cloning_candidate_p): Replace get_create with
+ get.
+ (devirtualization_time_bonus): Likewise.
+ (ipcp_propagate_stage): Likewise.
+ * ipa-fnsummary.c (redirect_to_unreachable): Likewise.
+ (edge_set_predicate): Likewise.
+ (evaluate_conditions_for_known_args): Likewise.
+ (evaluate_properties_for_edge): Likewise.
+ (ipa_call_summary::reset): Tranform to ...
+ (ipa_call_summary::~ipa_call_summary): ... this.
+ (ipa_fn_summary::reset): Transform to ...
+ (ipa_fn_summary::~ipa_fn_summary): ... this.
+ (ipa_fn_summary_t::remove): Rename to ...
+ (ipa_fn_summary_t::remove_callees): ... this.
+ (ipa_fn_summary_t::duplicate): Use placement new
+ instead of memory copy.
+ (ipa_call_summary_t::duplicate): Likewise.
+ (ipa_call_summary_t::remove): Remove.
+ (dump_ipa_call_summary): Change get_create to get.
+ (ipa_dump_fn_summary): Dump only when summary exists.
+ (analyze_function_body): Use symbol_summary::get instead
+ of get_create.
+ (compute_fn_summary): Likewise.
+ (estimate_edge_devirt_benefit): Likewise.
+ (estimate_edge_size_and_time): Likewise.
+ (inline_update_callee_summaries): Likewise.
+ (remap_edge_change_prob): Likewise.
+ (remap_edge_summaries): Likewise.
+ (ipa_merge_fn_summary_after_inlining): Likewise.
+ (write_ipa_call_summary): Likewise.
+ (ipa_fn_summary_write): Likewise.
+ (ipa_free_fn_summary): Likewise.
+ * ipa-fnsummary.h (struct GTY): Add new ctor and copy ctor.
+ (struct ipa_call_summary): Likewise.
+ * ipa-icf.c (sem_function::merge): Use symbol_summary::get instead
+ of get_create.
+ * ipa-inline-analysis.c (do_estimate_edge_time): Likewise.
+ (estimate_size_after_inlining): Likewise.
+ (estimate_growth): Likewise.
+ (growth_likely_positive): Likewise.
+ * ipa-inline-transform.c (clone_inlined_nodes): Likewise.
+ (inline_call): Likewise.
+ * ipa-inline.c (caller_growth_limits): Likewise.
+ (can_inline_edge_p): Likewise.
+ (can_inline_edge_by_limits_p): Likewise.
+ (compute_uninlined_call_time): Likewise.
+ (compute_inlined_call_time): Likewise.
+ (want_inline_small_function_p): Likewise.
+ (edge_badness): Likewise.
+ (update_caller_keys): Likewise.
+ (update_callee_keys): Likewise.
+ (inline_small_functions): Likewise.
+ (inline_to_all_callers_1): Likewise.
+ (dump_overall_stats): Likewise.
+ (early_inline_small_functions): Likewise.
+ (early_inliner): Likewise.
+ * ipa-profile.c (ipa_propagate_frequency_1): Likewise.
+ * ipa-prop.c (ipa_make_edge_direct_to_target): Likewise.
+ * ipa-pure-const.c (malloc_candidate_p): Likewise.
+ * ipa-split.c (execute_split_functions): Likewise.
+ * symbol-summary.h: Likewise.
+ * tree-sra.c (ipa_sra_preliminary_function_checks): Likewise.
+
2018-06-19 Richard Biener <rguenther@suse.de>
* tree-vectorizer.c (try_vectorize_loop_1): Split out of ...
&& 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. */
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
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",
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;
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;
max_count = max_count.max (node->count.ipa ());
}
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;
&& (!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)
{
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;
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;
{
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)
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.
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);
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 ();
}
}
-
-/* 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. */
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)
{
}
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, "",
{
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 ());
}
}
}
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 ();
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 ();
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
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;
}
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;
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
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);
{
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.
{
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++)
{
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;
}
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;
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;
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;
&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. */
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);
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;
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 ();
/* 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. */
/* 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;
};
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);
};
/* 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;
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 *>
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,
"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)
{
if (dump_file)
fprintf (dump_file, "Wrapper creation is not "
vec<tree> known_vals;
vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function_p> known_aggs;
- struct ipa_call_summary *es = ipa_call_summaries->get_create (edge);
+ struct ipa_call_summary *es = ipa_call_summaries->get (edge);
int min_size;
callee = edge->callee->ultimate_alias_target ();
estimate_size_after_inlining (struct cgraph_node *node,
struct cgraph_edge *edge)
{
- struct ipa_call_summary *es = ipa_call_summaries->get_create (edge);
- ipa_fn_summary *s = ipa_fn_summaries->get_create (node);
+ struct ipa_call_summary *es = ipa_call_summaries->get (edge);
+ ipa_fn_summary *s = ipa_fn_summaries->get (node);
if (!es->predicate || *es->predicate != false)
{
int size = s->size + estimate_edge_growth (edge);
estimate_growth (struct cgraph_node *node)
{
struct growth_data d = { node, false, false, 0 };
- struct ipa_fn_summary *info = ipa_fn_summaries->get_create (node);
+ struct ipa_fn_summary *info = ipa_fn_summaries->get (node);
node->call_for_symbol_and_aliases (do_estimate_growth_1, &d, true);
|| node->address_taken)
return true;
- max_callers = ipa_fn_summaries->get_create (node)->size * 4 / edge_growth + 2;
+ max_callers = ipa_fn_summaries->get (node)->size * 4 / edge_growth + 2;
for (e = node->callers; e; e = e->next_caller)
{
{
gcc_assert (!e->callee->alias);
if (overall_size)
- *overall_size -= ipa_fn_summaries->get_create (e->callee)->size;
+ *overall_size -= ipa_fn_summaries->get (e->callee)->size;
nfunctions_inlined++;
}
duplicate = false;
reload_optimization_node = true;
}
- ipa_fn_summary *caller_info = ipa_fn_summaries->get_create (to);
- ipa_fn_summary *callee_info = ipa_fn_summaries->get_create (callee);
+ ipa_fn_summary *caller_info = ipa_fn_summaries->get (to);
+ ipa_fn_summary *callee_info = ipa_fn_summaries->get (callee);
if (!caller_info->fp_expressions && callee_info->fp_expressions)
{
caller_info->fp_expressions = true;
gcc_assert (curr->callee->global.inlined_to == to);
- old_size = ipa_fn_summaries->get_create (to)->size;
+ old_size = ipa_fn_summaries->get (to)->size;
ipa_merge_fn_summary_after_inlining (e);
if (e->in_polymorphic_cdtor)
mark_all_inlined_calls_cdtor (e->callee);
work for further inlining into this function. Before inlining
the function we inlined to again we expect the caller to update
the overall summary. */
- ipa_fn_summaries->get_create (to)->size += estimated_growth;
- new_size = ipa_fn_summaries->get_create (to)->size;
+ ipa_fn_summaries->get (to)->size += estimated_growth;
+ new_size = ipa_fn_summaries->get (to)->size;
if (callee->calls_comdat_local)
to->calls_comdat_local = true;
int limit = 0;
HOST_WIDE_INT stack_size_limit = 0, inlined_stack;
ipa_fn_summary *info, *what_info;
- ipa_fn_summary *outer_info = ipa_fn_summaries->get_create (to);
+ ipa_fn_summary *outer_info = ipa_fn_summaries->get (to);
/* Look for function e->caller is inlined to. While doing
so work out the largest function body on the way. As
too much in order to prevent compiler from exploding". */
while (true)
{
- info = ipa_fn_summaries->get_create (to);
+ info = ipa_fn_summaries->get (to);
if (limit < info->self_size)
limit = info->self_size;
if (stack_size_limit < info->estimated_self_stack_size)
break;
}
- what_info = ipa_fn_summaries->get_create (what);
+ what_info = ipa_fn_summaries->get (what);
if (limit < what_info->self_size)
limit = what_info->self_size;
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)
{
e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
inlinable = false;
(DECL_DISREGARD_INLINE_LIMITS (callee->decl)
&& lookup_attribute ("always_inline",
DECL_ATTRIBUTES (callee->decl)));
- ipa_fn_summary *caller_info = ipa_fn_summaries->get_create (caller);
- ipa_fn_summary *callee_info = ipa_fn_summaries->get_create (callee);
+ ipa_fn_summary *caller_info = ipa_fn_summaries->get (caller);
+ ipa_fn_summary *callee_info = ipa_fn_summaries->get (callee);
/* Until GCC 4.9 we did not check the semantics alterning flags
bellow and inline across optimization boundry.
> opt_for_fn (caller->decl, optimize)))
{
if (estimate_edge_time (e)
- >= 20 + ipa_call_summaries->get_create (e)->call_stmt_time)
+ >= 20 + ipa_call_summaries->get (e)->call_stmt_time)
{
e->inline_failed = CIF_OPTIMIZATION_MISMATCH;
inlinable = false;
else
uninlined_call_time = uninlined_call_time >> 11;
- sreal caller_time = ipa_fn_summaries->get_create (caller)->time;
+ sreal caller_time = ipa_fn_summaries->get (caller)->time;
return uninlined_call_time + caller_time;
}
cgraph_node *caller = (edge->caller->global.inlined_to
? edge->caller->global.inlined_to
: edge->caller);
- sreal caller_time = ipa_fn_summaries->get_create (caller)->time;
+ sreal caller_time = ipa_fn_summaries->get (caller)->time;
sreal freq = edge->sreal_frequency ();
if (freq > 0)
/* This calculation should match one in ipa-inline-analysis.c
(estimate_edge_size_and_time). */
- time -= (sreal)ipa_call_summaries->get_create (edge)->call_stmt_time * freq;
+ time -= (sreal)ipa_call_summaries->get (edge)->call_stmt_time * freq;
time += caller_time;
if (time <= 0)
time = ((sreal) 1) >> 8;
MAX_INLINE_INSNS_SINGLE 16-fold for inline functions. */
else if ((!DECL_DECLARED_INLINE_P (callee->decl)
&& (!e->count.ipa ().initialized_p () || !e->maybe_hot_p ()))
- && ipa_fn_summaries->get_create (callee)->min_size
- - ipa_call_summaries->get_create (e)->call_stmt_size
+ && ipa_fn_summaries->get (callee)->min_size
+ - ipa_call_summaries->get (e)->call_stmt_size
> MAX (MAX_INLINE_INSNS_SINGLE, MAX_INLINE_INSNS_AUTO))
{
e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
}
else if ((DECL_DECLARED_INLINE_P (callee->decl)
|| e->count.ipa ().nonzero_p ())
- && ipa_fn_summaries->get_create (callee)->min_size
- - ipa_call_summaries->get_create (e)->call_stmt_size
+ && ipa_fn_summaries->get (callee)->min_size
+ - ipa_call_summaries->get (e)->call_stmt_size
> 16 * MAX_INLINE_INSNS_SINGLE)
{
e->inline_failed = (DECL_DECLARED_INLINE_P (callee->decl)
int growth;
sreal edge_time, unspec_edge_time;
struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
- struct ipa_fn_summary *callee_info = ipa_fn_summaries->get_create (callee);
+ struct ipa_fn_summary *callee_info = ipa_fn_summaries->get (callee);
ipa_hints hints;
cgraph_node *caller = (edge->caller->global.inlined_to
? edge->caller->global.inlined_to
&& (!DECL_DECLARED_INLINE_P (edge->callee->decl)
|| DECL_DECLARED_INLINE_P (caller->decl)))))
{
- ipa_fn_summary *caller_info = ipa_fn_summaries->get_create (caller);
+ ipa_fn_summary *caller_info = ipa_fn_summaries->get (caller);
int caller_growth = caller_info->growth;
/* Only apply the penalty when caller looks like inline candidate,
of functions fully inlined in program. */
else
{
- int nest = MIN (ipa_call_summaries->get_create (edge)->loop_depth, 8);
+ int nest = MIN (ipa_call_summaries->get (edge)->loop_depth, 8);
badness = growth;
/* Decrease badness if call is nested. */
struct cgraph_edge *edge;
struct ipa_ref *ref;
- if ((!node->alias && !ipa_fn_summaries->get_create (node)->inlinable)
+ if ((!node->alias && !ipa_fn_summaries->get (node)->inlinable)
|| node->global.inlined_to)
return;
if (!bitmap_set_bit (updated_nodes, node->get_uid ()))
don't need updating. */
if (e->inline_failed
&& (callee = e->callee->ultimate_alias_target (&avail, e->caller))
- && ipa_fn_summaries->get_create (callee)->inlinable
+ && ipa_fn_summaries->get (callee) != NULL
+ && ipa_fn_summaries->get (callee)->inlinable
&& avail >= AVAIL_AVAILABLE
&& !bitmap_bit_p (updated_nodes, callee->get_uid ()))
{
&& (node->has_gimple_body_p () || node->thunk.thunk_p)
&& opt_for_fn (node->decl, optimize))
{
- struct ipa_fn_summary *info = ipa_fn_summaries->get_create (node);
+ struct ipa_fn_summary *info = ipa_fn_summaries->get (node);
struct ipa_dfs_info *dfs = (struct ipa_dfs_info *) node->aux;
/* Do not account external functions, they will be optimized out
n2 = ((struct ipa_dfs_info *) n2->aux)->next_cycle)
if (opt_for_fn (n2->decl, optimize))
{
- ipa_fn_summary *info2 = ipa_fn_summaries->get_create (n2);
+ ipa_fn_summary *info2 = ipa_fn_summaries->get (n2);
if (info2->scc_no)
break;
info2->scc_no = id;
fprintf (dump_file,
"\nConsidering %s with %i size\n",
callee->dump_name (),
- ipa_fn_summaries->get_create (callee)->size);
+ ipa_fn_summaries->get (callee)->size);
fprintf (dump_file,
" to be inlined into %s in %s:%i\n"
" Estimated badness is %f, frequency %.2f.\n",
if (dump_file)
{
- ipa_fn_summary *s = ipa_fn_summaries->get_create (edge->caller);
+ ipa_fn_summary *s = ipa_fn_summaries->get (edge->caller);
fprintf (dump_file,
" Inlined %s into %s which now has time %f and size %i, "
"net change of %+i.\n",
fprintf (dump_file,
"\nInlining %s size %i.\n",
node->name (),
- ipa_fn_summaries->get_create (node)->size);
+ ipa_fn_summaries->get (node)->size);
fprintf (dump_file,
" Called once from %s %i insns.\n",
node->callers->caller->name (),
- ipa_fn_summaries->get_create (node->callers->caller)->size);
+ ipa_fn_summaries->get (node->callers->caller)->size);
}
/* Remember which callers we inlined to, delaying updating the
fprintf (dump_file,
" Inlined into %s which now has %i size\n",
caller->name (),
- ipa_fn_summaries->get_create (caller)->size);
+ ipa_fn_summaries->get (caller)->size);
if (!(*num_calls)--)
{
if (dump_file)
if (!node->global.inlined_to
&& !node->alias)
{
- sreal time = ipa_fn_summaries->get_create (node)->time;
- sum += time;
- if (node->count.ipa ().initialized_p ())
- sum_weighted += time * node->count.ipa ().to_gcov_type ();
+ ipa_fn_summary *s = ipa_fn_summaries->get (node);
+ if (s != NULL)
+ {
+ sum += s->time;
+ if (node->count.ipa ().initialized_p ())
+ sum_weighted += s->time * node->count.ipa ().to_gcov_type ();
+ }
}
fprintf (dump_file, "Overall time estimate: "
"%f weighted by profile: "
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)
+
+ /* We can enounter not-yet-analyzed function during
+ early inlining on callgraphs with strongly
+ connected components. */
+ ipa_fn_summary *s = ipa_fn_summaries->get (callee);
+ if (s == NULL || !s->inlinable || !e->inline_failed)
continue;
/* Do not consider functions not declared inline. */
statements that don't have inline parameters computed. */
for (edge = node->callees; edge; edge = edge->next_callee)
{
+ /* We can enounter not-yet-analyzed function during
+ early inlining on callgraphs with strongly
+ connected components. */
ipa_call_summary *es = ipa_call_summaries->get_create (edge);
es->call_stmt_size
= estimate_num_insns (edge->call_stmt, &eni_size_weights);
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);
+ }
if (edge->callee->decl
&& !gimple_check_call_matching_types (
case NODE_FREQUENCY_UNLIKELY_EXECUTED:
break;
case NODE_FREQUENCY_EXECUTED_ONCE:
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Called by %s that is executed once\n",
- edge->caller->name ());
- d->maybe_unlikely_executed = false;
- if (ipa_call_summaries->get_create (edge)->loop_depth)
- {
- d->maybe_executed_once = false;
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Called in loop\n");
- }
- break;
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " Called by %s that is executed once\n",
+ edge->caller->name ());
+ d->maybe_unlikely_executed = false;
+ ipa_call_summary *s = ipa_call_summaries->get (edge);
+ if (s != NULL && s->loop_depth)
+ {
+ d->maybe_executed_once = false;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " Called in loop\n");
+ }
+ break;
+ }
case NODE_FREQUENCY_HOT:
case NODE_FREQUENCY_NORMAL:
if (dump_file && (dump_flags & TDF_DETAILS))
bool speculative)
{
struct cgraph_node *callee;
- struct ipa_call_summary *es = ipa_call_summaries->get_create (ie);
bool unreachable = false;
if (TREE_CODE (target) == ADDR_EXPR)
for direct call (adjusted by inline_edge_duplication_hook). */
if (ie == orig)
{
- es = ipa_call_summaries->get_create (ie);
+ ipa_call_summary *es = ipa_call_summaries->get (ie);
es->call_stmt_size -= (eni_size_weights.indirect_call_cost
- eni_size_weights.call_cost);
es->call_stmt_time -= (eni_time_weights.indirect_call_cost
cgraph_edge *cs = node->get_edge (call_stmt);
if (cs)
{
- ipa_call_summary *es = ipa_call_summaries->get_create (cs);
+ ipa_call_summary *es = ipa_call_summaries->get (cs);
gcc_assert (es);
es->is_return_callee_uncaptured = true;
}
cgraph_edge *cs = node->get_edge (call_stmt);
if (cs)
{
- ipa_call_summary *es = ipa_call_summaries->get_create (cs);
+ ipa_call_summary *es = ipa_call_summaries->get (cs);
gcc_assert (es);
es->is_return_callee_uncaptured = true;
}
/* This can be relaxed; function might become inlinable after splitting
away the uninlinable part. */
if (ipa_fn_summaries
- && !ipa_fn_summaries->get_create (node)->inlinable)
+ && ipa_fn_summaries->get (node)
+ && !ipa_fn_summaries->get (node)->inlinable)
{
if (dump_file)
fprintf (dump_file, "Not splitting: not inlinable.\n");
+2018-06-19 Martin Liska <mliska@suse.cz>
+
+ * lto-partition.c (add_symbol_to_partition_1): Use symbol_summary::get instead
+ of get_create.
+ (undo_partition): Likewise.
+ (lto_balanced_map): Likewise.
+
2018-06-19 Martin Liska <mliska@suse.cz>
* config-lang.in: Remove stagestuff.
{
struct cgraph_edge *e;
if (!node->alias && c == SYMBOL_PARTITION)
- part->insns += ipa_fn_summaries->get_create (cnode)->size;
+ part->insns += ipa_fn_summaries->get (cnode)->size;
/* Add all inline clones and callees that are duplicated. */
for (e = cnode->callees; e; e = e->next_callee)
if (!node->alias && (cnode = dyn_cast <cgraph_node *> (node))
&& node->get_partitioning_class () == SYMBOL_PARTITION)
- partition->insns -= ipa_fn_summaries->get_create (cnode)->size;
+ partition->insns -= ipa_fn_summaries->get (cnode)->size;
lto_symtab_encoder_delete_node (partition->encoder, node);
node->aux = (void *)((size_t)node->aux - 1);
}
else
order.safe_push (node);
if (!node->alias)
- total_size += ipa_fn_summaries->get_create (node)->size;
+ total_size += ipa_fn_summaries->get (node)->size;
}
original_total_size = total_size;
return get (node->get_uid (), false);
}
+ /* Remove node from summary. */
+ void remove (cgraph_node *node)
+ {
+ int uid = node->get_uid ();
+ T **v = m_map.get (uid);
+ if (v)
+ {
+ m_map.remove (uid);
+ release (*v);
+ }
+ }
+
/* Return number of elements handled by data structure. */
size_t elements ()
{
}
if ((DECL_ONE_ONLY (node->decl) || DECL_EXTERNAL (node->decl))
- && ipa_fn_summaries->get_create (node)->size >= MAX_INLINE_INSNS_AUTO)
+ && ipa_fn_summaries->get (node)
+ && ipa_fn_summaries->get (node)->size >= MAX_INLINE_INSNS_AUTO)
{
if (dump_file)
fprintf (dump_file, "Function too big to be made truly local.\n");