Commit 8810cc52 by Martin Jambor Committed by Martin Jambor

re PR fortran/48636 (Enable more inlining with -O2 and higher)

2012-08-11  Martin Jambor  <mjambor@suse.cz>

	PR fortran/48636
	* ipa-inline.h (condition): New fields offset, agg_contents and by_ref.
	* ipa-inline-analysis.c (agg_position_info): New type.
	(add_condition): New parameter aggpos, also store agg_contents, by_ref
	and offset.
	(dump_condition): Also dump aggregate conditions.
	(evaluate_conditions_for_known_args): Also handle aggregate
	conditions.  New parameter known_aggs.
	(evaluate_properties_for_edge): Gather known aggregate contents.
	(inline_node_duplication_hook): Pass NULL known_aggs to
	evaluate_conditions_for_known_args.
	(unmodified_parm): Split into unmodified_parm and unmodified_parm_1.
	(unmodified_parm_or_parm_agg_item): New function.
	(set_cond_stmt_execution_predicate): Handle values passed in
	aggregates.
	(set_switch_stmt_execution_predicate): Likewise.
	(will_be_nonconstant_predicate): Likewise.
	(estimate_edge_devirt_benefit): Pass new parameter known_aggs to
	ipa_get_indirect_edge_target.
	(estimate_calls_size_and_time): New parameter known_aggs, pass it
	recrsively to itself and to estimate_edge_devirt_benefit.
	(estimate_node_size_and_time): New vector known_aggs, pass it o
	functions which need it.
	(remap_predicate): New parameter offset_map, use it to remap aggregate
	conditions.
	(remap_edge_summaries): New parameter offset_map, pass it recursively
	to itself and to remap_predicate.
	(inline_merge_summary): Also create and populate vector offset_map.
	(do_estimate_edge_time): New vector of known aggregate contents,
	passed to functions which need it.
	(inline_read_section): Stream new fields of condition.
	(inline_write_summary): Likewise.
	* ipa-cp.c (ipa_get_indirect_edge_target): Also examine the aggregate
	contents.  Let all local callers pass NULL for known_aggs.

	* testsuite/gfortran.dg/pr48636.f90: New test.

