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
This commit is contained in:
parent
ab96cc5b4d
commit
8810cc52c9
7 changed files with 425 additions and 133 deletions
|
@ -1,3 +1,40 @@
|
|||
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>
|
||||
|
||||
* lto-cgraph.c (output_cgraph): Rename to ...
|
||||
|
|
31
gcc/ipa-cp.c
31
gcc/ipa-cp.c
|
@ -1084,7 +1084,8 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
|
|||
tree
|
||||
ipa_get_indirect_edge_target (struct cgraph_edge *ie,
|
||||
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;
|
||||
HOST_WIDE_INT token, anc_offset;
|
||||
|
@ -1096,8 +1097,26 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie,
|
|||
|
||||
if (!ie->indirect_info->polymorphic)
|
||||
{
|
||||
tree t = (VEC_length (tree, known_vals) > (unsigned int) param_index
|
||||
? VEC_index (tree, known_vals, param_index) : NULL);
|
||||
tree t;
|
||||
|
||||
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 &&
|
||||
TREE_CODE (t) == ADDR_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
|
||||
|
@ -1106,6 +1125,7 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie,
|
|||
return NULL_TREE;
|
||||
}
|
||||
|
||||
gcc_assert (!ie->indirect_info->agg_contents);
|
||||
token = ie->indirect_info->otr_token;
|
||||
anc_offset = ie->indirect_info->offset;
|
||||
otr_type = ie->indirect_info->otr_type;
|
||||
|
@ -1156,7 +1176,8 @@ devirtualization_time_bonus (struct cgraph_node *node,
|
|||
struct inline_summary *isummary;
|
||||
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)
|
||||
continue;
|
||||
|
||||
|
@ -1673,7 +1694,7 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node,
|
|||
tree target;
|
||||
|
||||
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)
|
||||
ipa_make_edge_direct_to_target (ie, target);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -28,9 +28,18 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
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;
|
||||
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;
|
||||
|
||||
DEF_VEC_O (condition);
|
||||
|
|
|
@ -494,8 +494,9 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
|
|||
|
||||
/* Indirect edge and binfo processing. */
|
||||
tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
|
||||
VEC (tree, heap) *known_csts,
|
||||
VEC (tree, heap) *known_binfs);
|
||||
VEC (tree, heap) *,
|
||||
VEC (tree, heap) *,
|
||||
VEC (ipa_agg_jump_function_p, heap) *);
|
||||
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
|
||||
|
||||
/* Functions related to both. */
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
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>
|
||||
|
||||
* gcc.dg/torture/vector-shuffle1.c (f): Pass vectors indirectly
|
||||
|
|
37
gcc/testsuite/gfortran.dg/pr48636.f90
Normal file
37
gcc/testsuite/gfortran.dg/pr48636.f90
Normal file
|
@ -0,0 +1,37 @@
|
|||
! { 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" } }
|
Loading…
Add table
Reference in a new issue