aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjamborm <jamborm@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-11 10:50:24 +0000
committerjamborm <jamborm@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-11 10:50:24 +0000
commita4f60e55a178cb5500186d27ff3fd4a62d0281e3 (patch)
tree43a439de6e36e3979859d9e70595d7bc11210e62
parent02b699d50d860e2554adddf09753492b6f4bda66 (diff)
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@190313 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog37
-rw-r--r--gcc/ipa-cp.c31
-rw-r--r--gcc/ipa-inline-analysis.c432
-rw-r--r--gcc/ipa-inline.h11
-rw-r--r--gcc/ipa-prop.h5
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gfortran.dg/pr48636.f9037
7 files changed, 425 insertions, 133 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6eb422b0ca8..8a4bcb56487 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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 ...
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index b9184702aed..1f2ea92fb50 100644
--- a/gcc/ipa-cp.c
+++ b/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);
}
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index 474f2a9af19..1a3afc45699 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -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;
diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h
index fbd0b9982b7..db3f8d4e56b 100644
--- a/gcc/ipa-inline.h
+++ b/gcc/ipa-inline.h
@@ -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);
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 489e5d859b8..2d2a54be0cf 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -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. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 50c97413c15..5c5b9b52567 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/gfortran.dg/pr48636.f90 b/gcc/testsuite/gfortran.dg/pr48636.f90
new file mode 100644
index 00000000000..44515ae9ad9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr48636.f90
@@ -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" } }