From-SVN: r190313
parent ab96cc5b
2012-08-11 Martin Jambor <mjambor@suse.cz>
PR fortran/48636
* ipa-inline.h (condition): New fields offset, agg_contents and by_ref.
* ipa-inline-analysis.c (agg_position_info): New type.
(add_condition): New parameter aggpos, also store agg_contents, by_ref
and offset.
(dump_condition): Also dump aggregate conditions.
(evaluate_conditions_for_known_args): Also handle aggregate
conditions. New parameter known_aggs.
(evaluate_properties_for_edge): Gather known aggregate contents.
(inline_node_duplication_hook): Pass NULL known_aggs to
evaluate_conditions_for_known_args.
(unmodified_parm): Split into unmodified_parm and unmodified_parm_1.
(unmodified_parm_or_parm_agg_item): New function.
(set_cond_stmt_execution_predicate): Handle values passed in
aggregates.
(set_switch_stmt_execution_predicate): Likewise.
(will_be_nonconstant_predicate): Likewise.
(estimate_edge_devirt_benefit): Pass new parameter known_aggs to
ipa_get_indirect_edge_target.
(estimate_calls_size_and_time): New parameter known_aggs, pass it
recrsively to itself and to estimate_edge_devirt_benefit.
(estimate_node_size_and_time): New vector known_aggs, pass it o
functions which need it.
(remap_predicate): New parameter offset_map, use it to remap aggregate
conditions.
(remap_edge_summaries): New parameter offset_map, pass it recursively
to itself and to remap_predicate.
(inline_merge_summary): Also create and populate vector offset_map.
(do_estimate_edge_time): New vector of known aggregate contents,
passed to functions which need it.
(inline_read_section): Stream new fields of condition.
(inline_write_summary): Likewise.
* ipa-cp.c (ipa_get_indirect_edge_target): Also examine the aggregate
contents. Let all local callers pass NULL for known_aggs.
2012-08-11 Jan Hubicka <jh@suse.cz> 2012-08-11 Jan Hubicka <jh@suse.cz>
* lto-cgraph.c (output_cgraph): Rename to ... * lto-cgraph.c (output_cgraph): Rename to ...
......
...@@ -1084,7 +1084,8 @@ propagate_constants_accross_call (struct cgraph_edge *cs) ...@@ -1084,7 +1084,8 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
tree tree
ipa_get_indirect_edge_target (struct cgraph_edge *ie, ipa_get_indirect_edge_target (struct cgraph_edge *ie,
VEC (tree, heap) *known_vals, VEC (tree, heap) *known_vals,
VEC (tree, heap) *known_binfos) VEC (tree, heap) *known_binfos,
VEC (ipa_agg_jump_function_p, heap) *known_aggs)
{ {
int param_index = ie->indirect_info->param_index; int param_index = ie->indirect_info->param_index;
HOST_WIDE_INT token, anc_offset; HOST_WIDE_INT token, anc_offset;
...@@ -1096,8 +1097,26 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie, ...@@ -1096,8 +1097,26 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie,
if (!ie->indirect_info->polymorphic) if (!ie->indirect_info->polymorphic)
{ {
tree t = (VEC_length (tree, known_vals) > (unsigned int) param_index tree t;
? VEC_index (tree, known_vals, param_index) : NULL);
if (ie->indirect_info->agg_contents)
{
if (VEC_length (ipa_agg_jump_function_p, known_aggs)
> (unsigned int) param_index)
{
struct ipa_agg_jump_function *agg;
agg = VEC_index (ipa_agg_jump_function_p, known_aggs,
param_index);
t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset,
ie->indirect_info->by_ref);
}
else
t = NULL;
}
else
t = (VEC_length (tree, known_vals) > (unsigned int) param_index
? VEC_index (tree, known_vals, param_index) : NULL);
if (t && if (t &&
TREE_CODE (t) == ADDR_EXPR TREE_CODE (t) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL) && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
...@@ -1106,6 +1125,7 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie, ...@@ -1106,6 +1125,7 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie,
return NULL_TREE; return NULL_TREE;
} }
gcc_assert (!ie->indirect_info->agg_contents);
token = ie->indirect_info->otr_token; token = ie->indirect_info->otr_token;
anc_offset = ie->indirect_info->offset; anc_offset = ie->indirect_info->offset;
otr_type = ie->indirect_info->otr_type; otr_type = ie->indirect_info->otr_type;
...@@ -1156,7 +1176,8 @@ devirtualization_time_bonus (struct cgraph_node *node, ...@@ -1156,7 +1176,8 @@ devirtualization_time_bonus (struct cgraph_node *node,
struct inline_summary *isummary; struct inline_summary *isummary;
tree target; tree target;
target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos); target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
NULL);
if (!target) if (!target)
continue; continue;
...@@ -1673,7 +1694,7 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node, ...@@ -1673,7 +1694,7 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node,
tree target; tree target;
next_ie = ie->next_callee; next_ie = ie->next_callee;
target = ipa_get_indirect_edge_target (ie, known_vals, NULL); target = ipa_get_indirect_edge_target (ie, known_vals, NULL, NULL);
if (target) if (target)
ipa_make_edge_direct_to_target (ie, target); ipa_make_edge_direct_to_target (ie, target);
} }
......
...@@ -203,22 +203,54 @@ not_inlined_predicate (void) ...@@ -203,22 +203,54 @@ not_inlined_predicate (void)
return single_cond_predicate (predicate_not_inlined_condition); 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 static struct predicate
add_condition (struct inline_summary *summary, int operand_num, add_condition (struct inline_summary *summary, int operand_num,
struct agg_position_info *aggpos,
enum tree_code code, tree val) enum tree_code code, tree val)
{ {
int i; int i;
struct condition *c; struct condition *c;
struct condition new_cond; 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++) for (i = 0; VEC_iterate (condition, summary->conds, i, c); i++)
{ {
if (c->operand_num == operand_num if (c->operand_num == operand_num
&& c->code == code && 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); return single_cond_predicate (i + predicate_first_dynamic_condition);
} }
/* Too many conditions. Give up and return constant true. */ /* Too many conditions. Give up and return constant true. */
...@@ -228,6 +260,9 @@ add_condition (struct inline_summary *summary, int operand_num, ...@@ -228,6 +260,9 @@ add_condition (struct inline_summary *summary, int operand_num,
new_cond.operand_num = operand_num; new_cond.operand_num = operand_num;
new_cond.code = code; new_cond.code = code;
new_cond.val = val; 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); VEC_safe_push (condition, gc, summary->conds, &new_cond);
return single_cond_predicate (i + predicate_first_dynamic_condition); return single_cond_predicate (i + predicate_first_dynamic_condition);
} }
...@@ -519,6 +554,9 @@ dump_condition (FILE *f, conditions conditions, int cond) ...@@ -519,6 +554,9 @@ dump_condition (FILE *f, conditions conditions, int cond)
c = VEC_index (condition, conditions, c = VEC_index (condition, conditions,
cond - predicate_first_dynamic_condition); cond - predicate_first_dynamic_condition);
fprintf (f, "op%i", c->operand_num); 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) if (c->code == IS_NOT_CONSTANT)
{ {
fprintf (f, " not constant"); fprintf (f, " not constant");
...@@ -659,15 +697,17 @@ edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate) ...@@ -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. /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
Return clause of possible truths. When INLINE_P is true, assume that KNOWN_AGGS is a vector of aggreggate jump functions for each parameter.
we are inlining. Return clause of possible truths. When INLINE_P is true, assume that we are
inlining.
ERROR_MARK means compile time invariant. */ ERROR_MARK means compile time invariant. */
static clause_t static clause_t
evaluate_conditions_for_known_args (struct cgraph_node *node, evaluate_conditions_for_known_args (struct cgraph_node *node,
bool inline_p, bool inline_p,
VEC (tree, heap) *known_vals) 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; clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
struct inline_summary *info = inline_summary (node); struct inline_summary *info = inline_summary (node);
...@@ -679,16 +719,45 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -679,16 +719,45 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
tree val; tree val;
tree res; tree res;
/* We allow call stmt to have fewer arguments than the callee /* We allow call stmt to have fewer arguments than the callee function
function (especially for K&R style programs). So bound (especially for K&R style programs). So bound check here (we assume
check here. */ known_aggs vector, if non-NULL, has the same length as
if (c->operand_num < (int)VEC_length (tree, known_vals)) known_vals). */
val = VEC_index (tree, known_vals, c->operand_num); gcc_checking_assert (!known_aggs
else || (VEC_length (tree, known_vals)
val = NULL; == 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) if (c->agg_contents)
val = NULL; {
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) if (!val)
{ {
...@@ -711,13 +780,15 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -711,13 +780,15 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
static void static void
evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
clause_t *clause_ptr, clause_t *clause_ptr,
VEC (tree, heap) **known_vals_ptr, VEC (tree, heap) **known_vals_ptr,
VEC (tree, heap) **known_binfos_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 cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL);
struct inline_summary *info = inline_summary (callee); struct inline_summary *info = inline_summary (callee);
VEC (tree, heap) *known_vals = NULL; VEC (tree, heap) *known_vals = NULL;
VEC (ipa_agg_jump_function_p, heap) *known_aggs = NULL;
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;
...@@ -742,13 +813,16 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -742,13 +813,16 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
if (count && (info->conds || known_vals_ptr)) if (count && (info->conds || known_vals_ptr))
VEC_safe_grow_cleared (tree, heap, known_vals, count); 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) if (count && known_binfos_ptr)
VEC_safe_grow_cleared (tree, heap, *known_binfos_ptr, count); VEC_safe_grow_cleared (tree, heap, *known_binfos_ptr, count);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
tree cst = ipa_value_from_jfunc (parms_info, struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i);
ipa_get_ith_jump_func (args, i)); tree cst = ipa_value_from_jfunc (parms_info, jf);
if (cst) if (cst)
{ {
if (known_vals && TREE_CODE (cst) != TREE_BINFO) if (known_vals && TREE_CODE (cst) != TREE_BINFO)
...@@ -761,17 +835,26 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -761,17 +835,26 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
es->param, es->param,
i)->change_prob) i)->change_prob)
VEC_replace (tree, known_vals, i, error_mark_node); 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) if (clause_ptr)
*clause_ptr = evaluate_conditions_for_known_args (callee, inline_p, *clause_ptr = evaluate_conditions_for_known_args (callee, inline_p,
known_vals); known_vals, known_aggs);
if (known_vals_ptr) if (known_vals_ptr)
*known_vals_ptr = known_vals; *known_vals_ptr = known_vals;
else else
VEC_free (tree, heap, known_vals); 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, ...@@ -917,8 +1000,8 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
} }
} }
} }
possible_truths = evaluate_conditions_for_known_args (dst, possible_truths = evaluate_conditions_for_known_args (dst, false,
false, known_vals); known_vals, NULL);
VEC_free (tree, heap, known_vals); VEC_free (tree, heap, known_vals);
account_size_time (info, 0, 0, &true_pred); account_size_time (info, 0, 0, &true_pred);
...@@ -1262,11 +1345,11 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED, ...@@ -1262,11 +1345,11 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
return true; return true;
} }
/* If OP reffers to value of function parameter, return /* If OP refers to value of function parameter, return the corresponding
the corresponding parameter. */ parameter. */
static tree static tree
unmodified_parm (gimple stmt, tree op) unmodified_parm_1 (gimple stmt, tree op)
{ {
/* SSA_NAME referring to parm default def? */ /* SSA_NAME referring to parm default def? */
if (TREE_CODE (op) == SSA_NAME if (TREE_CODE (op) == SSA_NAME
...@@ -1285,13 +1368,67 @@ unmodified_parm (gimple stmt, tree op) ...@@ -1285,13 +1368,67 @@ unmodified_parm (gimple stmt, tree op)
if (!modified) if (!modified)
return op; 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 if (TREE_CODE (op) == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (op) && !SSA_NAME_IS_DEFAULT_DEF (op)
&& gimple_assign_single_p (SSA_NAME_DEF_STMT (op))) && gimple_assign_single_p (SSA_NAME_DEF_STMT (op)))
return unmodified_parm (SSA_NAME_DEF_STMT (op), return unmodified_parm (SSA_NAME_DEF_STMT (op),
gimple_assign_rhs1 (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. /* See if statement might disappear after inlining.
...@@ -1422,13 +1559,12 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info, ...@@ -1422,13 +1559,12 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
gimple last; gimple last;
tree op; tree op;
int index; int index;
struct agg_position_info aggpos;
enum tree_code code, inverted_code; enum tree_code code, inverted_code;
edge e; edge e;
edge_iterator ei; edge_iterator ei;
gimple set_stmt; gimple set_stmt;
tree op2; tree op2;
tree parm;
tree base;
last = last_stmt (bb); last = last_stmt (bb);
if (!last if (!last
...@@ -1440,12 +1576,8 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info, ...@@ -1440,12 +1576,8 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
/* TODO: handle conditionals like /* TODO: handle conditionals like
var = op0 < 4; var = op0 < 4;
if (var != 0). */ if (var != 0). */
parm = unmodified_parm (last, op); if (unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
if (parm)
{ {
index = ipa_get_param_decl_index (info, parm);
if (index == -1)
return;
code = gimple_cond_code (last); code = gimple_cond_code (last);
inverted_code inverted_code
= invert_tree_comparison (code, = invert_tree_comparison (code,
...@@ -1453,8 +1585,7 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info, ...@@ -1453,8 +1585,7 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
{ {
struct predicate p = add_condition (summary, struct predicate p = add_condition (summary, index, &aggpos,
index,
e->flags & EDGE_TRUE_VALUE e->flags & EDGE_TRUE_VALUE
? code : inverted_code, ? code : inverted_code,
gimple_cond_rhs (last)); gimple_cond_rhs (last));
...@@ -1475,28 +1606,21 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info, ...@@ -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 for this and also the constant code is not known to be
optimized away when inliner doen't see operand is constant. optimized away when inliner doen't see operand is constant.
Other optimizers might think otherwise. */ 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); set_stmt = SSA_NAME_DEF_STMT (op);
if (!gimple_call_builtin_p (set_stmt, BUILT_IN_CONSTANT_P) if (!gimple_call_builtin_p (set_stmt, BUILT_IN_CONSTANT_P)
|| gimple_call_num_args (set_stmt) != 1) || gimple_call_num_args (set_stmt) != 1)
return; return;
op2 = gimple_call_arg (set_stmt, 0); op2 = gimple_call_arg (set_stmt, 0);
base = get_base_address (op2); if (!unmodified_parm_or_parm_agg_item (info, set_stmt, op2, &index, &aggpos))
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)))
return; return;
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALSE_VALUE) if (e->flags & EDGE_FALSE_VALUE)
{ {
struct predicate p = add_condition (summary, struct predicate p = add_condition (summary, index, &aggpos,
index, IS_NOT_CONSTANT, NULL_TREE);
IS_NOT_CONSTANT,
NULL);
e->aux = pool_alloc (edge_predicate_pool); e->aux = pool_alloc (edge_predicate_pool);
*(struct predicate *)e->aux = p; *(struct predicate *)e->aux = p;
} }
...@@ -1514,22 +1638,18 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info, ...@@ -1514,22 +1638,18 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info,
gimple last; gimple last;
tree op; tree op;
int index; int index;
struct agg_position_info aggpos;
edge e; edge e;
edge_iterator ei; edge_iterator ei;
size_t n; size_t n;
size_t case_idx; size_t case_idx;
tree parm;
last = last_stmt (bb); last = last_stmt (bb);
if (!last if (!last
|| gimple_code (last) != GIMPLE_SWITCH) || gimple_code (last) != GIMPLE_SWITCH)
return; return;
op = gimple_switch_index (last); op = gimple_switch_index (last);
parm = unmodified_parm (last, op); if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
if (!parm)
return;
index = ipa_get_param_decl_index (info, parm);
if (index == -1)
return; return;
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
...@@ -1554,18 +1674,12 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info, ...@@ -1554,18 +1674,12 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info,
if (!min && !max) if (!min && !max)
p = true_predicate (); p = true_predicate ();
else if (!max) else if (!max)
p = add_condition (summary, index, p = add_condition (summary, index, &aggpos, EQ_EXPR, min);
EQ_EXPR,
min);
else else
{ {
struct predicate p1, p2; struct predicate p1, p2;
p1 = add_condition (summary, index, p1 = add_condition (summary, index, &aggpos, GE_EXPR, min);
GE_EXPR, p2 = add_condition (summary, index, &aggpos, LE_EXPR, max);
min);
p2 = add_condition (summary, index,
LE_EXPR,
max);
p = and_predicates (summary->conds, &p1, &p2); p = and_predicates (summary->conds, &p1, &p2);
} }
*(struct predicate *)e->aux *(struct predicate *)e->aux
...@@ -1659,13 +1773,14 @@ will_be_nonconstant_predicate (struct ipa_node_params *info, ...@@ -1659,13 +1773,14 @@ will_be_nonconstant_predicate (struct ipa_node_params *info,
struct inline_summary *summary, struct inline_summary *summary,
gimple stmt, gimple stmt,
VEC (predicate_t, heap) *nonconstant_names) VEC (predicate_t, heap) *nonconstant_names)
{ {
struct predicate p = true_predicate (); struct predicate p = true_predicate ();
ssa_op_iter iter; ssa_op_iter iter;
tree use; tree use;
struct predicate op_non_const; struct predicate op_non_const;
bool is_load; bool is_load;
int base_index;
struct agg_position_info aggpos;
/* What statments might be optimized away /* What statments might be optimized away
when their arguments are constant when their arguments are constant
...@@ -1681,23 +1796,18 @@ will_be_nonconstant_predicate (struct ipa_node_params *info, ...@@ -1681,23 +1796,18 @@ will_be_nonconstant_predicate (struct ipa_node_params *info,
return p; return p;
is_load = gimple_vuse (stmt) != NULL; is_load = gimple_vuse (stmt) != NULL;
/* Loads can be optimized when the value is known. */ /* Loads can be optimized when the value is known. */
if (is_load) if (is_load)
{ {
tree op = gimple_assign_rhs1 (stmt); tree op;
tree base = get_base_address (op);
tree parm;
gcc_assert (gimple_assign_single_p (stmt)); gcc_assert (gimple_assign_single_p (stmt));
if (!base) op = gimple_assign_rhs1 (stmt);
return p; if (!unmodified_parm_or_parm_agg_item (info, stmt, op, &base_index,
parm = unmodified_parm (stmt, base); &aggpos))
if (!parm )
return p;
if (ipa_get_param_decl_index (info, parm) < 0)
return p; return p;
} }
else
base_index = -1;
/* See if we understand all operands before we start /* See if we understand all operands before we start
adding conditionals. */ adding conditionals. */
...@@ -1716,23 +1826,24 @@ will_be_nonconstant_predicate (struct ipa_node_params *info, ...@@ -1716,23 +1826,24 @@ will_be_nonconstant_predicate (struct ipa_node_params *info,
continue; continue;
return p; return p;
} }
op_non_const = false_predicate ();
if (is_load) if (is_load)
{ op_non_const = add_condition (summary, base_index, &aggpos, CHANGED, NULL);
tree parm = unmodified_parm else
(stmt, get_base_address (gimple_assign_rhs1 (stmt))); op_non_const = false_predicate ();
p = add_condition (summary,
ipa_get_param_decl_index (info, parm),
CHANGED, NULL);
op_non_const = or_predicates (summary->conds, &p, &op_non_const);
}
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
{ {
tree parm = unmodified_parm (stmt, use); tree parm = unmodified_parm (stmt, use);
if (parm && ipa_get_param_decl_index (info, parm) >= 0) int index;
p = add_condition (summary,
ipa_get_param_decl_index (info, parm), if (parm
CHANGED, NULL); && (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 else
p = *VEC_index (predicate_t, nonconstant_names, p = *VEC_index (predicate_t, nonconstant_names,
SSA_NAME_VERSION (use)); SSA_NAME_VERSION (use));
...@@ -2194,7 +2305,8 @@ static void ...@@ -2194,7 +2305,8 @@ static void
estimate_edge_devirt_benefit (struct cgraph_edge *ie, estimate_edge_devirt_benefit (struct cgraph_edge *ie,
int *size, int *time, int prob, int *size, int *time, int prob,
VEC (tree, heap) *known_vals, 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; tree target;
int time_diff, size_diff; int time_diff, size_diff;
...@@ -2202,7 +2314,8 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie, ...@@ -2202,7 +2314,8 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
if (!known_vals && !known_binfos) if (!known_vals && !known_binfos)
return; 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) if (!target)
return; return;
...@@ -2259,7 +2372,8 @@ static void ...@@ -2259,7 +2372,8 @@ static void
estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time, estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
clause_t possible_truths, clause_t possible_truths,
VEC (tree, heap) *known_vals, 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; struct cgraph_edge *e;
for (e = node->callees; e; e = e->next_callee) 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, ...@@ -2276,7 +2390,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
else else
estimate_calls_size_and_time (e->callee, size, time, estimate_calls_size_and_time (e->callee, size, time,
possible_truths, possible_truths,
known_vals, known_binfos); known_vals, known_binfos, known_aggs);
} }
} }
for (e = node->indirect_calls; e; e = e->next_callee) 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, ...@@ -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_size_and_time (e, size, time, REG_BR_PROB_BASE);
estimate_edge_devirt_benefit (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, ...@@ -2301,6 +2415,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
clause_t possible_truths, clause_t possible_truths,
VEC (tree, heap) *known_vals, VEC (tree, heap) *known_vals,
VEC (tree, heap) *known_binfos, VEC (tree, heap) *known_binfos,
VEC (ipa_agg_jump_function_p, heap) *known_aggs,
int *ret_size, int *ret_time, int *ret_size, int *ret_time,
VEC (inline_param_summary_t, heap) VEC (inline_param_summary_t, heap)
*inline_param_summary) *inline_param_summary)
...@@ -2352,7 +2467,7 @@ estimate_node_size_and_time (struct cgraph_node *node, ...@@ -2352,7 +2467,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
time = MAX_TIME * INLINE_TIME_SCALE; time = MAX_TIME * INLINE_TIME_SCALE;
estimate_calls_size_and_time (node, &size, &time, possible_truths, 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; time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE; size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
...@@ -2381,27 +2496,31 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node, ...@@ -2381,27 +2496,31 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
{ {
clause_t clause; clause_t clause;
clause = evaluate_conditions_for_known_args (node, false, known_vals); clause = evaluate_conditions_for_known_args (node, false, known_vals, NULL);
estimate_node_size_and_time (node, clause, known_vals, known_binfos, estimate_node_size_and_time (node, clause, known_vals, known_binfos, NULL,
ret_size, ret_time, ret_size, ret_time,
NULL); NULL);
} }
/* Translate all conditions from callee representation into caller /* Translate all conditions from callee representation into caller
representation and symbolically evaluate predicate P into new predicate. representation and symbolically evaluate predicate P into new predicate.
INFO is inline_summary of function we are adding predicate into, INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
CALLEE_INFO is summary of function predicate P is from. OPERAND_MAP is is summary of function predicate P is from. OPERAND_MAP is array giving
array giving callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
clausule of all callee conditions that may be true in caller context. callee conditions that may be true in caller context. TOPLEV_PREDICATE is
TOPLEV_PREDICATE is predicate under which callee is executed. */ 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 static struct predicate
remap_predicate (struct inline_summary *info, remap_predicate (struct inline_summary *info,
struct inline_summary *callee_info, struct inline_summary *callee_info,
struct predicate *p, struct predicate *p,
VEC (int, heap) *operand_map, VEC (int, heap) *operand_map,
VEC (int, heap) *offset_map,
clause_t possible_truths, clause_t possible_truths,
struct predicate *toplev_predicate) struct predicate *toplev_predicate)
{ {
...@@ -2436,13 +2555,34 @@ remap_predicate (struct inline_summary *info, ...@@ -2436,13 +2555,34 @@ remap_predicate (struct inline_summary *info,
Otherwise give up. */ Otherwise give up. */
if (!operand_map if (!operand_map
|| (int)VEC_length (int, operand_map) <= c->operand_num || (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 (); cond_predicate = true_predicate ();
else else
cond_predicate = add_condition (info, {
VEC_index (int, operand_map, struct agg_position_info ap;
c->operand_num), HOST_WIDE_INT offset_delta = VEC_index (int, offset_map,
c->code, c->val); 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 /* Fixed conditions remains same, construct single
condition predicate. */ condition predicate. */
...@@ -2549,6 +2689,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge, ...@@ -2549,6 +2689,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
struct inline_summary *info, struct inline_summary *info,
struct inline_summary *callee_info, struct inline_summary *callee_info,
VEC (int, heap) *operand_map, VEC (int, heap) *operand_map,
VEC (int, heap) *offset_map,
clause_t possible_truths, clause_t possible_truths,
struct predicate *toplev_predicate) struct predicate *toplev_predicate)
{ {
...@@ -2565,7 +2706,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge, ...@@ -2565,7 +2706,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
if (es->predicate) if (es->predicate)
{ {
p = remap_predicate (info, callee_info, p = remap_predicate (info, callee_info,
es->predicate, operand_map, possible_truths, es->predicate, operand_map, offset_map,
possible_truths,
toplev_predicate); toplev_predicate);
edge_set_predicate (e, &p); edge_set_predicate (e, &p);
/* TODO: We should remove the edge for code that will be /* TODO: We should remove the edge for code that will be
...@@ -2582,7 +2724,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge, ...@@ -2582,7 +2724,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
} }
else else
remap_edge_summaries (inlined_edge, e->callee, info, callee_info, 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) for (e = node->indirect_calls; e; e = e->next_callee)
{ {
...@@ -2593,8 +2736,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge, ...@@ -2593,8 +2736,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
if (es->predicate) if (es->predicate)
{ {
p = remap_predicate (info, callee_info, p = remap_predicate (info, callee_info,
es->predicate, operand_map, possible_truths, es->predicate, operand_map, offset_map,
toplev_predicate); possible_truths, toplev_predicate);
edge_set_predicate (e, &p); edge_set_predicate (e, &p);
/* TODO: We should remove the edge for code that will be optimized /* TODO: We should remove the edge for code that will be optimized
out, but we need to keep verifiers and tree-inline happy. out, but we need to keep verifiers and tree-inline happy.
...@@ -2623,6 +2766,7 @@ inline_merge_summary (struct cgraph_edge *edge) ...@@ -2623,6 +2766,7 @@ inline_merge_summary (struct cgraph_edge *edge)
clause_t clause = 0; /* not_inline is known to be false. */ clause_t clause = 0; /* not_inline is known to be false. */
size_time_entry *e; size_time_entry *e;
VEC (int, heap) *operand_map = NULL; VEC (int, heap) *operand_map = NULL;
VEC (int, heap) *offset_map = NULL;
int i; int i;
struct predicate toplev_predicate; struct predicate toplev_predicate;
struct predicate true_p = true_predicate (); struct predicate true_p = true_predicate ();
...@@ -2639,17 +2783,36 @@ inline_merge_summary (struct cgraph_edge *edge) ...@@ -2639,17 +2783,36 @@ inline_merge_summary (struct cgraph_edge *edge)
int count = ipa_get_cs_argument_count (args); int count = ipa_get_cs_argument_count (args);
int i; int i;
evaluate_properties_for_edge (edge, true, &clause, NULL, NULL); evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL);
if (count) 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++) for (i = 0; i < count; i++)
{ {
struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i); struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
int map = -1; int map = -1;
/* TODO: handle non-NOPs when merging. */ /* TODO: handle non-NOPs when merging. */
if (jfunc->type == IPA_JF_PASS_THROUGH 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 (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); VEC_replace (int, operand_map, i, map);
gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to))); gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
} }
...@@ -2657,7 +2820,8 @@ inline_merge_summary (struct cgraph_edge *edge) ...@@ -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++) for (i = 0; VEC_iterate (size_time_entry, callee_info->entry, i, e); i++)
{ {
struct predicate p = remap_predicate (info, callee_info, struct predicate p = remap_predicate (info, callee_info,
&e->predicate, operand_map, clause, &e->predicate, operand_map,
offset_map, clause,
&toplev_predicate); &toplev_predicate);
if (!false_predicate_p (&p)) if (!false_predicate_p (&p))
{ {
...@@ -2679,7 +2843,7 @@ inline_merge_summary (struct cgraph_edge *edge) ...@@ -2679,7 +2843,7 @@ inline_merge_summary (struct cgraph_edge *edge)
} }
} }
remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map, 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_update_callee_summaries (edge->callee,
inline_edge_summary (edge)->loop_depth); inline_edge_summary (edge)->loop_depth);
...@@ -2689,6 +2853,7 @@ inline_merge_summary (struct cgraph_edge *edge) ...@@ -2689,6 +2853,7 @@ inline_merge_summary (struct cgraph_edge *edge)
/* Similarly remove param summaries. */ /* Similarly remove param summaries. */
VEC_free (inline_param_summary_t, heap, es->param); VEC_free (inline_param_summary_t, heap, es->param);
VEC_free (int, heap, operand_map); VEC_free (int, heap, operand_map);
VEC_free (int, heap, offset_map);
} }
/* For performance reasons inline_merge_summary is not updating overall size /* For performance reasons inline_merge_summary is not updating overall size
...@@ -2707,7 +2872,7 @@ inline_update_overall_summary (struct cgraph_node *node) ...@@ -2707,7 +2872,7 @@ inline_update_overall_summary (struct cgraph_node *node)
info->size += e->size, info->time += e->time; info->size += e->size, info->time += e->time;
estimate_calls_size_and_time (node, &info->size, &info->time, estimate_calls_size_and_time (node, &info->size, &info->time,
~(clause_t)(1 << predicate_false_condition), ~(clause_t)(1 << predicate_false_condition),
NULL, NULL); NULL, NULL, NULL);
info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE; info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE; info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
} }
...@@ -2729,17 +2894,20 @@ do_estimate_edge_time (struct cgraph_edge *edge) ...@@ -2729,17 +2894,20 @@ do_estimate_edge_time (struct cgraph_edge *edge)
clause_t clause; clause_t clause;
VEC (tree, heap) *known_vals; 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 inline_edge_summary *es = inline_edge_summary (edge); struct inline_edge_summary *es = inline_edge_summary (edge);
callee = cgraph_function_or_thunk_node (edge->callee, NULL); callee = cgraph_function_or_thunk_node (edge->callee, NULL);
gcc_checking_assert (edge->inline_failed); gcc_checking_assert (edge->inline_failed);
evaluate_properties_for_edge (edge, true, 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, 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_vals);
VEC_free (tree, heap, known_binfos); VEC_free (tree, heap, known_binfos);
VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
ret = (((gcov_type)time ret = (((gcov_type)time
- es->call_stmt_time) * edge->frequency - es->call_stmt_time) * edge->frequency
...@@ -2776,6 +2944,7 @@ do_estimate_edge_growth (struct cgraph_edge *edge) ...@@ -2776,6 +2944,7 @@ do_estimate_edge_growth (struct cgraph_edge *edge)
clause_t clause; clause_t clause;
VEC (tree, heap) *known_vals; VEC (tree, heap) *known_vals;
VEC (tree, heap) *known_binfos; 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. */ /* 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) ...@@ -2794,11 +2963,13 @@ do_estimate_edge_growth (struct cgraph_edge *edge)
/* Early inliner runs without caching, go ahead and do the dirty work. */ /* Early inliner runs without caching, go ahead and do the dirty work. */
gcc_checking_assert (edge->inline_failed); gcc_checking_assert (edge->inline_failed);
evaluate_properties_for_edge (edge, true, 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, 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_vals);
VEC_free (tree, heap, known_binfos); 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); gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
return size - 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, ...@@ -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.operand_num = streamer_read_uhwi (&ib);
c.code = (enum tree_code) streamer_read_uhwi (&ib); c.code = (enum tree_code) streamer_read_uhwi (&ib);
c.val = stream_read_tree (&ib, data_in); 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); VEC_safe_push (condition, gc, info->conds, &c);
} }
count2 = streamer_read_uhwi (&ib); count2 = streamer_read_uhwi (&ib);
...@@ -3223,6 +3399,12 @@ inline_write_summary (cgraph_node_set set, ...@@ -3223,6 +3399,12 @@ inline_write_summary (cgraph_node_set set,
streamer_write_uhwi (ob, c->operand_num); streamer_write_uhwi (ob, c->operand_num);
streamer_write_uhwi (ob, c->code); streamer_write_uhwi (ob, c->code);
stream_write_tree (ob, c->val, true); 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)); streamer_write_uhwi (ob, VEC_length (size_time_entry, info->entry));
for (i = 0; for (i = 0;
......
...@@ -28,9 +28,18 @@ along with GCC; see the file COPYING3. If not see ...@@ -28,9 +28,18 @@ along with GCC; see the file COPYING3. If not see
typedef struct GTY(()) condition typedef struct GTY(()) condition
{ {
/* If agg_contents is set, this is the offset from which the used data was
loaded. */
HOST_WIDE_INT offset;
tree val; tree val;
int operand_num; int operand_num;
enum tree_code code; ENUM_BITFIELD(tree_code) code : 16;
/* Set if the used data were loaded from an aggregate parameter or from
data received by reference. */
unsigned agg_contents : 1;
/* If agg_contents is set, this differentiates between loads from data
passed by reference and by value. */
unsigned by_ref : 1;
} condition; } condition;
DEF_VEC_O (condition); DEF_VEC_O (condition);
......
...@@ -494,8 +494,9 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, ...@@ -494,8 +494,9 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
/* Indirect edge and binfo processing. */ /* Indirect edge and binfo processing. */
tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
VEC (tree, heap) *known_csts, VEC (tree, heap) *,
VEC (tree, heap) *known_binfs); VEC (tree, heap) *,
VEC (ipa_agg_jump_function_p, heap) *);
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree); struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
/* Functions related to both. */ /* Functions related to both. */
......
2012-08-11 Martin Jambor <mjambor@suse.cz>
PR fortran/48636
* gfortran.dg/pr48636.f90: New test.
2012-08-10 Jakub Jelinek <jakub@redhat.com> 2012-08-10 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/torture/vector-shuffle1.c (f): Pass vectors indirectly * gcc.dg/torture/vector-shuffle1.c (f): Pass vectors indirectly
......
! { dg-do compile }
! { dg-options "-O3 -fdump-ipa-inline" }
module foo
implicit none
contains
subroutine bar(a,x)
real, dimension(:,:), intent(in) :: a
real, intent(out) :: x
integer :: i,j
x = 0
do j=1,ubound(a,2)
do i=1,ubound(a,1)
x = x + a(i,j)**2
end do
end do
end subroutine bar
end module foo
program main
use foo
implicit none
real, dimension(2,3) :: a
real :: x
integer :: i
data a /1.0, 2.0, 3.0, -1.0, -2.0, -3.0/
do i=1,2000000
call bar(a,x)
end do
print *,x
end program main
! { dg-final { scan-ipa-dump "bar\[^\\n\]*inline copy in MAIN" "inline" } }
! { dg-final { cleanup-ipa-dump "inline" } }
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