===================================================================
@@ -28,9 +28,11 @@ along with GCC; see the file COPYING3.
typedef struct GTY(()) condition
{
+ HOST_WIDE_INT offset;
tree val;
int operand_num;
enum tree_code code;
+ bool agg_contents;
} condition;
DEF_VEC_O (condition);
===================================================================
@@ -209,17 +209,21 @@ not_inlined_predicate (void)
static struct predicate
add_condition (struct inline_summary *summary, int operand_num,
+ bool agg_contents, HOST_WIDE_INT offset,
enum tree_code code, tree val)
{
int i;
struct condition *c;
struct condition new_cond;
+ 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))
return single_cond_predicate (i + predicate_first_dynamic_condition);
}
/* Too many conditions. Give up and return constant true. */
@@ -229,6 +233,8 @@ add_condition (struct inline_summary *su
new_cond.operand_num = operand_num;
new_cond.code = code;
new_cond.val = val;
+ new_cond.agg_contents = agg_contents;
+ new_cond.offset = offset;
VEC_safe_push (condition, gc, summary->conds, &new_cond);
return single_cond_predicate (i + predicate_first_dynamic_condition);
}
@@ -520,6 +526,8 @@ dump_condition (FILE *f, conditions cond
c = VEC_index (condition, conditions,
cond - predicate_first_dynamic_condition);
fprintf (f, "op%i", c->operand_num);
+ if (c->agg_contents)
+ fprintf (f, "[offset: " HOST_WIDE_INT_PRINT_DEC "]", c->offset);
if (c->code == IS_NOT_CONSTANT)
{
fprintf (f, " not constant");
@@ -661,14 +669,15 @@ edge_set_predicate (struct cgraph_edge *
/* 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.
+ 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);
@@ -680,16 +689,43 @@ evaluate_conditions_for_known_args (stru
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). */
+ 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
+ && !POINTER_TYPE_P (TREE_TYPE (ipa_get_param (IPA_NODE_REF (node),
+ c->operand_num)))
+ && (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, node,
+ c->operand_num);
+ }
+ 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)
{
@@ -712,13 +748,15 @@ evaluate_conditions_for_known_args (stru
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;
@@ -743,13 +781,16 @@ evaluate_properties_for_edge (struct cgr
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)
@@ -762,17 +803,27 @@ evaluate_properties_for_edge (struct cgr
es->param,
i)->change_prob)
VEC_replace (tree, known_vals, i, error_mark_node);
+ /* TODO: When IPA-CP starts merging aggregate jump functions, use its
+ knowledge of the caller too, just like the scalar case above.
+ When we do that, we must not forget to check also
+ ipa_jf_propagates_agg_p. */
+ 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);
}
@@ -918,8 +969,8 @@ inline_node_duplication_hook (struct cgr
}
}
}
- 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);
@@ -1263,11 +1314,11 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUS
return true;
}
-/* If OP reffers to value of function parameter, return
+/* 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
@@ -1286,13 +1337,64 @@ 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, whether it has been
+ loaded from an aggregate into *AGG_CONTENTS_P and if so, offset of the value
+ within the aggregate into *OFFSET_P. 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,
+ bool *agg_contents_p, HOST_WIDE_INT *offset_p)
+{
+ tree res = unmodified_parm_1 (stmt, op);
+
+ if (res)
+ {
+ *index_p = ipa_get_param_decl_index (info, res);
+ if (*index_p < 0)
+ return false;
+ *agg_contents_p = 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,
+ agg_contents_p, offset_p);
+ }
+
+ *agg_contents_p = true;
+ return ipa_load_from_parm_agg (info, stmt, op, index_p, offset_p);
}
/* See if statement might disappear after inlining.
@@ -1423,6 +1525,8 @@ set_cond_stmt_execution_predicate (struc
gimple last;
tree op;
int index;
+ bool agg_contents;
+ HOST_WIDE_INT offset;
enum tree_code code, inverted_code;
edge e;
edge_iterator ei;
@@ -1441,12 +1545,9 @@ set_cond_stmt_execution_predicate (struc
/* 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, &agg_contents,
+ &offset))
{
- index = ipa_get_param_decl_index (info, parm);
- if (index == -1)
- return;
code = gimple_cond_code (last);
inverted_code
= invert_tree_comparison (code,
@@ -1455,7 +1556,7 @@ set_cond_stmt_execution_predicate (struc
FOR_EACH_EDGE (e, ei, bb->succs)
{
struct predicate p = add_condition (summary,
- index,
+ index, agg_contents, offset,
e->flags & EDGE_TRUE_VALUE
? code : inverted_code,
gimple_cond_rhs (last));
@@ -1481,6 +1582,7 @@ set_cond_stmt_execution_predicate (struc
|| gimple_call_num_args (set_stmt) != 1)
return;
op2 = gimple_call_arg (set_stmt, 0);
+ /* TODO: Use unmodified_parm_or_parm_agg_item also here. */
base = get_base_address (op2);
parm = unmodified_parm (set_stmt, base ? base : op2);
if (!parm)
@@ -1495,7 +1597,7 @@ set_cond_stmt_execution_predicate (struc
if (e->flags & EDGE_FALSE_VALUE)
{
struct predicate p = add_condition (summary,
- index,
+ index, false, 0,
IS_NOT_CONSTANT,
NULL);
e->aux = pool_alloc (edge_predicate_pool);
@@ -1515,22 +1617,20 @@ set_switch_stmt_execution_predicate (str
gimple last;
tree op;
int index;
+ bool agg_contents;
+ HOST_WIDE_INT offset;
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, &agg_contents,
+ &offset))
return;
FOR_EACH_EDGE (e, ei, bb->succs)
@@ -1555,16 +1655,16 @@ set_switch_stmt_execution_predicate (str
if (!min && !max)
p = true_predicate ();
else if (!max)
- p = add_condition (summary, index,
+ p = add_condition (summary, index, agg_contents, offset,
EQ_EXPR,
min);
else
{
struct predicate p1, p2;
- p1 = add_condition (summary, index,
+ p1 = add_condition (summary, index, agg_contents, offset,
GE_EXPR,
min);
- p2 = add_condition (summary, index,
+ p2 = add_condition (summary, index, agg_contents, offset,
LE_EXPR,
max);
p = and_predicates (summary->conds, &p1, &p2);
@@ -1660,13 +1760,14 @@ will_be_nonconstant_predicate (struct ip
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;
+ bool is_load, agg_contents;
+ int base_index;
+ HOST_WIDE_INT offset;
/* What statments might be optimized away
when their arguments are constant
@@ -1682,23 +1783,18 @@ will_be_nonconstant_predicate (struct ip
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,
+ &agg_contents, &offset))
return p;
}
+ else
+ base_index = -1;
/* See if we understand all operands before we start
adding conditionals. */
@@ -1717,23 +1813,25 @@ will_be_nonconstant_predicate (struct ip
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, agg_contents, offset,
+ 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, false, 0, CHANGED, NULL);
+ else
+ continue;
+ }
else
p = *VEC_index (predicate_t, nonconstant_names,
SSA_NAME_VERSION (use));
@@ -2195,7 +2293,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;
@@ -2203,7 +2302,8 @@ estimate_edge_devirt_benefit (struct cgr
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;
@@ -2260,7 +2360,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)
@@ -2277,7 +2378,7 @@ estimate_calls_size_and_time (struct cgr
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)
@@ -2287,7 +2388,7 @@ estimate_calls_size_and_time (struct cgr
{
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);
}
}
}
@@ -2302,6 +2403,7 @@ estimate_node_size_and_time (struct cgra
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)
@@ -2353,7 +2455,7 @@ estimate_node_size_and_time (struct cgra
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;
@@ -2382,27 +2484,29 @@ estimate_ipcp_clone_size_and_time (struc
{
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 have to be discarded because of ipa_jf_propagates_agg_p. */
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)
{
@@ -2437,13 +2541,26 @@ remap_predicate (struct inline_summary *
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
+ && 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);
+ {
+ HOST_WIDE_INT new_offset;
+
+ new_offset = c->offset + VEC_index (int, offset_map,
+ c->operand_num);
+ cond_predicate = add_condition (info,
+ VEC_index (int,
+ operand_map,
+ c->operand_num),
+ c->agg_contents,
+ new_offset, c->code,
+ c->val);
+ }
}
/* Fixed conditions remains same, construct single
condition predicate. */
@@ -2550,6 +2667,7 @@ remap_edge_summaries (struct cgraph_edg
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)
{
@@ -2566,7 +2684,8 @@ remap_edge_summaries (struct cgraph_edg
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
@@ -2583,7 +2702,8 @@ remap_edge_summaries (struct cgraph_edg
}
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)
{
@@ -2594,8 +2714,8 @@ remap_edge_summaries (struct cgraph_edg
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.
@@ -2624,6 +2744,7 @@ inline_merge_summary (struct cgraph_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 ();
@@ -2640,9 +2761,12 @@ inline_merge_summary (struct cgraph_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);
@@ -2651,6 +2775,17 @@ inline_merge_summary (struct cgraph_edge
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_jf_propagates_agg_p (edge, jfunc, i))
+ 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);
+ VEC_replace (int, offset_map, i, (int) offset);
+ }
+ }
VEC_replace (int, operand_map, i, map);
gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
}
@@ -2658,7 +2793,8 @@ inline_merge_summary (struct cgraph_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))
{
@@ -2680,14 +2816,14 @@ inline_merge_summary (struct cgraph_edge
}
}
remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
- clause, &toplev_predicate);
+ offset_map, clause, &toplev_predicate);
info->size = 0;
info->time = 0;
for (i = 0; VEC_iterate (size_time_entry, info->entry, i, e); i++)
info->size += e->size, info->time += e->time;
estimate_calls_size_and_time (to, &info->size, &info->time,
~(clause_t)(1 << predicate_false_condition),
- NULL, NULL);
+ NULL, NULL, NULL);
inline_update_callee_summaries (edge->callee,
inline_edge_summary (edge)->loop_depth);
@@ -2697,6 +2833,7 @@ inline_merge_summary (struct cgraph_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);
info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
@@ -2720,17 +2857,20 @@ do_estimate_edge_time (struct cgraph_edg
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
@@ -2767,6 +2907,7 @@ do_estimate_edge_growth (struct cgraph_e
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. */
@@ -2785,11 +2926,13 @@ do_estimate_edge_growth (struct cgraph_e
/* 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;
}
@@ -3069,6 +3212,10 @@ inline_read_section (struct lto_file_dec
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);
+ if (c.agg_contents)
+ c.offset = streamer_read_uhwi (&ib);
VEC_safe_push (condition, gc, info->conds, &c);
}
count2 = streamer_read_uhwi (&ib);
@@ -3212,6 +3359,11 @@ inline_write_summary (cgraph_node_set se
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);
+ 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;
===================================================================
@@ -1087,7 +1087,8 @@ propagate_constants_accross_call (struct
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;
@@ -1099,8 +1100,26 @@ ipa_get_indirect_edge_target (struct cgr
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->caller, param_index);
+ }
+ 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)
@@ -1109,6 +1128,7 @@ ipa_get_indirect_edge_target (struct cgr
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;
@@ -1159,7 +1179,8 @@ devirtualization_time_bonus (struct cgra
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;
@@ -1676,7 +1697,7 @@ ipcp_discover_new_direct_edges (struct c
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);
}
===================================================================
@@ -495,8 +495,9 @@ bool ipa_propagate_indirect_call_infos (
/* 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. */
===================================================================
@@ -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" } }