Commit b0d55476 by Jan Hubicka Committed by Jan Hubicka

ipa-fnsummary.c (evaluate_conditions_for_known_args): Be ready for some vectors…

ipa-fnsummary.c (evaluate_conditions_for_known_args): Be ready for some vectors to not be allocated.


	* ipa-fnsummary.c (evaluate_conditions_for_known_args): Be
	ready for some vectors to not be allocated.
	(evaluate_properties_for_edge): Document better; make
	known_vals and known_aggs caller allocated; avoid determining
	values of parameters which are not used.
	(ipa_merge_fn_summary_after_inlining): Pre allocate known_vals and
	known_aggs.
	* ipa-inline-analysis.c (do_estimate_edge_time): Likewise.
	(do_estimate_edge_size): Likewise.
	(do_estimate_edge_hints): Likewise.
	* ipa-cp.c (ipa_get_indirect_edge_target_1): Do not early exit when
	values are not known.
	(ipa_release_agg_values): Add option to not release vector itself.

From-SVN: r278553
parent 48ffab98
2019-11-21 Jan Hubicka <jh@suse.cz>
* ipa-fnsummary.c (evaluate_conditions_for_known_args): Be
ready for some vectors to not be allocated.
(evaluate_properties_for_edge): Document better; make
known_vals and known_aggs caller allocated; avoid determining
values of parameters which are not used.
(ipa_merge_fn_summary_after_inlining): Pre allocate known_vals and
known_aggs.
* ipa-inline-analysis.c (do_estimate_edge_time): Likewise.
(do_estimate_edge_size): Likewise.
(do_estimate_edge_hints): Likewise.
* ipa-cp.c (ipa_get_indirect_edge_target_1): Do not early exit when
values are not known.
(ipa_release_agg_values): Add option to not release vector itself.
2019-11-21 Richard Biener <rguenther@suse.de> 2019-11-21 Richard Biener <rguenther@suse.de>
* cfgloop.h (loop_iterator::~loop_iterator): Remove. * cfgloop.h (loop_iterator::~loop_iterator): Remove.
...@@ -2744,18 +2744,17 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, ...@@ -2744,18 +2744,17 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
{ {
int param_index = ie->indirect_info->param_index; int param_index = ie->indirect_info->param_index;
HOST_WIDE_INT anc_offset; HOST_WIDE_INT anc_offset;
tree t; tree t = NULL;
tree target = NULL; tree target = NULL;
*speculative = false; *speculative = false;
if (param_index == -1 if (param_index == -1)
|| known_csts.length () <= (unsigned int) param_index)
return NULL_TREE; return NULL_TREE;
if (!ie->indirect_info->polymorphic) if (!ie->indirect_info->polymorphic)
{ {
tree t; tree t = NULL;
if (ie->indirect_info->agg_contents) if (ie->indirect_info->agg_contents)
{ {
...@@ -2782,7 +2781,11 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, ...@@ -2782,7 +2781,11 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
else else
agg = NULL; agg = NULL;
bool from_global_constant; bool from_global_constant;
t = ipa_find_agg_cst_for_param (agg, known_csts[param_index], t = ipa_find_agg_cst_for_param (agg,
(unsigned) param_index
< known_csts.length ()
? known_csts[param_index]
: NULL,
ie->indirect_info->offset, ie->indirect_info->offset,
ie->indirect_info->by_ref, ie->indirect_info->by_ref,
&from_global_constant); &from_global_constant);
...@@ -2792,7 +2795,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, ...@@ -2792,7 +2795,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
t = NULL_TREE; t = NULL_TREE;
} }
} }
else else if ((unsigned) param_index < known_csts.length ())
t = known_csts[param_index]; t = known_csts[param_index];
if (t if (t
...@@ -2833,7 +2836,10 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, ...@@ -2833,7 +2836,10 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
&& !ie->indirect_info->by_ref) && !ie->indirect_info->by_ref)
{ {
struct ipa_agg_value_set *agg = &known_aggs[param_index]; struct ipa_agg_value_set *agg = &known_aggs[param_index];
t = ipa_find_agg_cst_for_param (agg, known_csts[param_index], t = ipa_find_agg_cst_for_param (agg,
(unsigned) param_index
< known_csts.length ()
? known_csts[param_index] : NULL,
ie->indirect_info->offset, true); ie->indirect_info->offset, true);
} }
...@@ -2867,7 +2873,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, ...@@ -2867,7 +2873,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
} }
/* Do we know the constant value of pointer? */ /* Do we know the constant value of pointer? */
if (!t) if (!t && (unsigned) param_index < known_csts.length ())
t = known_csts[param_index]; t = known_csts[param_index];
gcc_checking_assert (!t || TREE_CODE (t) != TREE_BINFO); gcc_checking_assert (!t || TREE_CODE (t) != TREE_BINFO);
......
...@@ -342,7 +342,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -342,7 +342,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
for (i = 0; vec_safe_iterate (info->conds, i, &c); i++) for (i = 0; vec_safe_iterate (info->conds, i, &c); i++)
{ {
tree val; tree val = NULL;
tree res; tree res;
int j; int j;
struct expr_eval_op *op; struct expr_eval_op *op;
...@@ -351,14 +351,8 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -351,14 +351,8 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
(especially for K&R style programs). So bound check here (we assume (especially for K&R style programs). So bound check here (we assume
known_aggs vector, if non-NULL, has the same length as known_aggs vector, if non-NULL, has the same length as
known_vals). */ known_vals). */
gcc_checking_assert (!known_aggs.exists () gcc_checking_assert (!known_aggs.length () || !known_vals.length ()
|| (known_vals.length () == known_aggs.length ())); || (known_vals.length () == known_aggs.length ()));
if (c->operand_num >= (int) known_vals.length ())
{
clause |= 1 << (i + predicate::first_dynamic_condition);
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
continue;
}
if (c->agg_contents) if (c->agg_contents)
{ {
...@@ -366,19 +360,24 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -366,19 +360,24 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
if (c->code == predicate::changed if (c->code == predicate::changed
&& !c->by_ref && !c->by_ref
&& c->operand_num < (int)known_vals.length ()
&& (known_vals[c->operand_num] == error_mark_node)) && (known_vals[c->operand_num] == error_mark_node))
continue; continue;
if (known_aggs.exists ()) if (c->operand_num < (int)known_aggs.length ())
{ {
agg = &known_aggs[c->operand_num]; agg = &known_aggs[c->operand_num];
val = ipa_find_agg_cst_for_param (agg, known_vals[c->operand_num], val = ipa_find_agg_cst_for_param (agg,
c->operand_num
< (int) known_vals.length ()
? known_vals[c->operand_num]
: NULL,
c->offset, c->by_ref); c->offset, c->by_ref);
} }
else else
val = NULL_TREE; val = NULL_TREE;
} }
else else if (c->operand_num < (int) known_vals.length ())
{ {
val = known_vals[c->operand_num]; val = known_vals[c->operand_num];
if (val == error_mark_node && c->code != predicate::changed) if (val == error_mark_node && c->code != predicate::changed)
...@@ -504,7 +503,18 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -504,7 +503,18 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
} }
/* Work out what conditions might be true at invocation of E. */ /* Work out what conditions might be true at invocation of E.
Compute costs for inlined edge if INLINE_P is true.
Return in CLAUSE_PTR the evaluated condistions and in NONSPEC_CLAUSE_PTR
(if non-NULL) conditions evaluated for nonspecialized clone called
in a given context.
KNOWN_VALS_PTR and KNOWN_AGGS_PTR must be non-NULL and will be filled by
known canstant and aggregate values of parameters.
KNOWN_CONTEXT_PTR, if non-NULL, will be filled by polymorphic call contexts
of parameter used by a polymorphic call. */
void void
evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
...@@ -517,113 +527,141 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -517,113 +527,141 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
{ {
struct cgraph_node *callee = e->callee->ultimate_alias_target (); struct cgraph_node *callee = e->callee->ultimate_alias_target ();
class ipa_fn_summary *info = ipa_fn_summaries->get (callee); class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
vec<tree> known_vals = vNULL;
auto_vec<value_range, 32> known_value_ranges; auto_vec<value_range, 32> known_value_ranges;
vec<ipa_agg_value_set> known_aggs = vNULL;
class ipa_edge_args *args; class ipa_edge_args *args;
if (clause_ptr) if (clause_ptr)
*clause_ptr = inline_p ? 0 : 1 << predicate::not_inlined_condition; *clause_ptr = inline_p ? 0 : 1 << predicate::not_inlined_condition;
if (known_vals_ptr)
known_vals_ptr->create (0);
if (known_contexts_ptr)
known_contexts_ptr->create (0);
if (ipa_node_params_sum if (ipa_node_params_sum
&& !e->call_stmt_cannot_inline_p && !e->call_stmt_cannot_inline_p
&& ((clause_ptr && info->conds) || known_vals_ptr || known_contexts_ptr) && (info->conds || known_contexts_ptr)
&& (args = IPA_EDGE_REF (e)) != NULL) && (args = IPA_EDGE_REF (e)) != NULL)
{ {
struct cgraph_node *caller; struct cgraph_node *caller;
class ipa_node_params *caller_parms_info, *callee_pi; class ipa_node_params *caller_parms_info, *callee_pi = NULL;
class ipa_call_summary *es = ipa_call_summaries->get (e); class ipa_call_summary *es = ipa_call_summaries->get (e);
int i, count = ipa_get_cs_argument_count (args); int i, count = ipa_get_cs_argument_count (args);
if (e->caller->inlined_to) if (count)
caller = e->caller->inlined_to; {
else if (e->caller->inlined_to)
caller = e->caller; caller = e->caller->inlined_to;
caller_parms_info = IPA_NODE_REF (caller); else
callee_pi = IPA_NODE_REF (callee); caller = e->caller;
caller_parms_info = IPA_NODE_REF (caller);
if (count && (info->conds || known_vals_ptr)) callee_pi = IPA_NODE_REF (callee);
known_vals.safe_grow_cleared (count);
if (count && info->conds) /* Watch for thunks. */
known_value_ranges.safe_grow_cleared (count); if (callee_pi)
if (count && (info->conds || known_aggs_ptr)) /* Watch for variadic functions. */
known_aggs.safe_grow_cleared (count); count = MIN (count, ipa_get_param_count (callee_pi));
if (count && known_contexts_ptr) }
known_contexts_ptr->safe_grow_cleared (count);
if (callee_pi) if (callee_pi)
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i); struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i);
tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
ipa_get_type (callee_pi, i));
if (!cst && e->call_stmt if (ipa_is_param_used_by_indirect_call (callee_pi, i)
&& i < (int)gimple_call_num_args (e->call_stmt)) || ipa_is_param_used_by_ipa_predicates (callee_pi, i))
{ {
cst = gimple_call_arg (e->call_stmt, i); /* Determine if we know constant value of the parameter. */
if (!is_gimple_min_invariant (cst)) tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
cst = NULL; ipa_get_type (callee_pi, i));
if (!cst && e->call_stmt
&& i < (int)gimple_call_num_args (e->call_stmt))
{
cst = gimple_call_arg (e->call_stmt, i);
if (!is_gimple_min_invariant (cst))
cst = NULL;
}
if (cst)
{
gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO);
if (!known_vals_ptr->length ())
vec_safe_grow_cleared (known_vals_ptr, count);
(*known_vals_ptr)[i] = cst;
}
else if (inline_p && !es->param[i].change_prob)
{
if (!known_vals_ptr->length ())
vec_safe_grow_cleared (known_vals_ptr, count);
(*known_vals_ptr)[i] = error_mark_node;
}
/* If we failed to get simple constant, try value range. */
if ((!cst || TREE_CODE (cst) != INTEGER_CST)
&& ipa_is_param_used_by_ipa_predicates (callee_pi, i))
{
value_range vr
= ipa_value_range_from_jfunc (caller_parms_info, e, jf,
ipa_get_type (callee_pi,
i));
if (!vr.undefined_p () && !vr.varying_p ())
{
if (!known_value_ranges.length ())
known_value_ranges.safe_grow_cleared (count);
known_value_ranges[i] = vr;
}
}
/* Determine known aggregate values. */
ipa_agg_value_set agg
= ipa_agg_value_set_from_jfunc (caller_parms_info,
caller, &jf->agg);
if (agg.items.length ())
{
if (!known_aggs_ptr->length ())
vec_safe_grow_cleared (known_aggs_ptr, count);
(*known_aggs_ptr)[i] = agg;
}
} }
if (cst)
/* For calls used in polymorphic calls we further determine
polymorphic call context. */
if (known_contexts_ptr
&& ipa_is_param_used_by_polymorphic_call (callee_pi, i))
{ {
gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO); ipa_polymorphic_call_context
if (known_vals.exists ()) ctx = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
known_vals[i] = cst; if (!ctx.useless_p ())
} {
else if (inline_p && !es->param[i].change_prob) if (!known_contexts_ptr->length ())
known_vals[i] = error_mark_node; known_contexts_ptr->safe_grow_cleared (count);
(*known_contexts_ptr)[i]
if (known_contexts_ptr) = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
(*known_contexts_ptr)[i] }
= ipa_context_from_jfunc (caller_parms_info, e, i, jf); }
known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info,
caller, &jf->agg);
if (info->conds)
known_value_ranges[i]
= ipa_value_range_from_jfunc (caller_parms_info, e, jf,
ipa_get_type (callee_pi, i));
} }
else else
gcc_assert (callee->thunk.thunk_p); gcc_assert (!count || callee->thunk.thunk_p);
} }
else if (e->call_stmt && !e->call_stmt_cannot_inline_p else if (e->call_stmt && !e->call_stmt_cannot_inline_p && info->conds)
&& ((clause_ptr && info->conds) || known_vals_ptr))
{ {
int i, count = (int)gimple_call_num_args (e->call_stmt); int i, count = (int)gimple_call_num_args (e->call_stmt);
if (count && (info->conds || known_vals_ptr))
known_vals.safe_grow_cleared (count);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
tree cst = gimple_call_arg (e->call_stmt, i); tree cst = gimple_call_arg (e->call_stmt, i);
if (!is_gimple_min_invariant (cst)) if (!is_gimple_min_invariant (cst))
cst = NULL; cst = NULL;
if (cst) if (cst)
known_vals[i] = cst; {
if (!known_vals_ptr->length ())
vec_safe_grow_cleared (known_vals_ptr, count);
(*known_vals_ptr)[i] = cst;
}
} }
} }
evaluate_conditions_for_known_args (callee, inline_p, evaluate_conditions_for_known_args (callee, inline_p,
known_vals, *known_vals_ptr,
known_value_ranges, known_value_ranges,
known_aggs, clause_ptr, *known_aggs_ptr,
clause_ptr,
nonspec_clause_ptr); nonspec_clause_ptr);
if (known_vals_ptr)
*known_vals_ptr = known_vals;
else
known_vals.release ();
if (known_aggs_ptr)
*known_aggs_ptr = known_aggs;
else
ipa_release_agg_values (known_aggs);
} }
...@@ -2926,7 +2964,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie, ...@@ -2926,7 +2964,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
enum availability avail; enum availability avail;
bool speculative; bool speculative;
if (!known_vals.exists () && !known_contexts.exists ()) if (!known_vals.length () && !known_contexts.length ())
return false; return false;
if (!opt_for_fn (ie->caller->decl, flag_indirect_inlining)) if (!opt_for_fn (ie->caller->decl, flag_indirect_inlining))
return false; return false;
...@@ -3305,11 +3343,13 @@ ipa_call_context::release (bool all) ...@@ -3305,11 +3343,13 @@ ipa_call_context::release (bool all)
/* See if context is initialized at first place. */ /* See if context is initialized at first place. */
if (!m_node) if (!m_node)
return; return;
m_known_vals.release (); ipa_release_agg_values (m_known_aggs, all);
m_known_contexts.release ();
ipa_release_agg_values (m_known_aggs);
if (all) if (all)
m_inline_param_summary.release (); {
m_known_vals.release ();
m_known_contexts.release ();
m_inline_param_summary.release ();
}
} }
/* Return true if CTX describes the same call context as THIS. */ /* Return true if CTX describes the same call context as THIS. */
...@@ -3813,8 +3853,12 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge) ...@@ -3813,8 +3853,12 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
info->fp_expressions |= callee_info->fp_expressions; info->fp_expressions |= callee_info->fp_expressions;
if (callee_info->conds) if (callee_info->conds)
evaluate_properties_for_edge (edge, true, &clause, {
NULL, NULL, NULL, NULL); auto_vec<tree, 32> known_vals;
auto_vec<ipa_agg_value_set, 32> known_aggs;
evaluate_properties_for_edge (edge, true, &clause, NULL,
&known_vals, NULL, &known_aggs);
}
if (ipa_node_params_sum && callee_info->conds) if (ipa_node_params_sum && callee_info->conds)
{ {
class ipa_edge_args *args = IPA_EDGE_REF (edge); class ipa_edge_args *args = IPA_EDGE_REF (edge);
......
...@@ -186,9 +186,9 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time) ...@@ -186,9 +186,9 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time)
ipa_hints hints; ipa_hints hints;
struct cgraph_node *callee; struct cgraph_node *callee;
clause_t clause, nonspec_clause; clause_t clause, nonspec_clause;
vec<tree> known_vals; auto_vec<tree, 32> known_vals;
vec<ipa_polymorphic_call_context> known_contexts; auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
vec<ipa_agg_value_set> known_aggs; auto_vec<ipa_agg_value_set, 32> known_aggs;
class ipa_call_summary *es = ipa_call_summaries->get (edge); class ipa_call_summary *es = ipa_call_summaries->get (edge);
int min_size = -1; int min_size = -1;
...@@ -308,9 +308,9 @@ do_estimate_edge_size (struct cgraph_edge *edge) ...@@ -308,9 +308,9 @@ do_estimate_edge_size (struct cgraph_edge *edge)
int size; int size;
struct cgraph_node *callee; struct cgraph_node *callee;
clause_t clause, nonspec_clause; clause_t clause, nonspec_clause;
vec<tree> known_vals; auto_vec<tree, 32> known_vals;
vec<ipa_polymorphic_call_context> known_contexts; auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
vec<ipa_agg_value_set> known_aggs; auto_vec<ipa_agg_value_set, 32> known_aggs;
/* When we do caching, use do_estimate_edge_time to populate the entry. */ /* When we do caching, use do_estimate_edge_time to populate the entry. */
...@@ -347,9 +347,9 @@ do_estimate_edge_hints (struct cgraph_edge *edge) ...@@ -347,9 +347,9 @@ do_estimate_edge_hints (struct cgraph_edge *edge)
ipa_hints hints; ipa_hints hints;
struct cgraph_node *callee; struct cgraph_node *callee;
clause_t clause, nonspec_clause; clause_t clause, nonspec_clause;
vec<tree> known_vals; auto_vec<tree, 32> known_vals;
vec<ipa_polymorphic_call_context> known_contexts; auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
vec<ipa_agg_value_set> known_aggs; auto_vec<ipa_agg_value_set, 32> known_aggs;
/* When we do caching, use do_estimate_edge_time to populate the entry. */ /* When we do caching, use do_estimate_edge_time to populate the entry. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment