return target;
}
+/* If an indirect edge IE can be turned into a direct one based on data in
+ AVALS, return the destination. Store into *SPECULATIVE a boolean determinig
+ whether the discovered target is only speculative guess. */
-/* If an indirect edge IE can be turned into a direct one based on KNOWN_CSTS,
- KNOWN_CONTEXTS (which can be vNULL) or KNOWN_AGGS (which also can be vNULL)
- return the destination. */
+tree
+ipa_get_indirect_edge_target (struct cgraph_edge *ie,
+ ipa_call_arg_values *avals,
+ bool *speculative)
+{
+ return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals,
+ avals->m_known_contexts,
+ avals->m_known_aggs,
+ NULL, speculative);
+}
+
+/* The same functionality as above overloaded for ipa_auto_call_arg_values. */
tree
ipa_get_indirect_edge_target (struct cgraph_edge *ie,
- vec<tree> known_csts,
- vec<ipa_polymorphic_call_context> known_contexts,
- vec<ipa_agg_value_set> known_aggs,
+ ipa_auto_call_arg_values *avals,
bool *speculative)
{
- return ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
- known_aggs, NULL, speculative);
+ return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals,
+ avals->m_known_contexts,
+ avals->m_known_aggs,
+ NULL, speculative);
}
-/* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS
- and KNOWN_CONTEXTS. */
+/* Calculate devirtualization time bonus for NODE, assuming we know information
+ about arguments stored in AVALS. */
static int
devirtualization_time_bonus (struct cgraph_node *node,
- vec<tree> known_csts,
- vec<ipa_polymorphic_call_context> known_contexts,
- vec<ipa_agg_value_set> known_aggs)
+ ipa_auto_call_arg_values *avals)
{
struct cgraph_edge *ie;
int res = 0;
tree target;
bool speculative;
- target = ipa_get_indirect_edge_target (ie, known_csts, known_contexts,
- known_aggs, &speculative);
+ target = ipa_get_indirect_edge_target (ie, avals, &speculative);
if (!target)
continue;
return res;
}
-/* Allocate KNOWN_CSTS, KNOWN_CONTEXTS and, if non-NULL, KNOWN_AGGS and
- populate them with values of parameters that are known independent of the
- context. INFO describes the function. If REMOVABLE_PARAMS_COST is
- non-NULL, the movement cost of all removable parameters will be stored in
- it. */
+/* Grow vectors in AVALS and fill them with information about values of
+ parameters that are known to be independent of the context. Only calculate
+ m_known_aggs if CALCULATE_AGGS is true. INFO describes the function. If
+ REMOVABLE_PARAMS_COST is non-NULL, the movement cost of all removable
+ parameters will be stored in it.
+
+ TODO: Also grow context independent value range vectors. */
static bool
gather_context_independent_values (class ipa_node_params *info,
- vec<tree> *known_csts,
- vec<ipa_polymorphic_call_context>
- *known_contexts,
- vec<ipa_agg_value_set> *known_aggs,
+ ipa_auto_call_arg_values *avals,
+ bool calculate_aggs,
int *removable_params_cost)
{
int i, count = ipa_get_param_count (info);
bool ret = false;
- known_csts->create (0);
- known_contexts->create (0);
- known_csts->safe_grow_cleared (count, true);
- known_contexts->safe_grow_cleared (count, true);
- if (known_aggs)
- {
- known_aggs->create (0);
- known_aggs->safe_grow_cleared (count, true);
- }
+ avals->m_known_vals.safe_grow_cleared (count, true);
+ avals->m_known_contexts.safe_grow_cleared (count, true);
+ if (calculate_aggs)
+ avals->m_known_aggs.safe_grow_cleared (count, true);
if (removable_params_cost)
*removable_params_cost = 0;
{
ipcp_value<tree> *val = lat->values;
gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO);
- (*known_csts)[i] = val->value;
+ avals->m_known_vals[i] = val->value;
if (removable_params_cost)
*removable_params_cost
+= estimate_move_cost (TREE_TYPE (val->value), false);
/* Do not account known context as reason for cloning. We can see
if it permits devirtualization. */
if (ctxlat->is_single_const ())
- (*known_contexts)[i] = ctxlat->values->value;
+ avals->m_known_contexts[i] = ctxlat->values->value;
- if (known_aggs)
+ if (calculate_aggs)
{
vec<ipa_agg_value> agg_items;
struct ipa_agg_value_set *agg;
agg_items = context_independent_aggregate_values (plats);
- agg = &(*known_aggs)[i];
+ agg = &avals->m_known_aggs[i];
agg->items = agg_items;
agg->by_ref = plats->aggs_by_ref;
ret |= !agg_items.is_empty ();
return ret;
}
-/* Perform time and size measurement of NODE with the context given in
- KNOWN_CSTS, KNOWN_CONTEXTS and KNOWN_AGGS, calculate the benefit and cost
- given BASE_TIME of the node without specialization, REMOVABLE_PARAMS_COST of
- all context-independent removable parameters and EST_MOVE_COST of estimated
- movement of the considered parameter and store it into VAL. */
+/* Perform time and size measurement of NODE with the context given in AVALS,
+ calculate the benefit compared to the node without specialization and store
+ it into VAL. Take into account REMOVABLE_PARAMS_COST of all
+ context-independent or unused removable parameters and EST_MOVE_COST, the
+ estimated movement of the considered parameter. */
static void
-perform_estimation_of_a_value (cgraph_node *node, vec<tree> known_csts,
- vec<ipa_polymorphic_call_context> known_contexts,
- vec<ipa_agg_value_set> known_aggs,
- int removable_params_cost,
- int est_move_cost, ipcp_value_base *val)
+perform_estimation_of_a_value (cgraph_node *node,
+ ipa_auto_call_arg_values *avals,
+ int removable_params_cost, int est_move_cost,
+ ipcp_value_base *val)
{
int size, time_benefit;
sreal time, base_time;
ipa_hints hints;
- estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
- known_aggs, &size, &time,
+ estimate_ipcp_clone_size_and_time (node, avals, &size, &time,
&base_time, &hints);
base_time -= time;
if (base_time > 65535)
time_benefit = 0;
else
time_benefit = base_time.to_int ()
- + devirtualization_time_bonus (node, known_csts, known_contexts,
- known_aggs)
+ + devirtualization_time_bonus (node, avals)
+ hint_time_bonus (node, hints)
+ removable_params_cost + est_move_cost;
{
class ipa_node_params *info = IPA_NODE_REF (node);
int i, count = ipa_get_param_count (info);
- vec<tree> known_csts;
- vec<ipa_polymorphic_call_context> known_contexts;
- vec<ipa_agg_value_set> known_aggs;
bool always_const;
int removable_params_cost;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nEstimating effects for %s.\n", node->dump_name ());
- always_const = gather_context_independent_values (info, &known_csts,
- &known_contexts, &known_aggs,
+ ipa_auto_call_arg_values avals;
+ always_const = gather_context_independent_values (info, &avals, true,
&removable_params_cost);
- int devirt_bonus = devirtualization_time_bonus (node, known_csts,
- known_contexts, known_aggs);
+ int devirt_bonus = devirtualization_time_bonus (node, &avals);
if (always_const || devirt_bonus
|| (removable_params_cost && node->can_change_signature))
{
init_caller_stats (&stats);
node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats,
false);
- estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
- known_aggs, &size, &time,
+ estimate_ipcp_clone_size_and_time (node, &avals, &size, &time,
&base_time, &hints);
time -= devirt_bonus;
time -= hint_time_bonus (node, hints);
if (lat->bottom
|| !lat->values
- || known_csts[i])
+ || avals.m_known_vals[i])
continue;
for (val = lat->values; val; val = val->next)
{
gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO);
- known_csts[i] = val->value;
+ avals.m_known_vals[i] = val->value;
int emc = estimate_move_cost (TREE_TYPE (val->value), true);
- perform_estimation_of_a_value (node, known_csts, known_contexts,
- known_aggs,
- removable_params_cost, emc, val);
+ perform_estimation_of_a_value (node, &avals, removable_params_cost,
+ emc, val);
if (dump_file && (dump_flags & TDF_DETAILS))
{
val->local_time_benefit, val->local_size_cost);
}
}
- known_csts[i] = NULL_TREE;
+ avals.m_known_vals[i] = NULL_TREE;
}
for (i = 0; i < count; i++)
if (ctxlat->bottom
|| !ctxlat->values
- || !known_contexts[i].useless_p ())
+ || !avals.m_known_contexts[i].useless_p ())
continue;
for (val = ctxlat->values; val; val = val->next)
{
- known_contexts[i] = val->value;
- perform_estimation_of_a_value (node, known_csts, known_contexts,
- known_aggs,
- removable_params_cost, 0, val);
+ avals.m_known_contexts[i] = val->value;
+ perform_estimation_of_a_value (node, &avals, removable_params_cost,
+ 0, val);
if (dump_file && (dump_flags & TDF_DETAILS))
{
val->local_time_benefit, val->local_size_cost);
}
}
- known_contexts[i] = ipa_polymorphic_call_context ();
+ avals.m_known_contexts[i] = ipa_polymorphic_call_context ();
}
for (i = 0; i < count; i++)
{
class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
- struct ipa_agg_value_set *agg;
- struct ipcp_agg_lattice *aglat;
if (plats->aggs_bottom || !plats->aggs)
continue;
- agg = &known_aggs[i];
- for (aglat = plats->aggs; aglat; aglat = aglat->next)
+ ipa_agg_value_set *agg = &avals.m_known_aggs[i];
+ for (ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next)
{
ipcp_value<tree> *val;
if (aglat->bottom || !aglat->values
item.value = val->value;
agg->items.safe_push (item);
- perform_estimation_of_a_value (node, known_csts, known_contexts,
- known_aggs,
+ perform_estimation_of_a_value (node, &avals,
removable_params_cost, 0, val);
if (dump_file && (dump_flags & TDF_DETAILS))
}
}
}
-
- known_csts.release ();
- known_contexts.release ();
- ipa_release_agg_values (known_aggs);
}
return vNULL;
}
-/* Copy KNOWN_CSTS and modify the copy according to VAL and INDEX. If
- non-empty, replace KNOWN_CONTEXTS with its copy too. */
+/* Copy known scalar values from AVALS into KNOWN_CSTS and modify the copy
+ according to VAL and INDEX. If non-empty, replace KNOWN_CONTEXTS with its
+ copy too. */
static void
-modify_known_vectors_with_val (vec<tree> *known_csts,
- vec<ipa_polymorphic_call_context> *known_contexts,
- ipcp_value<tree> *val,
- int index)
+copy_known_vectors_add_val (ipa_auto_call_arg_values *avals,
+ vec<tree> *known_csts,
+ vec<ipa_polymorphic_call_context> *known_contexts,
+ ipcp_value<tree> *val, int index)
{
- *known_csts = known_csts->copy ();
- *known_contexts = copy_useful_known_contexts (*known_contexts);
+ *known_csts = avals->m_known_vals.copy ();
+ *known_contexts = copy_useful_known_contexts (avals->m_known_contexts);
(*known_csts)[index] = val->value;
}
-/* Replace KNOWN_CSTS with its copy. Also copy KNOWN_CONTEXTS and modify the
- copy according to VAL and INDEX. */
+/* Copy known scalar values from AVALS into KNOWN_CSTS. Similarly, copy
+ contexts to KNOWN_CONTEXTS and modify the copy according to VAL and
+ INDEX. */
static void
-modify_known_vectors_with_val (vec<tree> *known_csts,
- vec<ipa_polymorphic_call_context> *known_contexts,
- ipcp_value<ipa_polymorphic_call_context> *val,
- int index)
-{
- *known_csts = known_csts->copy ();
- *known_contexts = known_contexts->copy ();
+copy_known_vectors_add_val (ipa_auto_call_arg_values *avals,
+ vec<tree> *known_csts,
+ vec<ipa_polymorphic_call_context> *known_contexts,
+ ipcp_value<ipa_polymorphic_call_context> *val,
+ int index)
+{
+ *known_csts = avals->m_known_vals.copy ();
+ *known_contexts = avals->m_known_contexts.copy ();
(*known_contexts)[index] = val->value;
}
return offset == -1;
}
-/* Decide whether to create a special version of NODE for value VAL of parameter
- at the given INDEX. If OFFSET is -1, the value is for the parameter itself,
- otherwise it is stored at the given OFFSET of the parameter. KNOWN_CSTS,
- KNOWN_CONTEXTS and KNOWN_AGGS describe the other already known values. */
+/* Decide whether to create a special version of NODE for value VAL of
+ parameter at the given INDEX. If OFFSET is -1, the value is for the
+ parameter itself, otherwise it is stored at the given OFFSET of the
+ parameter. AVALS describes the other already known values. */
template <typename valtype>
static bool
decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset,
- ipcp_value<valtype> *val, vec<tree> known_csts,
- vec<ipa_polymorphic_call_context> known_contexts)
+ ipcp_value<valtype> *val, ipa_auto_call_arg_values *avals)
{
struct ipa_agg_replacement_value *aggvals;
int freq_sum, caller_count;
fprintf (dump_file, " Creating a specialized node of %s.\n",
node->dump_name ());
+ vec<tree> known_csts;
+ vec<ipa_polymorphic_call_context> known_contexts;
+
callers = gather_edges_for_value (val, node, caller_count);
if (offset == -1)
- modify_known_vectors_with_val (&known_csts, &known_contexts, val, index);
+ copy_known_vectors_add_val (avals, &known_csts, &known_contexts, val, index);
else
{
- known_csts = known_csts.copy ();
- known_contexts = copy_useful_known_contexts (known_contexts);
+ known_csts = avals->m_known_vals.copy ();
+ known_contexts = copy_useful_known_contexts (avals->m_known_contexts);
}
find_more_scalar_values_for_callers_subset (node, known_csts, callers);
find_more_contexts_for_caller_subset (node, &known_contexts, callers);
{
class ipa_node_params *info = IPA_NODE_REF (node);
int i, count = ipa_get_param_count (info);
- vec<tree> known_csts;
- vec<ipa_polymorphic_call_context> known_contexts;
bool ret = false;
if (count == 0)
fprintf (dump_file, "\nEvaluating opportunities for %s.\n",
node->dump_name ());
- gather_context_independent_values (info, &known_csts, &known_contexts,
- NULL, NULL);
+ ipa_auto_call_arg_values avals;
+ gather_context_independent_values (info, &avals, false, NULL);
for (i = 0; i < count;i++)
{
ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
if (!lat->bottom
- && !known_csts[i])
+ && !avals.m_known_vals[i])
{
ipcp_value<tree> *val;
for (val = lat->values; val; val = val->next)
- ret |= decide_about_value (node, i, -1, val, known_csts,
- known_contexts);
+ ret |= decide_about_value (node, i, -1, val, &avals);
}
if (!plats->aggs_bottom)
ipcp_value<tree> *val;
for (aglat = plats->aggs; aglat; aglat = aglat->next)
if (!aglat->bottom && aglat->values
- /* If the following is false, the one value is in
- known_aggs. */
+ /* If the following is false, the one value has been considered
+ for cloning for all contexts. */
&& (plats->aggs_contain_variable
|| !aglat->is_single_const ()))
for (val = aglat->values; val; val = val->next)
- ret |= decide_about_value (node, i, aglat->offset, val,
- known_csts, known_contexts);
+ ret |= decide_about_value (node, i, aglat->offset, val, &avals);
}
if (!ctxlat->bottom
- && known_contexts[i].useless_p ())
+ && avals.m_known_contexts[i].useless_p ())
{
ipcp_value<ipa_polymorphic_call_context> *val;
for (val = ctxlat->values; val; val = val->next)
- ret |= decide_about_value (node, i, -1, val, known_csts,
- known_contexts);
+ ret |= decide_about_value (node, i, -1, val, &avals);
}
info = IPA_NODE_REF (node);
if (!adjust_callers_for_value_intersection (callers, node))
{
/* If node is not called by anyone, or all its caller edges are
- self-recursive, the node is not really be in use, no need to
- do cloning. */
+ self-recursive, the node is not really in use, no need to do
+ cloning. */
callers.release ();
- known_csts.release ();
- known_contexts.release ();
info->do_clone_for_all_contexts = false;
return ret;
}
fprintf (dump_file, " - Creating a specialized node of %s "
"for all known contexts.\n", node->dump_name ());
+ vec<tree> known_csts = avals.m_known_vals.copy ();
+ vec<ipa_polymorphic_call_context> known_contexts
+ = copy_useful_known_contexts (avals.m_known_contexts);
find_more_scalar_values_for_callers_subset (node, known_csts, callers);
find_more_contexts_for_caller_subset (node, &known_contexts, callers);
ipa_agg_replacement_value *aggvals
IPA_NODE_REF (clone)->is_all_contexts_clone = true;
ret = true;
}
- else
- {
- known_csts.release ();
- known_contexts.release ();
- }
return ret;
}
is always false in the second and also builtin_constant_p tests cannot use
the fact that parameter is indeed a constant.
- KNOWN_VALS is partial mapping of parameters of NODE to constant values.
- KNOWN_AGGS is a vector of aggregate known offset/value set for each
- parameter. Return clause of possible truths. When INLINE_P is true, assume
- that we are inlining.
+ When INLINE_P is true, assume that we are inlining. AVAL contains known
+ information about argument values. The function does not modify its content
+ and so AVALs could also be of type ipa_call_arg_values but so far all
+ callers work with the auto version and so we avoid the conversion for
+ convenience.
- ERROR_MARK means compile time invariant. */
+ ERROR_MARK value of an argument means compile time invariant. */
static void
evaluate_conditions_for_known_args (struct cgraph_node *node,
bool inline_p,
- vec<tree> known_vals,
- vec<value_range> known_value_ranges,
- vec<ipa_agg_value_set> known_aggs,
+ ipa_auto_call_arg_values *avals,
clause_t *ret_clause,
clause_t *ret_nonspec_clause)
{
/* We allow call stmt to have fewer arguments than the callee function
(especially for K&R style programs). So bound check here (we assume
- known_aggs vector, if non-NULL, has the same length as
- known_vals). */
- gcc_checking_assert (!known_aggs.length () || !known_vals.length ()
- || (known_vals.length () == known_aggs.length ()));
+ m_known_aggs vector is either empty or has the same length as
+ m_known_vals). */
+ gcc_checking_assert (!avals->m_known_aggs.length ()
+ || !avals->m_known_vals.length ()
+ || (avals->m_known_vals.length ()
+ == avals->m_known_aggs.length ()));
if (c->agg_contents)
{
- struct ipa_agg_value_set *agg;
-
if (c->code == predicate::changed
&& !c->by_ref
- && c->operand_num < (int)known_vals.length ()
- && (known_vals[c->operand_num] == error_mark_node))
+ && (avals->safe_sval_at(c->operand_num) == error_mark_node))
continue;
- if (c->operand_num < (int)known_aggs.length ())
+ if (ipa_agg_value_set *agg = avals->safe_aggval_at (c->operand_num))
{
- agg = &known_aggs[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);
+ tree sval = avals->safe_sval_at (c->operand_num);
+ val = ipa_find_agg_cst_for_param (agg, sval, c->offset,
+ c->by_ref);
}
else
val = NULL_TREE;
}
- else if (c->operand_num < (int) known_vals.length ())
+ else
{
- val = known_vals[c->operand_num];
- if (val == error_mark_node && c->code != predicate::changed)
+ val = avals->safe_sval_at (c->operand_num);
+ if (val && val == error_mark_node && c->code != predicate::changed)
val = NULL_TREE;
}
continue;
}
}
- if (c->operand_num < (int) known_value_ranges.length ()
+ if (c->operand_num < (int) avals->m_known_value_ranges.length ()
&& !c->agg_contents
- && !known_value_ranges[c->operand_num].undefined_p ()
- && !known_value_ranges[c->operand_num].varying_p ()
- && TYPE_SIZE (c->type)
- == TYPE_SIZE (known_value_ranges[c->operand_num].type ())
&& (!val || TREE_CODE (val) != INTEGER_CST))
{
- value_range vr = known_value_ranges[c->operand_num];
- if (!useless_type_conversion_p (c->type, vr.type ()))
+ value_range vr = avals->m_known_value_ranges[c->operand_num];
+ if (!vr.undefined_p ()
+ && !vr.varying_p ()
+ && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ())))
{
- value_range res;
- range_fold_unary_expr (&res, NOP_EXPR,
+ if (!useless_type_conversion_p (c->type, vr.type ()))
+ {
+ value_range res;
+ range_fold_unary_expr (&res, NOP_EXPR,
c->type, &vr, vr.type ());
- vr = res;
- }
- tree type = c->type;
+ vr = res;
+ }
+ tree type = c->type;
- for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
- {
- if (vr.varying_p () || vr.undefined_p ())
- break;
+ for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+ {
+ if (vr.varying_p () || vr.undefined_p ())
+ break;
- value_range res;
- if (!op->val[0])
- range_fold_unary_expr (&res, op->code, op->type, &vr, type);
- else if (!op->val[1])
+ value_range res;
+ if (!op->val[0])
+ range_fold_unary_expr (&res, op->code, op->type, &vr, type);
+ else if (!op->val[1])
+ {
+ value_range op0 (op->val[0], op->val[0]);
+ range_fold_binary_expr (&res, op->code, op->type,
+ op->index ? &op0 : &vr,
+ op->index ? &vr : &op0);
+ }
+ else
+ gcc_unreachable ();
+ type = op->type;
+ vr = res;
+ }
+ if (!vr.varying_p () && !vr.undefined_p ())
{
- value_range op0 (op->val[0], op->val[0]);
- range_fold_binary_expr (&res, op->code, op->type,
- op->index ? &op0 : &vr,
- op->index ? &vr : &op0);
+ value_range res;
+ value_range val_vr (c->val, c->val);
+ range_fold_binary_expr (&res, c->code, boolean_type_node,
+ &vr,
+ &val_vr);
+ if (res.zero_p ())
+ continue;
}
- else
- gcc_unreachable ();
- type = op->type;
- vr = res;
- }
- if (!vr.varying_p () && !vr.undefined_p ())
- {
- value_range res;
- value_range val_vr (c->val, c->val);
- range_fold_binary_expr (&res, c->code, boolean_type_node,
- &vr,
- &val_vr);
- if (res.zero_p ())
- continue;
}
}
(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 constant 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. */
+ Vectors in AVALS will be populated with useful known information about
+ argument values - information not known to have any uses will be omitted -
+ except for m_known_contexts which will only be calculated if
+ COMPUTE_CONTEXTS is true. */
void
evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
clause_t *clause_ptr,
clause_t *nonspec_clause_ptr,
- vec<tree> *known_vals_ptr,
- vec<ipa_polymorphic_call_context>
- *known_contexts_ptr,
- vec<ipa_agg_value_set> *known_aggs_ptr)
+ ipa_auto_call_arg_values *avals,
+ bool compute_contexts)
{
struct cgraph_node *callee = e->callee->ultimate_alias_target ();
class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
- auto_vec<value_range, 32> known_value_ranges;
class ipa_edge_args *args;
if (clause_ptr)
if (ipa_node_params_sum
&& !e->call_stmt_cannot_inline_p
- && (info->conds || known_contexts_ptr)
+ && (info->conds || compute_contexts)
&& (args = IPA_EDGE_REF (e)) != NULL)
{
struct cgraph_node *caller;
if (cst)
{
gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO);
- if (!known_vals_ptr->length ())
- vec_safe_grow_cleared (known_vals_ptr, count, true);
- (*known_vals_ptr)[i] = cst;
+ if (!avals->m_known_vals.length ())
+ avals->m_known_vals.safe_grow_cleared (count, true);
+ avals->m_known_vals[i] = cst;
}
else if (inline_p && !es->param[i].change_prob)
{
- if (!known_vals_ptr->length ())
- vec_safe_grow_cleared (known_vals_ptr, count, true);
- (*known_vals_ptr)[i] = error_mark_node;
+ if (!avals->m_known_vals.length ())
+ avals->m_known_vals.safe_grow_cleared (count, true);
+ avals->m_known_vals[i] = error_mark_node;
}
/* If we failed to get simple constant, try value range. */
&& vrp_will_run_p (caller)
&& ipa_is_param_used_by_ipa_predicates (callee_pi, i))
{
- value_range vr
+ 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 ())
+ if (!avals->m_known_value_ranges.length ())
{
- known_value_ranges.safe_grow (count, true);
+ avals->m_known_value_ranges.safe_grow (count, true);
for (int i = 0; i < count; ++i)
- new (&known_value_ranges[i]) value_range ();
+ new (&avals->m_known_value_ranges[i])
+ value_range ();
}
- known_value_ranges[i] = vr;
+ avals->m_known_value_ranges[i] = vr;
}
}
caller, &jf->agg);
if (agg.items.length ())
{
- if (!known_aggs_ptr->length ())
- vec_safe_grow_cleared (known_aggs_ptr, count, true);
- (*known_aggs_ptr)[i] = agg;
+ if (!avals->m_known_aggs.length ())
+ avals->m_known_aggs.safe_grow_cleared (count, true);
+ avals->m_known_aggs[i] = agg;
}
}
}
/* For calls used in polymorphic calls we further determine
polymorphic call context. */
- if (known_contexts_ptr
+ if (compute_contexts
&& ipa_is_param_used_by_polymorphic_call (callee_pi, i))
{
ipa_polymorphic_call_context
ctx = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
if (!ctx.useless_p ())
{
- if (!known_contexts_ptr->length ())
- known_contexts_ptr->safe_grow_cleared (count, true);
- (*known_contexts_ptr)[i]
+ if (!avals->m_known_contexts.length ())
+ avals->m_known_contexts.safe_grow_cleared (count, true);
+ avals->m_known_contexts[i]
= ipa_context_from_jfunc (caller_parms_info, e, i, jf);
}
}
cst = NULL;
if (cst)
{
- if (!known_vals_ptr->length ())
- vec_safe_grow_cleared (known_vals_ptr, count, true);
- (*known_vals_ptr)[i] = cst;
+ if (!avals->m_known_vals.length ())
+ avals->m_known_vals.safe_grow_cleared (count, true);
+ avals->m_known_vals[i] = cst;
}
}
}
- evaluate_conditions_for_known_args (callee, inline_p,
- *known_vals_ptr,
- known_value_ranges,
- *known_aggs_ptr,
- clause_ptr,
+ evaluate_conditions_for_known_args (callee, inline_p, avals, clause_ptr,
nonspec_clause_ptr);
}
vec<size_time_entry, va_gc> *entry = info->size_time_table;
/* Use SRC parm info since it may not be copied yet. */
class ipa_node_params *parms_info = IPA_NODE_REF (src);
- vec<tree> known_vals = vNULL;
+ ipa_auto_call_arg_values avals;
int count = ipa_get_param_count (parms_info);
int i, j;
clause_t possible_truths;
struct cgraph_edge *edge, *next;
info->size_time_table = 0;
- known_vals.safe_grow_cleared (count, true);
+ avals.m_known_vals.safe_grow_cleared (count, true);
for (i = 0; i < count; i++)
{
struct ipa_replace_map *r;
{
if (r->parm_num == i)
{
- known_vals[i] = r->new_tree;
+ avals.m_known_vals[i] = r->new_tree;
break;
}
}
}
evaluate_conditions_for_known_args (dst, false,
- known_vals,
- vNULL,
- vNULL,
+ &avals,
&possible_truths,
/* We are going to specialize,
so ignore nonspec truths. */
NULL);
- known_vals.release ();
info->account_size_time (0, 0, true_pred, true_pred);
return 0;
}
-/* Estimate benefit devirtualizing indirect edge IE, provided KNOWN_VALS,
- KNOWN_CONTEXTS and KNOWN_AGGS. */
+/* Estimate benefit devirtualizing indirect edge IE and return true if it can
+ be devirtualized and inlined, provided m_known_vals, m_known_contexts and
+ m_known_aggs in AVALS. Return false straight away if AVALS is NULL. */
static bool
estimate_edge_devirt_benefit (struct cgraph_edge *ie,
int *size, int *time,
- vec<tree> known_vals,
- vec<ipa_polymorphic_call_context> known_contexts,
- vec<ipa_agg_value_set> known_aggs)
+ ipa_call_arg_values *avals)
{
tree target;
struct cgraph_node *callee;
enum availability avail;
bool speculative;
- if (!known_vals.length () && !known_contexts.length ())
+ if (!avals
+ || (!avals->m_known_vals.length() && !avals->m_known_contexts.length ()))
return false;
if (!opt_for_fn (ie->caller->decl, flag_indirect_inlining))
return false;
- target = ipa_get_indirect_edge_target (ie, known_vals, known_contexts,
- known_aggs, &speculative);
+ target = ipa_get_indirect_edge_target (ie, avals, &speculative);
if (!target || speculative)
return false;
}
/* Increase SIZE, MIN_SIZE (if non-NULL) and TIME for size and time needed to
- handle edge E with probability PROB.
- Set HINTS if edge may be devirtualized.
- KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS describe context of the call
- site. */
+ handle edge E with probability PROB. Set HINTS accordingly if edge may be
+ devirtualized. AVALS, if non-NULL, describes the context of the call site
+ as far as values of parameters are concerened. */
static inline void
estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size,
- sreal *time,
- vec<tree> known_vals,
- vec<ipa_polymorphic_call_context> known_contexts,
- vec<ipa_agg_value_set> known_aggs,
+ sreal *time, ipa_call_arg_values *avals,
ipa_hints *hints)
{
class ipa_call_summary *es = ipa_call_summaries->get (e);
int cur_size;
if (!e->callee && hints && e->maybe_hot_p ()
- && estimate_edge_devirt_benefit (e, &call_size, &call_time,
- known_vals, known_contexts, known_aggs))
+ && estimate_edge_devirt_benefit (e, &call_size, &call_time, avals))
*hints |= INLINE_HINT_indirect_call;
cur_size = call_size * ipa_fn_summary::size_scale;
*size += cur_size;
/* Increase SIZE, MIN_SIZE and TIME for size and time needed to handle all
- calls in NODE. POSSIBLE_TRUTHS, KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS
- describe context of the call site.
-
+ calls in NODE. POSSIBLE_TRUTHS and AVALS describe the context of the call
+ site.
+
Helper for estimate_calls_size_and_time which does the same but
(in most cases) faster. */
int *min_size, sreal *time,
ipa_hints *hints,
clause_t possible_truths,
- vec<tree> known_vals,
- vec<ipa_polymorphic_call_context> known_contexts,
- vec<ipa_agg_value_set> known_aggs)
+ ipa_call_arg_values *avals)
{
struct cgraph_edge *e;
for (e = node->callees; e; e = e->next_callee)
{
gcc_checking_assert (!ipa_call_summaries->get (e));
estimate_calls_size_and_time_1 (e->callee, size, min_size, time,
- hints,
- possible_truths,
- known_vals, known_contexts,
- known_aggs);
+ hints, possible_truths, avals);
+
continue;
}
class ipa_call_summary *es = ipa_call_summaries->get (e);
so we do not need to compute probabilities. */
estimate_edge_size_and_time (e, size,
es->predicate ? NULL : min_size,
- time,
- known_vals, known_contexts,
- known_aggs, hints);
+ time, avals, hints);
}
}
for (e = node->indirect_calls; e; e = e->next_callee)
|| es->predicate->evaluate (possible_truths))
estimate_edge_size_and_time (e, size,
es->predicate ? NULL : min_size,
- time,
- known_vals, known_contexts, known_aggs,
- hints);
+ time, avals, hints);
}
}
int size = 0;
sreal time = 0;
- estimate_edge_size_and_time (e, &size, NULL, &time,
- vNULL, vNULL, vNULL, NULL);
+ estimate_edge_size_and_time (e, &size, NULL, &time, NULL, NULL);
struct predicate pred = true;
class ipa_call_summary *es = ipa_call_summaries->get (e);
int size = 0;
sreal time = 0;
- estimate_edge_size_and_time (e, &size, NULL, &time,
- vNULL, vNULL, vNULL, NULL);
+ estimate_edge_size_and_time (e, &size, NULL, &time, NULL, NULL);
struct predicate pred = true;
class ipa_call_summary *es = ipa_call_summaries->get (e);
}
/* Increase SIZE, MIN_SIZE and TIME for size and time needed to handle all
- calls in NODE. POSSIBLE_TRUTHS, KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS
- describe context of the call site. */
+ calls in NODE. POSSIBLE_TRUTHS and AVALS (the latter if non-NULL) describe
+ context of the call site. */
static void
estimate_calls_size_and_time (struct cgraph_node *node, int *size,
int *min_size, sreal *time,
ipa_hints *hints,
clause_t possible_truths,
- vec<tree> known_vals,
- vec<ipa_polymorphic_call_context> known_contexts,
- vec<ipa_agg_value_set> known_aggs)
+ ipa_call_arg_values *avals)
{
class ipa_fn_summary *sum = ipa_fn_summaries->get (node);
bool use_table = true;
use_table = false;
/* If there is an indirect edge that may be optimized, we need
to go the slow way. */
- else if ((known_vals.length ()
- || known_contexts.length ()
- || known_aggs.length ()) && hints)
+ else if (avals && hints
+ && (avals->m_known_vals.length ()
+ || avals->m_known_contexts.length ()
+ || avals->m_known_aggs.length ()))
{
class ipa_node_params *params_summary = IPA_NODE_REF (node);
unsigned int nargs = params_summary
for (unsigned int i = 0; i < nargs && use_table; i++)
{
if (ipa_is_param_used_by_indirect_call (params_summary, i)
- && ((known_vals.length () > i && known_vals[i])
- || (known_aggs.length () > i
- && known_aggs[i].items.length ())))
+ && (avals->safe_sval_at (i)
+ || (avals->m_known_aggs.length () > i
+ && avals->m_known_aggs[i].items.length ())))
use_table = false;
else if (ipa_is_param_used_by_polymorphic_call (params_summary, i)
- && (known_contexts.length () > i
- && !known_contexts[i].useless_p ()))
+ && (avals->m_known_contexts.length () > i
+ && !avals->m_known_contexts[i].useless_p ()))
use_table = false;
}
}
< ipa_fn_summary::max_size_time_table_size)
{
estimate_calls_size_and_time_1 (node, &old_size, NULL, &old_time, NULL,
- possible_truths, known_vals,
- known_contexts, known_aggs);
+ possible_truths, avals);
gcc_assert (*size == old_size);
if (time && (*time - old_time > 1 || *time - old_time < -1)
&& dump_file)
/* Slow path by walking all edges. */
else
estimate_calls_size_and_time_1 (node, size, min_size, time, hints,
- possible_truths, known_vals, known_contexts,
- known_aggs);
+ possible_truths, avals);
}
-/* Default constructor for ipa call context.
- Memory allocation of known_vals, known_contexts
- and known_aggs vectors is owned by the caller, but can
- be release by ipa_call_context::release.
-
- inline_param_summary is owned by the caller. */
-ipa_call_context::ipa_call_context (cgraph_node *node,
- clause_t possible_truths,
+/* Main constructor for ipa call context. Memory allocation of ARG_VALUES
+ is owned by the caller. INLINE_PARAM_SUMMARY is also owned by the
+ caller. */
+
+ipa_call_context::ipa_call_context (cgraph_node *node, clause_t possible_truths,
clause_t nonspec_possible_truths,
- vec<tree> known_vals,
- vec<ipa_polymorphic_call_context>
- known_contexts,
- vec<ipa_agg_value_set> known_aggs,
vec<inline_param_summary>
- inline_param_summary)
+ inline_param_summary,
+ ipa_auto_call_arg_values *arg_values)
: m_node (node), m_possible_truths (possible_truths),
m_nonspec_possible_truths (nonspec_possible_truths),
m_inline_param_summary (inline_param_summary),
- m_known_vals (known_vals),
- m_known_contexts (known_contexts),
- m_known_aggs (known_aggs)
+ m_avals (arg_values)
{
}
break;
}
}
- m_known_vals = vNULL;
- if (ctx.m_known_vals.exists ())
+ m_avals.m_known_vals = vNULL;
+ if (ctx.m_avals.m_known_vals.exists ())
{
- unsigned int n = MIN (ctx.m_known_vals.length (), nargs);
+ unsigned int n = MIN (ctx.m_avals.m_known_vals.length (), nargs);
for (unsigned int i = 0; i < n; i++)
if (ipa_is_param_used_by_indirect_call (params_summary, i)
- && ctx.m_known_vals[i])
+ && ctx.m_avals.m_known_vals[i])
{
- m_known_vals = ctx.m_known_vals.copy ();
+ m_avals.m_known_vals = ctx.m_avals.m_known_vals.copy ();
break;
}
}
- m_known_contexts = vNULL;
- if (ctx.m_known_contexts.exists ())
+ m_avals.m_known_contexts = vNULL;
+ if (ctx.m_avals.m_known_contexts.exists ())
{
- unsigned int n = MIN (ctx.m_known_contexts.length (), nargs);
+ unsigned int n = MIN (ctx.m_avals.m_known_contexts.length (), nargs);
for (unsigned int i = 0; i < n; i++)
if (ipa_is_param_used_by_polymorphic_call (params_summary, i)
- && !ctx.m_known_contexts[i].useless_p ())
+ && !ctx.m_avals.m_known_contexts[i].useless_p ())
{
- m_known_contexts = ctx.m_known_contexts.copy ();
+ m_avals.m_known_contexts = ctx.m_avals.m_known_contexts.copy ();
break;
}
}
- m_known_aggs = vNULL;
- if (ctx.m_known_aggs.exists ())
+ m_avals.m_known_aggs = vNULL;
+ if (ctx.m_avals.m_known_aggs.exists ())
{
- unsigned int n = MIN (ctx.m_known_aggs.length (), nargs);
+ unsigned int n = MIN (ctx.m_avals.m_known_aggs.length (), nargs);
for (unsigned int i = 0; i < n; i++)
if (ipa_is_param_used_by_indirect_call (params_summary, i)
- && !ctx.m_known_aggs[i].is_empty ())
+ && !ctx.m_avals.m_known_aggs[i].is_empty ())
{
- m_known_aggs = ipa_copy_agg_values (ctx.m_known_aggs);
+ m_avals.m_known_aggs
+ = ipa_copy_agg_values (ctx.m_avals.m_known_aggs);
break;
}
}
+
+ m_avals.m_known_value_ranges = vNULL;
}
/* Release memory used by known_vals/contexts/aggs vectors.
/* See if context is initialized at first place. */
if (!m_node)
return;
- ipa_release_agg_values (m_known_aggs, all);
+ ipa_release_agg_values (m_avals.m_known_aggs, all);
if (all)
{
- m_known_vals.release ();
- m_known_contexts.release ();
+ m_avals.m_known_vals.release ();
+ m_avals.m_known_contexts.release ();
m_inline_param_summary.release ();
}
}
return false;
}
}
- if (m_known_vals.exists () || ctx.m_known_vals.exists ())
+ if (m_avals.m_known_vals.exists () || ctx.m_avals.m_known_vals.exists ())
{
for (unsigned int i = 0; i < nargs; i++)
{
if (!ipa_is_param_used_by_indirect_call (params_summary, i))
continue;
- if (i >= m_known_vals.length () || !m_known_vals[i])
+ if (i >= m_avals.m_known_vals.length () || !m_avals.m_known_vals[i])
{
- if (i < ctx.m_known_vals.length () && ctx.m_known_vals[i])
+ if (i < ctx.m_avals.m_known_vals.length ()
+ && ctx.m_avals.m_known_vals[i])
return false;
continue;
}
- if (i >= ctx.m_known_vals.length () || !ctx.m_known_vals[i])
+ if (i >= ctx.m_avals.m_known_vals.length ()
+ || !ctx.m_avals.m_known_vals[i])
{
- if (i < m_known_vals.length () && m_known_vals[i])
+ if (i < m_avals.m_known_vals.length () && m_avals.m_known_vals[i])
return false;
continue;
}
- if (m_known_vals[i] != ctx.m_known_vals[i])
+ if (m_avals.m_known_vals[i] != ctx.m_avals.m_known_vals[i])
return false;
}
}
- if (m_known_contexts.exists () || ctx.m_known_contexts.exists ())
+ if (m_avals.m_known_contexts.exists ()
+ || ctx.m_avals.m_known_contexts.exists ())
{
for (unsigned int i = 0; i < nargs; i++)
{
if (!ipa_is_param_used_by_polymorphic_call (params_summary, i))
continue;
- if (i >= m_known_contexts.length ()
- || m_known_contexts[i].useless_p ())
+ if (i >= m_avals.m_known_contexts.length ()
+ || m_avals.m_known_contexts[i].useless_p ())
{
- if (i < ctx.m_known_contexts.length ()
- && !ctx.m_known_contexts[i].useless_p ())
+ if (i < ctx.m_avals.m_known_contexts.length ()
+ && !ctx.m_avals.m_known_contexts[i].useless_p ())
return false;
continue;
}
- if (i >= ctx.m_known_contexts.length ()
- || ctx.m_known_contexts[i].useless_p ())
+ if (i >= ctx.m_avals.m_known_contexts.length ()
+ || ctx.m_avals.m_known_contexts[i].useless_p ())
{
- if (i < m_known_contexts.length ()
- && !m_known_contexts[i].useless_p ())
+ if (i < m_avals.m_known_contexts.length ()
+ && !m_avals.m_known_contexts[i].useless_p ())
return false;
continue;
}
- if (!m_known_contexts[i].equal_to
- (ctx.m_known_contexts[i]))
+ if (!m_avals.m_known_contexts[i].equal_to
+ (ctx.m_avals.m_known_contexts[i]))
return false;
}
}
- if (m_known_aggs.exists () || ctx.m_known_aggs.exists ())
+ if (m_avals.m_known_aggs.exists () || ctx.m_avals.m_known_aggs.exists ())
{
for (unsigned int i = 0; i < nargs; i++)
{
if (!ipa_is_param_used_by_indirect_call (params_summary, i))
continue;
- if (i >= m_known_aggs.length () || m_known_aggs[i].is_empty ())
+ if (i >= m_avals.m_known_aggs.length ()
+ || m_avals.m_known_aggs[i].is_empty ())
{
- if (i < ctx.m_known_aggs.length ()
- && !ctx.m_known_aggs[i].is_empty ())
+ if (i < ctx.m_avals.m_known_aggs.length ()
+ && !ctx.m_avals.m_known_aggs[i].is_empty ())
return false;
continue;
}
- if (i >= ctx.m_known_aggs.length ()
- || ctx.m_known_aggs[i].is_empty ())
+ if (i >= ctx.m_avals.m_known_aggs.length ()
+ || ctx.m_avals.m_known_aggs[i].is_empty ())
{
- if (i < m_known_aggs.length ()
- && !m_known_aggs[i].is_empty ())
+ if (i < m_avals.m_known_aggs.length ()
+ && !m_avals.m_known_aggs[i].is_empty ())
return false;
continue;
}
- if (!m_known_aggs[i].equal_to (ctx.m_known_aggs[i]))
+ if (!m_avals.m_known_aggs[i].equal_to (ctx.m_avals.m_known_aggs[i]))
return false;
}
}
estimate_calls_size_and_time (m_node, &size, &min_size,
ret_time ? &time : NULL,
ret_hints ? &hints : NULL, m_possible_truths,
- m_known_vals, m_known_contexts, m_known_aggs);
+ &m_avals);
sreal nonspecialized_time = time;
void
estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
- vec<tree> known_vals,
- vec<ipa_polymorphic_call_context>
- known_contexts,
- vec<ipa_agg_value_set> known_aggs,
+ ipa_auto_call_arg_values *avals,
int *ret_size, sreal *ret_time,
sreal *ret_nonspec_time,
ipa_hints *hints)
{
clause_t clause, nonspec_clause;
- /* TODO: Also pass known value ranges. */
- evaluate_conditions_for_known_args (node, false, known_vals, vNULL,
- known_aggs, &clause, &nonspec_clause);
- ipa_call_context ctx (node, clause, nonspec_clause,
- known_vals, known_contexts,
- known_aggs, vNULL);
+ evaluate_conditions_for_known_args (node, false, avals, &clause,
+ &nonspec_clause);
+ ipa_call_context ctx (node, clause, nonspec_clause, vNULL, avals);
ctx.estimate_size_and_time (ret_size, NULL, ret_time,
ret_nonspec_time, hints);
}
if (callee_info->conds)
{
- 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);
+ ipa_auto_call_arg_values avals;
+ evaluate_properties_for_edge (edge, true, &clause, NULL, &avals, false);
}
if (ipa_node_params_sum && callee_info->conds)
{
int edge_size = 0;
sreal edge_time = 0;
- estimate_edge_size_and_time (edge, &edge_size, NULL, &edge_time, vNULL,
- vNULL, vNULL, 0);
+ estimate_edge_size_and_time (edge, &edge_size, NULL, &edge_time, NULL, 0);
/* Unaccount size and time of the optimized out call. */
info->account_size_time (-edge_size, -edge_time,
es->predicate ? *es->predicate : true,
estimate_calls_size_and_time (node, &size_info->size, &info->min_size,
&info->time, NULL,
~(clause_t) (1 << predicate::false_condition),
- vNULL, vNULL, vNULL);
+ NULL);
size_info->size = RDIV (size_info->size, ipa_fn_summary::size_scale);
info->min_size = RDIV (info->min_size, ipa_fn_summary::size_scale);
}
ipa_call_context (cgraph_node *node,
clause_t possible_truths,
clause_t nonspec_possible_truths,
- vec<tree> known_vals,
- vec<ipa_polymorphic_call_context> known_contexts,
- vec<ipa_agg_value_set> known_aggs,
- vec<inline_param_summary> m_inline_param_summary);
+ vec<inline_param_summary> inline_param_summary,
+ ipa_auto_call_arg_values *arg_values);
ipa_call_context ()
: m_node(NULL)
{
/* Inline summary maintains info about change probabilities. */
vec<inline_param_summary> m_inline_param_summary;
- /* The following is used only to resolve indirect calls. */
-
- /* Vector describing known values of parameters. */
- vec<tree> m_known_vals;
- /* Vector describing known polymorphic call contexts. */
- vec<ipa_polymorphic_call_context> m_known_contexts;
- /* Vector describing known aggregate values. */
- vec<ipa_agg_value_set> m_known_aggs;
+ /* Even after having calculated clauses, the information about argument
+ values is used to resolve indirect calls. */
+ ipa_call_arg_values m_avals;
};
extern fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
void ipa_free_size_summary (void);
void inline_analyze_function (struct cgraph_node *node);
void estimate_ipcp_clone_size_and_time (struct cgraph_node *,
- vec<tree>,
- vec<ipa_polymorphic_call_context>,
- vec<ipa_agg_value_set>,
+ ipa_auto_call_arg_values *,
int *, sreal *, sreal *,
ipa_hints *);
void ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge);
bool inline_p,
clause_t *clause_ptr,
clause_t *nonspec_clause_ptr,
- vec<tree> *known_vals_ptr,
- vec<ipa_polymorphic_call_context>
- *known_contexts_ptr,
- vec<ipa_agg_value_set> *);
+ ipa_auto_call_arg_values *avals,
+ bool compute_contexts);
void ipa_fnsummary_c_finalize (void);
HOST_WIDE_INT ipa_get_stack_frame_offset (struct cgraph_node *node);
ipa_hints hints;
struct cgraph_node *callee;
clause_t clause, nonspec_clause;
- auto_vec<tree, 32> known_vals;
- auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
- auto_vec<ipa_agg_value_set, 32> known_aggs;
+ ipa_auto_call_arg_values avals;
class ipa_call_summary *es = ipa_call_summaries->get (edge);
int min_size = -1;
callee = edge->callee->ultimate_alias_target ();
gcc_checking_assert (edge->inline_failed);
- evaluate_properties_for_edge (edge, true,
- &clause, &nonspec_clause, &known_vals,
- &known_contexts, &known_aggs);
- ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
- known_contexts, known_aggs, es->param);
+ evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause,
+ &avals, true);
+ ipa_call_context ctx (callee, clause, nonspec_clause, es->param, &avals);
if (node_context_cache != NULL)
{
node_context_summary *e = node_context_cache->get_create (callee);
: edge->caller->count.ipa ())))
hints |= INLINE_HINT_known_hot;
- ctx.release ();
gcc_checking_assert (size >= 0);
gcc_checking_assert (time >= 0);
int size;
struct cgraph_node *callee;
clause_t clause, nonspec_clause;
- auto_vec<tree, 32> known_vals;
- auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
- auto_vec<ipa_agg_value_set, 32> known_aggs;
/* When we do caching, use do_estimate_edge_time to populate the entry. */
/* Early inliner runs without caching, go ahead and do the dirty work. */
gcc_checking_assert (edge->inline_failed);
- evaluate_properties_for_edge (edge, true,
- &clause, &nonspec_clause,
- &known_vals, &known_contexts,
- &known_aggs);
- ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
- known_contexts, known_aggs, vNULL);
+ ipa_auto_call_arg_values avals;
+ evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause,
+ &avals, true);
+ ipa_call_context ctx (callee, clause, nonspec_clause, vNULL, &avals);
ctx.estimate_size_and_time (&size, NULL, NULL, NULL, NULL);
- ctx.release ();
return size;
}
ipa_hints hints;
struct cgraph_node *callee;
clause_t clause, nonspec_clause;
- auto_vec<tree, 32> known_vals;
- auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
- auto_vec<ipa_agg_value_set, 32> known_aggs;
/* When we do caching, use do_estimate_edge_time to populate the entry. */
/* Early inliner runs without caching, go ahead and do the dirty work. */
gcc_checking_assert (edge->inline_failed);
- evaluate_properties_for_edge (edge, true,
- &clause, &nonspec_clause,
- &known_vals, &known_contexts,
- &known_aggs);
- ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
- known_contexts, known_aggs, vNULL);
+ ipa_auto_call_arg_values avals;
+ evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause,
+ &avals, true);
+ ipa_call_context ctx (callee, clause, nonspec_clause, vNULL, &avals);
ctx.estimate_size_and_time (NULL, NULL, NULL, NULL, &hints);
- ctx.release ();
hints |= simple_edge_hints (edge);
return hints;
}
return offset == other.offset
&& operand_equal_p (value, other.value, 0);
}
+
+/* Destructor also removing individual aggregate values. */
+
+ipa_auto_call_arg_values::~ipa_auto_call_arg_values ()
+{
+ ipa_release_agg_values (m_known_aggs, false);
+}
+
+
+
#include "gt-ipa-prop.h"
return jfunc->value.ancestor.agg_preserved;
}
+/* Class for allocating a bundle of various potentially known properties about
+ actual arguments of a particular call on stack for the usual case and on
+ heap only if there are unusually many arguments. The data is deallocated
+ when the instance of this class goes out of scope or is otherwise
+ destructed. */
+
+class ipa_auto_call_arg_values
+{
+public:
+ ~ipa_auto_call_arg_values ();
+
+ /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
+ return its element at INDEX, otherwise return NULL. */
+ tree safe_sval_at (int index)
+ {
+ /* TODO: Assert non-negative index here and test. */
+ if ((unsigned) index < m_known_vals.length ())
+ return m_known_vals[index];
+ return NULL;
+ }
+
+ /* If m_known_aggs is sufficiantly long, return the pointer rto its element
+ at INDEX, otherwise return NULL. */
+ ipa_agg_value_set *safe_aggval_at (int index)
+ {
+ /* TODO: Assert non-negative index here and test. */
+ if ((unsigned) index < m_known_aggs.length ())
+ return &m_known_aggs[index];
+ return NULL;
+ }
+
+ /* Vector describing known values of parameters. */
+ auto_vec<tree, 32> m_known_vals;
+
+ /* Vector describing known polymorphic call contexts. */
+ auto_vec<ipa_polymorphic_call_context, 32> m_known_contexts;
+
+ /* Vector describing known aggregate values. */
+ auto_vec<ipa_agg_value_set, 32> m_known_aggs;
+
+ /* Vector describing known value ranges of arguments. */
+ auto_vec<value_range, 32> m_known_value_ranges;
+};
+
+/* Class bundling the various potentially known properties about actual
+ arguments of a particular call. This variant does not deallocate the
+ bundled data in any way. */
+
+class ipa_call_arg_values
+{
+public:
+ /* Default constructor, setting the vectors to empty ones. */
+ ipa_call_arg_values ()
+ {}
+
+ /* Construct this general variant of the bundle from the variant which uses
+ auto_vecs to hold the vectors. This means that vectors of objects
+ constructed with this constructor should not be changed because if they
+ get reallocated, the member vectors and the underlying auto_vecs would get
+ out of sync. */
+ ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
+ : m_known_vals (aavals->m_known_vals),
+ m_known_contexts (aavals->m_known_contexts),
+ m_known_aggs (aavals->m_known_aggs),
+ m_known_value_ranges (aavals->m_known_value_ranges)
+ {}
+
+ /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
+ return its element at INDEX, otherwise return NULL. */
+ tree safe_sval_at (int index)
+ {
+ /* TODO: Assert non-negative index here and test. */
+ if ((unsigned) index < m_known_vals.length ())
+ return m_known_vals[index];
+ return NULL;
+ }
+
+ /* If m_known_aggs is sufficiantly long, return the pointer rto its element
+ at INDEX, otherwise return NULL. */
+ ipa_agg_value_set *safe_aggval_at (int index)
+ {
+ /* TODO: Assert non-negative index here and test. */
+ if ((unsigned) index < m_known_aggs.length ())
+ return &m_known_aggs[index];
+ return NULL;
+ }
+
+ /* Vector describing known values of parameters. */
+ vec<tree> m_known_vals = vNULL;
+
+ /* Vector describing known polymorphic call contexts. */
+ vec<ipa_polymorphic_call_context> m_known_contexts = vNULL;
+
+ /* Vector describing known aggregate values. */
+ vec<ipa_agg_value_set> m_known_aggs = vNULL;
+
+ /* Vector describing known value ranges of arguments. */
+ vec<value_range> m_known_value_ranges = vNULL;
+};
+
+
/* Summary describing a single formal parameter. */
struct GTY(()) ipa_param_descriptor
bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
vec<cgraph_edge *> *new_edges);
-/* Indirect edge and binfo processing. */
+/* Indirect edge processing and target discovery. */
+tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
+ ipa_call_arg_values *avals,
+ bool *speculative);
tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
- vec<tree>,
- vec<ipa_polymorphic_call_context>,
- vec<ipa_agg_value_set>,
- bool *);
+ ipa_auto_call_arg_values *avals,
+ bool *speculative);
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
bool speculative = false);
tree ipa_impossible_devirt_target (struct cgraph_edge *, tree);