|
|
|
@ -203,22 +203,54 @@ not_inlined_predicate (void)
|
|
|
|
|
return single_cond_predicate (predicate_not_inlined_condition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Simple description of whether a memory load or a condition refers to a load
|
|
|
|
|
from an aggregate and if so, how and where from in the aggregate.
|
|
|
|
|
Individual fields have the same meaning like fields with the same name in
|
|
|
|
|
struct condition. */
|
|
|
|
|
|
|
|
|
|
/* Add condition to condition list CONDS. */
|
|
|
|
|
struct agg_position_info
|
|
|
|
|
{
|
|
|
|
|
HOST_WIDE_INT offset;
|
|
|
|
|
bool agg_contents;
|
|
|
|
|
bool by_ref;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Add condition to condition list CONDS. AGGPOS describes whether the used
|
|
|
|
|
oprand is loaded from an aggregate and where in the aggregate it is. It can
|
|
|
|
|
be NULL, which means this not a load from an aggregate. */
|
|
|
|
|
|
|
|
|
|
static struct predicate
|
|
|
|
|
add_condition (struct inline_summary *summary, int operand_num,
|
|
|
|
|
struct agg_position_info *aggpos,
|
|
|
|
|
enum tree_code code, tree val)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct condition *c;
|
|
|
|
|
struct condition new_cond;
|
|
|
|
|
HOST_WIDE_INT offset;
|
|
|
|
|
bool agg_contents, by_ref;
|
|
|
|
|
|
|
|
|
|
if (aggpos)
|
|
|
|
|
{
|
|
|
|
|
offset = aggpos->offset;
|
|
|
|
|
agg_contents = aggpos->agg_contents;
|
|
|
|
|
by_ref = aggpos->by_ref;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
offset = 0;
|
|
|
|
|
agg_contents = false;
|
|
|
|
|
by_ref = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gcc_checking_assert (operand_num >= 0);
|
|
|
|
|
for (i = 0; VEC_iterate (condition, summary->conds, i, c); i++)
|
|
|
|
|
{
|
|
|
|
|
if (c->operand_num == operand_num
|
|
|
|
|
&& c->code == code
|
|
|
|
|
&& c->val == val)
|
|
|
|
|
&& c->val == val
|
|
|
|
|
&& c->agg_contents == agg_contents
|
|
|
|
|
&& (!agg_contents || (c->offset == offset && c->by_ref == by_ref)))
|
|
|
|
|
return single_cond_predicate (i + predicate_first_dynamic_condition);
|
|
|
|
|
}
|
|
|
|
|
/* Too many conditions. Give up and return constant true. */
|
|
|
|
@ -228,6 +260,9 @@ add_condition (struct inline_summary *summary, int operand_num,
|
|
|
|
|
new_cond.operand_num = operand_num;
|
|
|
|
|
new_cond.code = code;
|
|
|
|
|
new_cond.val = val;
|
|
|
|
|
new_cond.agg_contents = agg_contents;
|
|
|
|
|
new_cond.by_ref = by_ref;
|
|
|
|
|
new_cond.offset = offset;
|
|
|
|
|
VEC_safe_push (condition, gc, summary->conds, &new_cond);
|
|
|
|
|
return single_cond_predicate (i + predicate_first_dynamic_condition);
|
|
|
|
|
}
|
|
|
|
@ -519,6 +554,9 @@ dump_condition (FILE *f, conditions conditions, int cond)
|
|
|
|
|
c = VEC_index (condition, conditions,
|
|
|
|
|
cond - predicate_first_dynamic_condition);
|
|
|
|
|
fprintf (f, "op%i", c->operand_num);
|
|
|
|
|
if (c->agg_contents)
|
|
|
|
|
fprintf (f, "[%soffset: " HOST_WIDE_INT_PRINT_DEC "]",
|
|
|
|
|
c->by_ref ? "ref " : "", c->offset);
|
|
|
|
|
if (c->code == IS_NOT_CONSTANT)
|
|
|
|
|
{
|
|
|
|
|
fprintf (f, " not constant");
|
|
|
|
@ -659,15 +697,17 @@ edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
|
|
|
|
|
Return clause of possible truths. When INLINE_P is true, assume that
|
|
|
|
|
we are inlining.
|
|
|
|
|
KNOWN_AGGS is a vector of aggreggate jump functions for each parameter.
|
|
|
|
|
Return clause of possible truths. When INLINE_P is true, assume that we are
|
|
|
|
|
inlining.
|
|
|
|
|
|
|
|
|
|
ERROR_MARK means compile time invariant. */
|
|
|
|
|
|
|
|
|
|
static clause_t
|
|
|
|
|
evaluate_conditions_for_known_args (struct cgraph_node *node,
|
|
|
|
|
bool inline_p,
|
|
|
|
|
VEC (tree, heap) *known_vals)
|
|
|
|
|
bool inline_p,
|
|
|
|
|
VEC (tree, heap) *known_vals,
|
|
|
|
|
VEC (ipa_agg_jump_function_p, heap) *known_aggs)
|
|
|
|
|
{
|
|
|
|
|
clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
|
|
|
|
|
struct inline_summary *info = inline_summary (node);
|
|
|
|
@ -679,16 +719,45 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
|
|
|
|
|
tree val;
|
|
|
|
|
tree res;
|
|
|
|
|
|
|
|
|
|
/* We allow call stmt to have fewer arguments than the callee
|
|
|
|
|
function (especially for K&R style programs). So bound
|
|
|
|
|
check here. */
|
|
|
|
|
if (c->operand_num < (int)VEC_length (tree, known_vals))
|
|
|
|
|
val = VEC_index (tree, known_vals, c->operand_num);
|
|
|
|
|
else
|
|
|
|
|
val = NULL;
|
|
|
|
|
/* 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
|
|
|
|
|
|| (VEC_length (tree, known_vals)
|
|
|
|
|
== VEC_length (ipa_agg_jump_function_p,
|
|
|
|
|
known_aggs)));
|
|
|
|
|
if (c->operand_num >= (int) VEC_length (tree, known_vals))
|
|
|
|
|
{
|
|
|
|
|
clause |= 1 << (i + predicate_first_dynamic_condition);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (val == error_mark_node && c->code != CHANGED)
|
|
|
|
|
val = NULL;
|
|
|
|
|
if (c->agg_contents)
|
|
|
|
|
{
|
|
|
|
|
struct ipa_agg_jump_function *agg;
|
|
|
|
|
|
|
|
|
|
if (c->code == CHANGED
|
|
|
|
|
&& !c->by_ref
|
|
|
|
|
&& (VEC_index (tree, known_vals, c->operand_num)
|
|
|
|
|
== error_mark_node))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (known_aggs)
|
|
|
|
|
{
|
|
|
|
|
agg = VEC_index (ipa_agg_jump_function_p, known_aggs,
|
|
|
|
|
c->operand_num);
|
|
|
|
|
val = ipa_find_agg_cst_for_param (agg, c->offset, c->by_ref);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
val = NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
val = VEC_index (tree, known_vals, c->operand_num);
|
|
|
|
|
if (val == error_mark_node && c->code != CHANGED)
|
|
|
|
|
val = NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!val)
|
|
|
|
|
{
|
|
|
|
@ -711,13 +780,15 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
|
|
|
|
|
clause_t *clause_ptr,
|
|
|
|
|
VEC (tree, heap) **known_vals_ptr,
|
|
|
|
|
VEC (tree, heap) **known_binfos_ptr)
|
|
|
|
|
clause_t *clause_ptr,
|
|
|
|
|
VEC (tree, heap) **known_vals_ptr,
|
|
|
|
|
VEC (tree, heap) **known_binfos_ptr,
|
|
|
|
|
VEC (ipa_agg_jump_function_p, heap) **known_aggs_ptr)
|
|
|
|
|
{
|
|
|
|
|
struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL);
|
|
|
|
|
struct inline_summary *info = inline_summary (callee);
|
|
|
|
|
VEC (tree, heap) *known_vals = NULL;
|
|
|
|
|
VEC (ipa_agg_jump_function_p, heap) *known_aggs = NULL;
|
|
|
|
|
|
|
|
|
|
if (clause_ptr)
|
|
|
|
|
*clause_ptr = inline_p ? 0 : 1 << predicate_not_inlined_condition;
|
|
|
|
@ -742,13 +813,16 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
|
|
|
|
|
|
|
|
|
|
if (count && (info->conds || known_vals_ptr))
|
|
|
|
|
VEC_safe_grow_cleared (tree, heap, known_vals, count);
|
|
|
|
|
if (count && (info->conds || known_aggs_ptr))
|
|
|
|
|
VEC_safe_grow_cleared (ipa_agg_jump_function_p, heap, known_aggs,
|
|
|
|
|
count);
|
|
|
|
|
if (count && known_binfos_ptr)
|
|
|
|
|
VEC_safe_grow_cleared (tree, heap, *known_binfos_ptr, count);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
tree cst = ipa_value_from_jfunc (parms_info,
|
|
|
|
|
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 (parms_info, jf);
|
|
|
|
|
if (cst)
|
|
|
|
|
{
|
|
|
|
|
if (known_vals && TREE_CODE (cst) != TREE_BINFO)
|
|
|
|
@ -761,17 +835,26 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
|
|
|
|
|
es->param,
|
|
|
|
|
i)->change_prob)
|
|
|
|
|
VEC_replace (tree, known_vals, i, error_mark_node);
|
|
|
|
|
/* TODO: When IPA-CP starts propagating and merging aggregate jump
|
|
|
|
|
functions, use its knowledge of the caller too, just like the
|
|
|
|
|
scalar case above. */
|
|
|
|
|
VEC_replace (ipa_agg_jump_function_p, known_aggs, i, &jf->agg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (clause_ptr)
|
|
|
|
|
*clause_ptr = evaluate_conditions_for_known_args (callee, inline_p,
|
|
|
|
|
known_vals);
|
|
|
|
|
known_vals, known_aggs);
|
|
|
|
|
|
|
|
|
|
if (known_vals_ptr)
|
|
|
|
|
*known_vals_ptr = known_vals;
|
|
|
|
|
else
|
|
|
|
|
VEC_free (tree, heap, known_vals);
|
|
|
|
|
|
|
|
|
|
if (known_aggs_ptr)
|
|
|
|
|
*known_aggs_ptr = known_aggs;
|
|
|
|
|
else
|
|
|
|
|
VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -917,8 +1000,8 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
possible_truths = evaluate_conditions_for_known_args (dst,
|
|
|
|
|
false, known_vals);
|
|
|
|
|
possible_truths = evaluate_conditions_for_known_args (dst, false,
|
|
|
|
|
known_vals, NULL);
|
|
|
|
|
VEC_free (tree, heap, known_vals);
|
|
|
|
|
|
|
|
|
|
account_size_time (info, 0, 0, &true_pred);
|
|
|
|
@ -1262,11 +1345,11 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If OP reffers to value of function parameter, return
|
|
|
|
|
the corresponding parameter. */
|
|
|
|
|
/* If OP refers to value of function parameter, return the corresponding
|
|
|
|
|
parameter. */
|
|
|
|
|
|
|
|
|
|
static tree
|
|
|
|
|
unmodified_parm (gimple stmt, tree op)
|
|
|
|
|
unmodified_parm_1 (gimple stmt, tree op)
|
|
|
|
|
{
|
|
|
|
|
/* SSA_NAME referring to parm default def? */
|
|
|
|
|
if (TREE_CODE (op) == SSA_NAME
|
|
|
|
@ -1285,13 +1368,67 @@ unmodified_parm (gimple stmt, tree op)
|
|
|
|
|
if (!modified)
|
|
|
|
|
return op;
|
|
|
|
|
}
|
|
|
|
|
/* Assignment from a parameter? */
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If OP refers to value of function parameter, return the corresponding
|
|
|
|
|
parameter. Also traverse chains of SSA register assignments. */
|
|
|
|
|
|
|
|
|
|
static tree
|
|
|
|
|
unmodified_parm (gimple stmt, tree op)
|
|
|
|
|
{
|
|
|
|
|
tree res = unmodified_parm_1 (stmt, op);
|
|
|
|
|
if (res)
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (op) == SSA_NAME
|
|
|
|
|
&& !SSA_NAME_IS_DEFAULT_DEF (op)
|
|
|
|
|
&& gimple_assign_single_p (SSA_NAME_DEF_STMT (op)))
|
|
|
|
|
return unmodified_parm (SSA_NAME_DEF_STMT (op),
|
|
|
|
|
gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)));
|
|
|
|
|
return NULL;
|
|
|
|
|
return NULL_TREE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If OP refers to a value of a function parameter or value loaded from an
|
|
|
|
|
aggregate passed to a parameter (either by value or reference), return TRUE
|
|
|
|
|
and store the number of the parameter to *INDEX_P and information whether
|
|
|
|
|
and how it has been loaded from an aggregate into *AGGPOS. INFO describes
|
|
|
|
|
the function parameters, STMT is the statement in which OP is used or
|
|
|
|
|
loaded. */
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
unmodified_parm_or_parm_agg_item (struct ipa_node_params *info,
|
|
|
|
|
gimple stmt, tree op, int *index_p,
|
|
|
|
|
struct agg_position_info *aggpos)
|
|
|
|
|
{
|
|
|
|
|
tree res = unmodified_parm_1 (stmt, op);
|
|
|
|
|
|
|
|
|
|
gcc_checking_assert (aggpos);
|
|
|
|
|
if (res)
|
|
|
|
|
{
|
|
|
|
|
*index_p = ipa_get_param_decl_index (info, res);
|
|
|
|
|
if (*index_p < 0)
|
|
|
|
|
return false;
|
|
|
|
|
aggpos->agg_contents = false;
|
|
|
|
|
aggpos->by_ref = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TREE_CODE (op) == SSA_NAME)
|
|
|
|
|
{
|
|
|
|
|
if (SSA_NAME_IS_DEFAULT_DEF (op)
|
|
|
|
|
|| !gimple_assign_single_p (SSA_NAME_DEF_STMT (op)))
|
|
|
|
|
return false;
|
|
|
|
|
stmt = SSA_NAME_DEF_STMT (op);
|
|
|
|
|
op = gimple_assign_rhs1 (stmt);
|
|
|
|
|
if (!REFERENCE_CLASS_P (op))
|
|
|
|
|
return unmodified_parm_or_parm_agg_item (info, stmt, op, index_p,
|
|
|
|
|
aggpos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aggpos->agg_contents = true;
|
|
|
|
|
return ipa_load_from_parm_agg (info, stmt, op, index_p, &aggpos->offset,
|
|
|
|
|
&aggpos->by_ref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if statement might disappear after inlining.
|
|
|
|
@ -1422,13 +1559,12 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
|
|
|
|
|
gimple last;
|
|
|
|
|
tree op;
|
|
|
|
|
int index;
|
|
|
|
|
struct agg_position_info aggpos;
|
|
|
|
|
enum tree_code code, inverted_code;
|
|
|
|
|
edge e;
|
|
|
|
|
edge_iterator ei;
|
|
|
|
|
gimple set_stmt;
|
|
|
|
|
tree op2;
|
|
|
|
|
tree parm;
|
|
|
|
|
tree base;
|
|
|
|
|
|
|
|
|
|
last = last_stmt (bb);
|
|
|
|
|
if (!last
|
|
|
|
@ -1440,12 +1576,8 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
|
|
|
|
|
/* TODO: handle conditionals like
|
|
|
|
|
var = op0 < 4;
|
|
|
|
|
if (var != 0). */
|
|
|
|
|
parm = unmodified_parm (last, op);
|
|
|
|
|
if (parm)
|
|
|
|
|
if (unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
|
|
|
|
|
{
|
|
|
|
|
index = ipa_get_param_decl_index (info, parm);
|
|
|
|
|
if (index == -1)
|
|
|
|
|
return;
|
|
|
|
|
code = gimple_cond_code (last);
|
|
|
|
|
inverted_code
|
|
|
|
|
= invert_tree_comparison (code,
|
|
|
|
@ -1453,8 +1585,7 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
|
|
|
|
|
|
|
|
|
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
|
|
|
|
{
|
|
|
|
|
struct predicate p = add_condition (summary,
|
|
|
|
|
index,
|
|
|
|
|
struct predicate p = add_condition (summary, index, &aggpos,
|
|
|
|
|
e->flags & EDGE_TRUE_VALUE
|
|
|
|
|
? code : inverted_code,
|
|
|
|
|
gimple_cond_rhs (last));
|
|
|
|
@ -1475,28 +1606,21 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
|
|
|
|
|
for this and also the constant code is not known to be
|
|
|
|
|
optimized away when inliner doen't see operand is constant.
|
|
|
|
|
Other optimizers might think otherwise. */
|
|
|
|
|
if (gimple_cond_code (last) != NE_EXPR
|
|
|
|
|
|| !integer_zerop (gimple_cond_rhs (last)))
|
|
|
|
|
return;
|
|
|
|
|
set_stmt = SSA_NAME_DEF_STMT (op);
|
|
|
|
|
if (!gimple_call_builtin_p (set_stmt, BUILT_IN_CONSTANT_P)
|
|
|
|
|
|| gimple_call_num_args (set_stmt) != 1)
|
|
|
|
|
return;
|
|
|
|
|
op2 = gimple_call_arg (set_stmt, 0);
|
|
|
|
|
base = get_base_address (op2);
|
|
|
|
|
parm = unmodified_parm (set_stmt, base ? base : op2);
|
|
|
|
|
if (!parm)
|
|
|
|
|
return;
|
|
|
|
|
index = ipa_get_param_decl_index (info, parm);
|
|
|
|
|
if (index == -1)
|
|
|
|
|
return;
|
|
|
|
|
if (gimple_cond_code (last) != NE_EXPR
|
|
|
|
|
|| !integer_zerop (gimple_cond_rhs (last)))
|
|
|
|
|
if (!unmodified_parm_or_parm_agg_item (info, set_stmt, op2, &index, &aggpos))
|
|
|
|
|
return;
|
|
|
|
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
|
|
|
|
if (e->flags & EDGE_FALSE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
struct predicate p = add_condition (summary,
|
|
|
|
|
index,
|
|
|
|
|
IS_NOT_CONSTANT,
|
|
|
|
|
NULL);
|
|
|
|
|
struct predicate p = add_condition (summary, index, &aggpos,
|
|
|
|
|
IS_NOT_CONSTANT, NULL_TREE);
|
|
|
|
|
e->aux = pool_alloc (edge_predicate_pool);
|
|
|
|
|
*(struct predicate *)e->aux = p;
|
|
|
|
|
}
|
|
|
|
@ -1514,22 +1638,18 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info,
|
|
|
|
|
gimple last;
|
|
|
|
|
tree op;
|
|
|
|
|
int index;
|
|
|
|
|
struct agg_position_info aggpos;
|
|
|
|
|
edge e;
|
|
|
|
|
edge_iterator ei;
|
|
|
|
|
size_t n;
|
|
|
|
|
size_t case_idx;
|
|
|
|
|
tree parm;
|
|
|
|
|
|
|
|
|
|
last = last_stmt (bb);
|
|
|
|
|
if (!last
|
|
|
|
|
|| gimple_code (last) != GIMPLE_SWITCH)
|
|
|
|
|
return;
|
|
|
|
|
op = gimple_switch_index (last);
|
|
|
|
|
parm = unmodified_parm (last, op);
|
|
|
|
|
if (!parm)
|
|
|
|
|
return;
|
|
|
|
|
index = ipa_get_param_decl_index (info, parm);
|
|
|
|
|
if (index == -1)
|
|
|
|
|
if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
|
|
|
@ -1554,18 +1674,12 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info,
|
|
|
|
|
if (!min && !max)
|
|
|
|
|
p = true_predicate ();
|
|
|
|
|
else if (!max)
|
|
|
|
|
p = add_condition (summary, index,
|
|
|
|
|
EQ_EXPR,
|
|
|
|
|
min);
|
|
|
|
|
p = add_condition (summary, index, &aggpos, EQ_EXPR, min);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct predicate p1, p2;
|
|
|
|
|
p1 = add_condition (summary, index,
|
|
|
|
|
GE_EXPR,
|
|
|
|
|
min);
|
|
|
|
|
p2 = add_condition (summary, index,
|
|
|
|
|
LE_EXPR,
|
|
|
|
|
max);
|
|
|
|
|
p1 = add_condition (summary, index, &aggpos, GE_EXPR, min);
|
|
|
|
|
p2 = add_condition (summary, index, &aggpos, LE_EXPR, max);
|
|
|
|
|
p = and_predicates (summary->conds, &p1, &p2);
|
|
|
|
|
}
|
|
|
|
|
*(struct predicate *)e->aux
|
|
|
|
@ -1659,13 +1773,14 @@ will_be_nonconstant_predicate (struct ipa_node_params *info,
|
|
|
|
|
struct inline_summary *summary,
|
|
|
|
|
gimple stmt,
|
|
|
|
|
VEC (predicate_t, heap) *nonconstant_names)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
struct predicate p = true_predicate ();
|
|
|
|
|
ssa_op_iter iter;
|
|
|
|
|
tree use;
|
|
|
|
|
struct predicate op_non_const;
|
|
|
|
|
bool is_load;
|
|
|
|
|
int base_index;
|
|
|
|
|
struct agg_position_info aggpos;
|
|
|
|
|
|
|
|
|
|
/* What statments might be optimized away
|
|
|
|
|
when their arguments are constant
|
|
|
|
@ -1681,23 +1796,18 @@ will_be_nonconstant_predicate (struct ipa_node_params *info,
|
|
|
|
|
return p;
|
|
|
|
|
|
|
|
|
|
is_load = gimple_vuse (stmt) != NULL;
|
|
|
|
|
|
|
|
|
|
/* Loads can be optimized when the value is known. */
|
|
|
|
|
if (is_load)
|
|
|
|
|
{
|
|
|
|
|
tree op = gimple_assign_rhs1 (stmt);
|
|
|
|
|
tree base = get_base_address (op);
|
|
|
|
|
tree parm;
|
|
|
|
|
|
|
|
|
|
tree op;
|
|
|
|
|
gcc_assert (gimple_assign_single_p (stmt));
|
|
|
|
|
if (!base)
|
|
|
|
|
return p;
|
|
|
|
|
parm = unmodified_parm (stmt, base);
|
|
|
|
|
if (!parm )
|
|
|
|
|
return p;
|
|
|
|
|
if (ipa_get_param_decl_index (info, parm) < 0)
|
|
|
|
|
op = gimple_assign_rhs1 (stmt);
|
|
|
|
|
if (!unmodified_parm_or_parm_agg_item (info, stmt, op, &base_index,
|
|
|
|
|
&aggpos))
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
base_index = -1;
|
|
|
|
|
|
|
|
|
|
/* See if we understand all operands before we start
|
|
|
|
|
adding conditionals. */
|
|
|
|
@ -1716,23 +1826,24 @@ will_be_nonconstant_predicate (struct ipa_node_params *info,
|
|
|
|
|
continue;
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
op_non_const = false_predicate ();
|
|
|
|
|
|
|
|
|
|
if (is_load)
|
|
|
|
|
{
|
|
|
|
|
tree parm = unmodified_parm
|
|
|
|
|
(stmt, get_base_address (gimple_assign_rhs1 (stmt)));
|
|
|
|
|
p = add_condition (summary,
|
|
|
|
|
ipa_get_param_decl_index (info, parm),
|
|
|
|
|
CHANGED, NULL);
|
|
|
|
|
op_non_const = or_predicates (summary->conds, &p, &op_non_const);
|
|
|
|
|
}
|
|
|
|
|
op_non_const = add_condition (summary, base_index, &aggpos, CHANGED, NULL);
|
|
|
|
|
else
|
|
|
|
|
op_non_const = false_predicate ();
|
|
|
|
|
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
|
|
|
|
|
{
|
|
|
|
|
tree parm = unmodified_parm (stmt, use);
|
|
|
|
|
if (parm && ipa_get_param_decl_index (info, parm) >= 0)
|
|
|
|
|
p = add_condition (summary,
|
|
|
|
|
ipa_get_param_decl_index (info, parm),
|
|
|
|
|
CHANGED, NULL);
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
if (parm
|
|
|
|
|
&& (index = ipa_get_param_decl_index (info, parm)) >= 0)
|
|
|
|
|
{
|
|
|
|
|
if (index != base_index)
|
|
|
|
|
p = add_condition (summary, index, NULL, CHANGED, NULL_TREE);
|
|
|
|
|
else
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
p = *VEC_index (predicate_t, nonconstant_names,
|
|
|
|
|
SSA_NAME_VERSION (use));
|
|
|
|
@ -2194,7 +2305,8 @@ static void
|
|
|
|
|
estimate_edge_devirt_benefit (struct cgraph_edge *ie,
|
|
|
|
|
int *size, int *time, int prob,
|
|
|
|
|
VEC (tree, heap) *known_vals,
|
|
|
|
|
VEC (tree, heap) *known_binfos)
|
|
|
|
|
VEC (tree, heap) *known_binfos,
|
|
|
|
|
VEC (ipa_agg_jump_function_p, heap) *known_aggs)
|
|
|
|
|
{
|
|
|
|
|
tree target;
|
|
|
|
|
int time_diff, size_diff;
|
|
|
|
@ -2202,7 +2314,8 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
|
|
|
|
|
if (!known_vals && !known_binfos)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos);
|
|
|
|
|
target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
|
|
|
|
|
known_aggs);
|
|
|
|
|
if (!target)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
@ -2259,7 +2372,8 @@ static void
|
|
|
|
|
estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
|
|
|
|
|
clause_t possible_truths,
|
|
|
|
|
VEC (tree, heap) *known_vals,
|
|
|
|
|
VEC (tree, heap) *known_binfos)
|
|
|
|
|
VEC (tree, heap) *known_binfos,
|
|
|
|
|
VEC (ipa_agg_jump_function_p, heap) *known_aggs)
|
|
|
|
|
{
|
|
|
|
|
struct cgraph_edge *e;
|
|
|
|
|
for (e = node->callees; e; e = e->next_callee)
|
|
|
|
@ -2276,7 +2390,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
|
|
|
|
|
else
|
|
|
|
|
estimate_calls_size_and_time (e->callee, size, time,
|
|
|
|
|
possible_truths,
|
|
|
|
|
known_vals, known_binfos);
|
|
|
|
|
known_vals, known_binfos, known_aggs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (e = node->indirect_calls; e; e = e->next_callee)
|
|
|
|
@ -2286,7 +2400,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
|
|
|
|
|
{
|
|
|
|
|
estimate_edge_size_and_time (e, size, time, REG_BR_PROB_BASE);
|
|
|
|
|
estimate_edge_devirt_benefit (e, size, time, REG_BR_PROB_BASE,
|
|
|
|
|
known_vals, known_binfos);
|
|
|
|
|
known_vals, known_binfos, known_aggs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2301,6 +2415,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
|
|
|
|
|
clause_t possible_truths,
|
|
|
|
|
VEC (tree, heap) *known_vals,
|
|
|
|
|
VEC (tree, heap) *known_binfos,
|
|
|
|
|
VEC (ipa_agg_jump_function_p, heap) *known_aggs,
|
|
|
|
|
int *ret_size, int *ret_time,
|
|
|
|
|
VEC (inline_param_summary_t, heap)
|
|
|
|
|
*inline_param_summary)
|
|
|
|
@ -2352,7 +2467,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
|
|
|
|
|
time = MAX_TIME * INLINE_TIME_SCALE;
|
|
|
|
|
|
|
|
|
|
estimate_calls_size_and_time (node, &size, &time, possible_truths,
|
|
|
|
|
known_vals, known_binfos);
|
|
|
|
|
known_vals, known_binfos, known_aggs);
|
|
|
|
|
time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
|
|
|
|
|
size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
|
|
|
|
|
|
|
|
|
@ -2381,27 +2496,31 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
|
|
|
|
|
{
|
|
|
|
|
clause_t clause;
|
|
|
|
|
|
|
|
|
|
clause = evaluate_conditions_for_known_args (node, false, known_vals);
|
|
|
|
|
estimate_node_size_and_time (node, clause, known_vals, known_binfos,
|
|
|
|
|
clause = evaluate_conditions_for_known_args (node, false, known_vals, NULL);
|
|
|
|
|
estimate_node_size_and_time (node, clause, known_vals, known_binfos, NULL,
|
|
|
|
|
ret_size, ret_time,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Translate all conditions from callee representation into caller
|
|
|
|
|
representation and symbolically evaluate predicate P into new predicate.
|
|
|
|
|
|
|
|
|
|
INFO is inline_summary of function we are adding predicate into,
|
|
|
|
|
CALLEE_INFO is summary of function predicate P is from. OPERAND_MAP is
|
|
|
|
|
array giving callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is
|
|
|
|
|
clausule of all callee conditions that may be true in caller context.
|
|
|
|
|
TOPLEV_PREDICATE is predicate under which callee is executed. */
|
|
|
|
|
INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
|
|
|
|
|
is summary of function predicate P is from. OPERAND_MAP is array giving
|
|
|
|
|
callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
|
|
|
|
|
callee conditions that may be true in caller context. TOPLEV_PREDICATE is
|
|
|
|
|
predicate under which callee is executed. OFFSET_MAP is an array of of
|
|
|
|
|
offsets that need to be added to conditions, negative offset means that
|
|
|
|
|
conditions relying on values passed by reference have to be discarded
|
|
|
|
|
because they might not be preserved (and should be considered offset zero
|
|
|
|
|
for other purposes). */
|
|
|
|
|
|
|
|
|
|
static struct predicate
|
|
|
|
|
remap_predicate (struct inline_summary *info,
|
|
|
|
|
struct inline_summary *callee_info,
|
|
|
|
|
struct predicate *p,
|
|
|
|
|
VEC (int, heap) *operand_map,
|
|
|
|
|
VEC (int, heap) *offset_map,
|
|
|
|
|
clause_t possible_truths,
|
|
|
|
|
struct predicate *toplev_predicate)
|
|
|
|
|
{
|
|
|
|
@ -2436,13 +2555,34 @@ remap_predicate (struct inline_summary *info,
|
|
|
|
|
Otherwise give up. */
|
|
|
|
|
if (!operand_map
|
|
|
|
|
|| (int)VEC_length (int, operand_map) <= c->operand_num
|
|
|
|
|
|| VEC_index (int, operand_map, c->operand_num) == -1)
|
|
|
|
|
|| VEC_index (int, operand_map, c->operand_num) == -1
|
|
|
|
|
|| (!c->agg_contents
|
|
|
|
|
&& VEC_index (int, offset_map, c->operand_num) != 0)
|
|
|
|
|
|| (c->agg_contents && c->by_ref
|
|
|
|
|
&& VEC_index (int, offset_map, c->operand_num) < 0))
|
|
|
|
|
cond_predicate = true_predicate ();
|
|
|
|
|
else
|
|
|
|
|
cond_predicate = add_condition (info,
|
|
|
|
|
VEC_index (int, operand_map,
|
|
|
|
|
c->operand_num),
|
|
|
|
|
c->code, c->val);
|
|
|
|
|
{
|
|
|
|
|
struct agg_position_info ap;
|
|
|
|
|
HOST_WIDE_INT offset_delta = VEC_index (int, offset_map,
|
|
|
|
|
c->operand_num);
|
|
|
|
|
if (offset_delta < 0)
|
|
|
|
|
{
|
|
|
|
|
gcc_checking_assert (!c->agg_contents || !c->by_ref);
|
|
|
|
|
offset_delta = 0;
|
|
|
|
|
}
|
|
|
|
|
gcc_assert (!c->agg_contents
|
|
|
|
|
|| c->by_ref
|
|
|
|
|
|| offset_delta == 0);
|
|
|
|
|
ap.offset = c->offset + offset_delta;
|
|
|
|
|
ap.agg_contents = c->agg_contents;
|
|
|
|
|
ap.by_ref = c->by_ref;
|
|
|
|
|
cond_predicate = add_condition (info,
|
|
|
|
|
VEC_index (int,
|
|
|
|
|
operand_map,
|
|
|
|
|
c->operand_num),
|
|
|
|
|
&ap, c->code, c->val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Fixed conditions remains same, construct single
|
|
|
|
|
condition predicate. */
|
|
|
|
@ -2549,6 +2689,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
|
|
|
|
|
struct inline_summary *info,
|
|
|
|
|
struct inline_summary *callee_info,
|
|
|
|
|
VEC (int, heap) *operand_map,
|
|
|
|
|
VEC (int, heap) *offset_map,
|
|
|
|
|
clause_t possible_truths,
|
|
|
|
|
struct predicate *toplev_predicate)
|
|
|
|
|
{
|
|
|
|
@ -2565,7 +2706,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
|
|
|
|
|
if (es->predicate)
|
|
|
|
|
{
|
|
|
|
|
p = remap_predicate (info, callee_info,
|
|
|
|
|
es->predicate, operand_map, possible_truths,
|
|
|
|
|
es->predicate, operand_map, offset_map,
|
|
|
|
|
possible_truths,
|
|
|
|
|
toplev_predicate);
|
|
|
|
|
edge_set_predicate (e, &p);
|
|
|
|
|
/* TODO: We should remove the edge for code that will be
|
|
|
|
@ -2582,7 +2724,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
|
|
|
|
|
operand_map, possible_truths, toplev_predicate);
|
|
|
|
|
operand_map, offset_map, possible_truths,
|
|
|
|
|
toplev_predicate);
|
|
|
|
|
}
|
|
|
|
|
for (e = node->indirect_calls; e; e = e->next_callee)
|
|
|
|
|
{
|
|
|
|
@ -2593,8 +2736,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
|
|
|
|
|
if (es->predicate)
|
|
|
|
|
{
|
|
|
|
|
p = remap_predicate (info, callee_info,
|
|
|
|
|
es->predicate, operand_map, possible_truths,
|
|
|
|
|
toplev_predicate);
|
|
|
|
|
es->predicate, operand_map, offset_map,
|
|
|
|
|
possible_truths, toplev_predicate);
|
|
|
|
|
edge_set_predicate (e, &p);
|
|
|
|
|
/* TODO: We should remove the edge for code that will be optimized
|
|
|
|
|
out, but we need to keep verifiers and tree-inline happy.
|
|
|
|
@ -2623,6 +2766,7 @@ inline_merge_summary (struct cgraph_edge *edge)
|
|
|
|
|
clause_t clause = 0; /* not_inline is known to be false. */
|
|
|
|
|
size_time_entry *e;
|
|
|
|
|
VEC (int, heap) *operand_map = NULL;
|
|
|
|
|
VEC (int, heap) *offset_map = NULL;
|
|
|
|
|
int i;
|
|
|
|
|
struct predicate toplev_predicate;
|
|
|
|
|
struct predicate true_p = true_predicate ();
|
|
|
|
@ -2639,17 +2783,36 @@ inline_merge_summary (struct cgraph_edge *edge)
|
|
|
|
|
int count = ipa_get_cs_argument_count (args);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
evaluate_properties_for_edge (edge, true, &clause, NULL, NULL);
|
|
|
|
|
evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL);
|
|
|
|
|
if (count)
|
|
|
|
|
VEC_safe_grow_cleared (int, heap, operand_map, count);
|
|
|
|
|
{
|
|
|
|
|
VEC_safe_grow_cleared (int, heap, operand_map, count);
|
|
|
|
|
VEC_safe_grow_cleared (int, heap, offset_map, count);
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
|
|
|
|
|
int map = -1;
|
|
|
|
|
|
|
|
|
|
/* TODO: handle non-NOPs when merging. */
|
|
|
|
|
if (jfunc->type == IPA_JF_PASS_THROUGH
|
|
|
|
|
&& ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
|
|
|
|
|
map = ipa_get_jf_pass_through_formal_id (jfunc);
|
|
|
|
|
if (jfunc->type == IPA_JF_PASS_THROUGH)
|
|
|
|
|
{
|
|
|
|
|
if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
|
|
|
|
|
map = ipa_get_jf_pass_through_formal_id (jfunc);
|
|
|
|
|
if (!ipa_get_jf_pass_through_agg_preserved (jfunc))
|
|
|
|
|
VEC_replace (int, offset_map, i, -1);
|
|
|
|
|
}
|
|
|
|
|
else if (jfunc->type == IPA_JF_ANCESTOR)
|
|
|
|
|
{
|
|
|
|
|
HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
|
|
|
|
|
if (offset >= 0 && offset < INT_MAX)
|
|
|
|
|
{
|
|
|
|
|
map = ipa_get_jf_ancestor_formal_id (jfunc);
|
|
|
|
|
if (!ipa_get_jf_ancestor_agg_preserved (jfunc))
|
|
|
|
|
offset = -1;
|
|
|
|
|
VEC_replace (int, offset_map, i, offset);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
VEC_replace (int, operand_map, i, map);
|
|
|
|
|
gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
|
|
|
|
|
}
|
|
|
|
@ -2657,7 +2820,8 @@ inline_merge_summary (struct cgraph_edge *edge)
|
|
|
|
|
for (i = 0; VEC_iterate (size_time_entry, callee_info->entry, i, e); i++)
|
|
|
|
|
{
|
|
|
|
|
struct predicate p = remap_predicate (info, callee_info,
|
|
|
|
|
&e->predicate, operand_map, clause,
|
|
|
|
|
&e->predicate, operand_map,
|
|
|
|
|
offset_map, clause,
|
|
|
|
|
&toplev_predicate);
|
|
|
|
|
if (!false_predicate_p (&p))
|
|
|
|
|
{
|
|
|
|
@ -2679,7 +2843,7 @@ inline_merge_summary (struct cgraph_edge *edge)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
|
|
|
|
|
clause, &toplev_predicate);
|
|
|
|
|
offset_map, clause, &toplev_predicate);
|
|
|
|
|
|
|
|
|
|
inline_update_callee_summaries (edge->callee,
|
|
|
|
|
inline_edge_summary (edge)->loop_depth);
|
|
|
|
@ -2689,6 +2853,7 @@ inline_merge_summary (struct cgraph_edge *edge)
|
|
|
|
|
/* Similarly remove param summaries. */
|
|
|
|
|
VEC_free (inline_param_summary_t, heap, es->param);
|
|
|
|
|
VEC_free (int, heap, operand_map);
|
|
|
|
|
VEC_free (int, heap, offset_map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For performance reasons inline_merge_summary is not updating overall size
|
|
|
|
@ -2707,7 +2872,7 @@ inline_update_overall_summary (struct cgraph_node *node)
|
|
|
|
|
info->size += e->size, info->time += e->time;
|
|
|
|
|
estimate_calls_size_and_time (node, &info->size, &info->time,
|
|
|
|
|
~(clause_t)(1 << predicate_false_condition),
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
|
|
|
|
|
info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
|
|
|
|
|
}
|
|
|
|
@ -2729,17 +2894,20 @@ do_estimate_edge_time (struct cgraph_edge *edge)
|
|
|
|
|
clause_t clause;
|
|
|
|
|
VEC (tree, heap) *known_vals;
|
|
|
|
|
VEC (tree, heap) *known_binfos;
|
|
|
|
|
VEC (ipa_agg_jump_function_p, heap) *known_aggs;
|
|
|
|
|
struct inline_edge_summary *es = inline_edge_summary (edge);
|
|
|
|
|
|
|
|
|
|
callee = cgraph_function_or_thunk_node (edge->callee, NULL);
|
|
|
|
|
|
|
|
|
|
gcc_checking_assert (edge->inline_failed);
|
|
|
|
|
evaluate_properties_for_edge (edge, true,
|
|
|
|
|
&clause, &known_vals, &known_binfos);
|
|
|
|
|
&clause, &known_vals, &known_binfos,
|
|
|
|
|
&known_aggs);
|
|
|
|
|
estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
|
|
|
|
|
&size, &time, es->param);
|
|
|
|
|
known_aggs, &size, &time, es->param);
|
|
|
|
|
VEC_free (tree, heap, known_vals);
|
|
|
|
|
VEC_free (tree, heap, known_binfos);
|
|
|
|
|
VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
|
|
|
|
|
|
|
|
|
|
ret = (((gcov_type)time
|
|
|
|
|
- es->call_stmt_time) * edge->frequency
|
|
|
|
@ -2776,6 +2944,7 @@ do_estimate_edge_growth (struct cgraph_edge *edge)
|
|
|
|
|
clause_t clause;
|
|
|
|
|
VEC (tree, heap) *known_vals;
|
|
|
|
|
VEC (tree, heap) *known_binfos;
|
|
|
|
|
VEC (ipa_agg_jump_function_p, heap) *known_aggs;
|
|
|
|
|
|
|
|
|
|
/* When we do caching, use do_estimate_edge_time to populate the entry. */
|
|
|
|
|
|
|
|
|
@ -2794,11 +2963,13 @@ do_estimate_edge_growth (struct cgraph_edge *edge)
|
|
|
|
|
/* 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, &known_vals, &known_binfos);
|
|
|
|
|
&clause, &known_vals, &known_binfos,
|
|
|
|
|
&known_aggs);
|
|
|
|
|
estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
|
|
|
|
|
&size, NULL, NULL);
|
|
|
|
|
known_aggs, &size, NULL, NULL);
|
|
|
|
|
VEC_free (tree, heap, known_vals);
|
|
|
|
|
VEC_free (tree, heap, known_binfos);
|
|
|
|
|
VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
|
|
|
|
|
gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
|
|
|
|
|
return size - inline_edge_summary (edge)->call_stmt_size;
|
|
|
|
|
}
|
|
|
|
@ -3078,6 +3249,11 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
|
|
|
|
|
c.operand_num = streamer_read_uhwi (&ib);
|
|
|
|
|
c.code = (enum tree_code) streamer_read_uhwi (&ib);
|
|
|
|
|
c.val = stream_read_tree (&ib, data_in);
|
|
|
|
|
bp = streamer_read_bitpack (&ib);
|
|
|
|
|
c.agg_contents = bp_unpack_value (&bp, 1);
|
|
|
|
|
c.by_ref = bp_unpack_value (&bp, 1);
|
|
|
|
|
if (c.agg_contents)
|
|
|
|
|
c.offset = streamer_read_uhwi (&ib);
|
|
|
|
|
VEC_safe_push (condition, gc, info->conds, &c);
|
|
|
|
|
}
|
|
|
|
|
count2 = streamer_read_uhwi (&ib);
|
|
|
|
@ -3223,6 +3399,12 @@ inline_write_summary (cgraph_node_set set,
|
|
|
|
|
streamer_write_uhwi (ob, c->operand_num);
|
|
|
|
|
streamer_write_uhwi (ob, c->code);
|
|
|
|
|
stream_write_tree (ob, c->val, true);
|
|
|
|
|
bp = bitpack_create (ob->main_stream);
|
|
|
|
|
bp_pack_value (&bp, c->agg_contents, 1);
|
|
|
|
|
bp_pack_value (&bp, c->by_ref, 1);
|
|
|
|
|
streamer_write_bitpack (&bp);
|
|
|
|
|
if (c->agg_contents)
|
|
|
|
|
streamer_write_uhwi (ob, c->offset);
|
|
|
|
|
}
|
|
|
|
|
streamer_write_uhwi (ob, VEC_length (size_time_entry, info->entry));
|
|
|
|
|
for (i = 0;
|
|
|
|
|