Improve effectivity of ipa_polymorphi_context cache.

* ipa-fnsummary.c (set_cond_stmt_execution_predicate,
	set_switch_stmt_execution_predicate, compute_bb_predicates,
	will_be_nonconstant_expr_predicate,
	phi_result_unknown_predicate,
	analyze_function_body): Pass arround params summary.
	(ipa_call_context::duplicate_from): New comment;
	only duplicate useful values.
	(ipa_call_context::equal_to): Only compare useful values.
	(remap_edge_summaries): Pass params_summary.
	(remap_hint_predicate): Likewise.
	(ipa_merge_fn_summary_after_inlining): Likewise.
	(inline_read_section): Initialize params summary used flags.
	* ipa-predicate.c (predicate::remap_after_inlining): Pass
	around param_summary.
	(add_condition): Initialized used params summary flags.
	* ipa-predicate.h (inline_param_summary::equals_to): Make const.
	(inline_param_summary::useless_p): New predicate.
	(remap_after_inlining, add_condition): Update prototype
	* ipa-prop.c (ipa_populate_param_decls): Watch overflow in
	move_cost.
	(ipa_note_param_call): Add parameter POLYMORPHIC; update params
	summaries.
	(ipa_analyze_indirect_call_uses): Update use of ipa_note_param_call.
	(ipa_analyze_virtual_call_uses): Likewise.
	(update_indirect_edges_after_inlining): Update param summaries.
	(ipa_print_node_params): Print used flags.
	(ipa_read_indirect_edge_info): Update param summareis.
	* ipa-prop.h (ipa_param_descriptor): Add
	used_by_ipa_predicates, used_by_indirect_call
	and used_by_polymorphic_call.
	(ipa_set_param_used_by_ipa_predicates,
	ipa_set_param_used_by_indirect_call,
	ipa_set_param_used_by_polymorphic_call,
	ipa_is_param_used_by_ipa_predicates,
	ipa_is_param_used_by_indirect_call,
	ipa_is_param_used_by_polymorphic_call): New inline functions.

From-SVN: r277759
This commit is contained in:
Jan Hubicka 2019-11-03 23:32:56 +01:00 committed by Jan Hubicka
parent 4bcd578ab4
commit 40a777e840
6 changed files with 386 additions and 97 deletions

View file

@ -1,3 +1,42 @@
2019-11-02 Jan Hubicka <hubicka@ucw.cz>
* ipa-fnsummary.c (set_cond_stmt_execution_predicate,
set_switch_stmt_execution_predicate, compute_bb_predicates,
will_be_nonconstant_expr_predicate,
phi_result_unknown_predicate,
analyze_function_body): Pass arround params summary.
(ipa_call_context::duplicate_from): New comment;
only duplicate useful values.
(ipa_call_context::equal_to): Only compare useful values.
(remap_edge_summaries): Pass params_summary.
(remap_hint_predicate): Likewise.
(ipa_merge_fn_summary_after_inlining): Likewise.
(inline_read_section): Initialize params summary used flags.
* ipa-predicate.c (predicate::remap_after_inlining): Pass
around param_summary.
(add_condition): Initialized used params summary flags.
* ipa-predicate.h (inline_param_summary::equals_to): Make const.
(inline_param_summary::useless_p): New predicate.
(remap_after_inlining, add_condition): Update prototype
* ipa-prop.c (ipa_populate_param_decls): Watch overflow in
move_cost.
(ipa_note_param_call): Add parameter POLYMORPHIC; update params
summaries.
(ipa_analyze_indirect_call_uses): Update use of ipa_note_param_call.
(ipa_analyze_virtual_call_uses): Likewise.
(update_indirect_edges_after_inlining): Update param summaries.
(ipa_print_node_params): Print used flags.
(ipa_read_indirect_edge_info): Update param summareis.
* ipa-prop.h (ipa_param_descriptor): Add
used_by_ipa_predicates, used_by_indirect_call
and used_by_polymorphic_call.
(ipa_set_param_used_by_ipa_predicates,
ipa_set_param_used_by_indirect_call,
ipa_set_param_used_by_polymorphic_call,
ipa_is_param_used_by_ipa_predicates,
ipa_is_param_used_by_indirect_call,
ipa_is_param_used_by_polymorphic_call): New inline functions.
2019-11-02 Jan Hubicka <hubicka@ucw.cz>
* ipa-fnsummary.c (ipa_call_context::duplicate_from): New

View file

@ -1312,6 +1312,7 @@ fail:
static void
set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
class ipa_fn_summary *summary,
class ipa_node_params *params_summary,
basic_block bb)
{
gimple *last;
@ -1354,7 +1355,8 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
&& !dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest))
{
predicate p
= add_condition (summary, index, param_type, &aggpos,
= add_condition (summary, params_summary, index,
param_type, &aggpos,
this_code, gimple_cond_rhs (last), param_ops);
e->aux = edge_predicate_pool.allocate ();
*(predicate *) e->aux = p;
@ -1387,7 +1389,8 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
return;
FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALSE_VALUE)
{
predicate p = add_condition (summary, index, param_type, &aggpos,
predicate p = add_condition (summary, params_summary, index,
param_type, &aggpos,
predicate::is_not_constant, NULL_TREE);
e->aux = edge_predicate_pool.allocate ();
*(predicate *) e->aux = p;
@ -1401,6 +1404,7 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
static void
set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
class ipa_fn_summary *summary,
class ipa_node_params *params_summary,
basic_block bb)
{
gimple *lastg;
@ -1470,15 +1474,15 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
if (dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest))
p = true;
else if (min == max)
p = add_condition (summary, index, param_type, &aggpos, EQ_EXPR,
min, param_ops);
p = add_condition (summary, params_summary, index, param_type,
&aggpos, EQ_EXPR, min, param_ops);
else
{
predicate p1, p2;
p1 = add_condition (summary, index, param_type, &aggpos, GE_EXPR,
min, param_ops);
p2 = add_condition (summary, index, param_type, &aggpos, LE_EXPR,
max, param_ops);
p1 = add_condition (summary, params_summary, index, param_type,
&aggpos, GE_EXPR, min, param_ops);
p2 = add_condition (summary, params_summary,index, param_type,
&aggpos, LE_EXPR, max, param_ops);
p = p1 & p2;
}
*(class predicate *) e->aux
@ -1559,7 +1563,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
tree max = ranges[i].second;
if (min == max)
p_seg &= add_condition (summary, index, param_type, &aggpos, NE_EXPR,
p_seg &= add_condition (summary, params_summary, index,
param_type, &aggpos, NE_EXPR,
min, param_ops);
else
{
@ -1567,7 +1572,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
of switch index. */
if (wi::lt_p (vr_wmin, wi::to_wide (min), TYPE_SIGN (type)))
{
p_seg &= add_condition (summary, index, param_type, &aggpos,
p_seg &= add_condition (summary, params_summary, index,
param_type, &aggpos,
LT_EXPR, min, param_ops);
p_all = p_all.or_with (summary->conds, p_seg);
}
@ -1580,7 +1586,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
break;
}
p_seg = add_condition (summary, index, param_type, &aggpos, GT_EXPR,
p_seg = add_condition (summary, params_summary, index,
param_type, &aggpos, GT_EXPR,
max, param_ops);
}
}
@ -1599,7 +1606,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
static void
compute_bb_predicates (struct ipa_func_body_info *fbi,
struct cgraph_node *node,
class ipa_fn_summary *summary)
class ipa_fn_summary *summary,
class ipa_node_params *params_summary)
{
struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
bool done = false;
@ -1607,8 +1615,8 @@ compute_bb_predicates (struct ipa_func_body_info *fbi,
FOR_EACH_BB_FN (bb, my_function)
{
set_cond_stmt_execution_predicate (fbi, summary, bb);
set_switch_stmt_execution_predicate (fbi, summary, bb);
set_cond_stmt_execution_predicate (fbi, summary, params_summary, bb);
set_switch_stmt_execution_predicate (fbi, summary, params_summary, bb);
}
/* Entry block is always executable. */
@ -1701,6 +1709,7 @@ compute_bb_predicates (struct ipa_func_body_info *fbi,
static predicate
will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
class ipa_fn_summary *summary,
class ipa_node_params *params_summary,
tree expr,
vec<predicate> nonconstant_names)
{
@ -1712,7 +1721,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
parm = unmodified_parm (fbi, NULL, expr, NULL);
if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
return add_condition (summary, index, TREE_TYPE (parm), NULL,
return add_condition (summary, params_summary, index, TREE_TYPE (parm), NULL,
predicate::changed, NULL_TREE);
if (is_gimple_min_invariant (expr))
return false;
@ -1722,6 +1731,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
{
predicate p1
= will_be_nonconstant_expr_predicate (fbi, summary,
params_summary,
TREE_OPERAND (expr, 0),
nonconstant_names);
if (p1 == true)
@ -1729,6 +1739,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
predicate p2
= will_be_nonconstant_expr_predicate (fbi, summary,
params_summary,
TREE_OPERAND (expr, 1),
nonconstant_names);
return p1.or_with (summary->conds, p2);
@ -1737,6 +1748,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
{
predicate p1
= will_be_nonconstant_expr_predicate (fbi, summary,
params_summary,
TREE_OPERAND (expr, 0),
nonconstant_names);
if (p1 == true)
@ -1744,12 +1756,14 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
predicate p2
= will_be_nonconstant_expr_predicate (fbi, summary,
params_summary,
TREE_OPERAND (expr, 1),
nonconstant_names);
if (p2 == true)
return p2;
p1 = p1.or_with (summary->conds, p2);
p2 = will_be_nonconstant_expr_predicate (fbi, summary,
params_summary,
TREE_OPERAND (expr, 2),
nonconstant_names);
return p2.or_with (summary->conds, p1);
@ -1771,6 +1785,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
static predicate
will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
class ipa_fn_summary *summary,
class ipa_node_params *params_summary,
gimple *stmt,
vec<predicate> nonconstant_names)
{
@ -1828,7 +1843,8 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
if (is_load)
op_non_const =
add_condition (summary, base_index, param_type, &aggpos,
add_condition (summary, params_summary,
base_index, param_type, &aggpos,
predicate::changed, NULL_TREE);
else
op_non_const = false;
@ -1840,7 +1856,8 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
{
if (index != base_index)
p = add_condition (summary, index, TREE_TYPE (parm), NULL,
p = add_condition (summary, params_summary, index,
TREE_TYPE (parm), NULL,
predicate::changed, NULL_TREE);
else
continue;
@ -2027,7 +2044,9 @@ param_change_prob (ipa_func_body_info *fbi, gimple *stmt, int i)
static bool
phi_result_unknown_predicate (ipa_func_body_info *fbi,
ipa_fn_summary *summary, basic_block bb,
ipa_fn_summary *summary,
class ipa_node_params *params_summary,
basic_block bb,
predicate *p,
vec<predicate> nonconstant_names)
{
@ -2071,7 +2090,7 @@ phi_result_unknown_predicate (ipa_func_body_info *fbi,
|| !is_gimple_ip_invariant (gimple_cond_rhs (stmt)))
return false;
*p = will_be_nonconstant_expr_predicate (fbi, summary,
*p = will_be_nonconstant_expr_predicate (fbi, summary, params_summary,
gimple_cond_lhs (stmt),
nonconstant_names);
if (*p == true)
@ -2264,6 +2283,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
sreal freq;
class ipa_fn_summary *info = ipa_fn_summaries->get_create (node);
class ipa_node_params *params_summary = early ? NULL : IPA_NODE_REF (node);
predicate bb_predicate;
struct ipa_func_body_info fbi;
vec<predicate> nonconstant_names = vNULL;
@ -2329,7 +2349,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
bb_predicate);
if (fbi.info)
compute_bb_predicates (&fbi, node, info);
compute_bb_predicates (&fbi, node, info, params_summary);
order = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
nblocks = pre_and_rev_post_order_compute (NULL, order, false);
for (n = 0; n < nblocks; n++)
@ -2371,7 +2391,9 @@ analyze_function_body (struct cgraph_node *node, bool early)
gsi_next (&bsi))
{
if (first_phi
&& !phi_result_unknown_predicate (&fbi, info, bb,
&& !phi_result_unknown_predicate (&fbi, info,
params_summary,
bb,
&phi_predicate,
nonconstant_names))
break;
@ -2469,7 +2491,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
just maximum of the possible paths. */
if (fbi.info)
will_be_nonconstant
= will_be_nonconstant_predicate (&fbi, info,
= will_be_nonconstant_predicate (&fbi, info, params_summary,
stmt, nonconstant_names);
else
will_be_nonconstant = true;
@ -2536,7 +2558,8 @@ analyze_function_body (struct cgraph_node *node, bool early)
predicate p = bb_predicate;
if (fbi.info)
p = p & will_be_nonconstant_expr_predicate
(&fbi, info, TREE_OPERAND (op, 1),
(&fbi, info, params_summary,
TREE_OPERAND (op, 1),
nonconstant_names);
if (p != false)
{
@ -2581,6 +2604,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
{
predicate will_be_nonconstant
= will_be_nonconstant_expr_predicate (&fbi, info,
params_summary,
niter_desc.niter,
nonconstant_names);
if (will_be_nonconstant != true)
@ -2625,7 +2649,9 @@ analyze_function_body (struct cgraph_node *node, bool early)
continue;
predicate will_be_nonconstant
= will_be_nonconstant_expr_predicate (&fbi, info, iv.step,
= will_be_nonconstant_expr_predicate (&fbi, info,
params_summary,
iv.step,
nonconstant_names);
if (will_be_nonconstant != true)
will_be_nonconstant = bb_predicate & will_be_nonconstant;
@ -2964,29 +2990,73 @@ ipa_call_context::ipa_call_context (cgraph_node *node,
{
}
/* Set THIS to be a duplicate of CTX. Copy all relevant info. */
void
ipa_call_context::duplicate_from (const ipa_call_context &ctx)
{
m_node = ctx.m_node;
m_possible_truths = ctx.m_possible_truths;
m_nonspec_possible_truths = ctx.m_nonspec_possible_truths;
class ipa_node_params *params_summary = IPA_NODE_REF (m_node);
unsigned int nargs = ipa_get_param_count (params_summary);
m_inline_param_summary = vNULL;
/* Copy the info only if there is at least one useful entry. */
if (ctx.m_inline_param_summary.exists ())
m_inline_param_summary = ctx.m_inline_param_summary.copy ();
else
m_inline_param_summary = vNULL;
{
unsigned int n = MIN (ctx.m_inline_param_summary.length (), nargs);
for (unsigned int i = 0; i < n; i++)
if (ipa_is_param_used_by_ipa_predicates (params_summary, i)
&& !ctx.m_inline_param_summary[i].useless_p ())
{
m_inline_param_summary
= ctx.m_inline_param_summary.copy ();
break;
}
}
m_known_vals = vNULL;
if (ctx.m_known_vals.exists ())
m_known_vals = ctx.m_known_vals.copy ();
else
m_known_vals = vNULL;
{
unsigned int n = MIN (ctx.m_known_vals.length (), nargs);
for (unsigned int i = 0; i < n; i++)
if (ipa_is_param_used_by_indirect_call (params_summary, i)
&& ctx.m_known_vals[i])
{
m_known_vals = ctx.m_known_vals.copy ();
break;
}
}
m_known_contexts = vNULL;
if (ctx.m_known_contexts.exists ())
m_known_contexts = ctx.m_known_contexts.copy ();
else
m_known_contexts = vNULL;
{
unsigned int n = MIN (ctx.m_known_contexts.length (), nargs);
for (unsigned int i = 0; i < n; i++)
if (ipa_is_param_used_by_polymorphic_call (params_summary, i)
&& !ctx.m_known_contexts[i].useless_p ())
{
m_known_contexts = ctx.m_known_contexts.copy ();
break;
}
}
m_known_aggs = vNULL;
if (ctx.m_known_aggs.exists ())
m_known_aggs = ctx.m_known_aggs.copy ();
else
m_known_aggs = vNULL;
{
unsigned int n = MIN (ctx.m_known_aggs.length (), nargs);
for (unsigned int i = 0; i < n; i++)
if (ipa_is_param_used_by_indirect_call (params_summary, i)
&& ctx.m_known_aggs[i])
{
m_known_aggs = ctx.m_known_aggs.copy ();
break;
}
}
}
/* Release memory used by known_vals/contexts/aggs vectors.
@ -3016,49 +3086,107 @@ ipa_call_context::equal_to (const ipa_call_context &ctx)
|| m_possible_truths != ctx.m_possible_truths
|| m_nonspec_possible_truths != ctx.m_nonspec_possible_truths)
return false;
if (m_inline_param_summary.exists () != ctx.m_inline_param_summary.exists ()
|| m_known_vals.exists () != ctx.m_known_vals.exists()
|| m_known_contexts.exists () != ctx.m_known_contexts.exists ()
|| m_known_aggs.exists () != ctx.m_known_aggs.exists ())
return false;
if (m_inline_param_summary.exists ())
{
if (m_inline_param_summary.length () != ctx.m_inline_param_summary.length ())
return false;
for (unsigned int i = 0; i < m_inline_param_summary.length (); i++)
if (!m_inline_param_summary[i].equal_to (ctx.m_inline_param_summary[i]))
return false;
}
if (m_known_vals.exists ())
{
if (m_known_vals.length () != ctx.m_known_vals.length ())
return false;
for (unsigned int i = 0; i < m_known_vals.length (); i++)
{
tree t1 = m_known_vals[i];
tree t2 = ctx.m_known_vals[i];
if (t1 != t2
&& (!t1 || !t2 || !operand_equal_p (m_known_vals[i],
ctx.m_known_vals[i], 0)))
class ipa_node_params *params_summary = IPA_NODE_REF (m_node);
unsigned int nargs = ipa_get_param_count (params_summary);
if (m_inline_param_summary.exists () || ctx.m_inline_param_summary.exists ())
{
for (unsigned int i = 0; i < nargs; i++)
{
if (!ipa_is_param_used_by_ipa_predicates (params_summary, i))
continue;
if (i >= m_inline_param_summary.length ()
|| m_inline_param_summary[i].useless_p ())
{
if (i < ctx.m_inline_param_summary.length ()
&& !ctx.m_inline_param_summary[i].useless_p ())
return false;
continue;
}
if (i >= ctx.m_inline_param_summary.length ()
|| ctx.m_inline_param_summary[i].useless_p ())
{
if (i < m_inline_param_summary.length ()
&& !m_inline_param_summary[i].useless_p ())
return false;
continue;
}
if (!m_inline_param_summary[i].equal_to
(ctx.m_inline_param_summary[i]))
return false;
}
}
if (m_known_contexts.exists ())
if (m_known_vals.exists () || ctx.m_known_vals.exists ())
{
if (m_known_contexts.length () != ctx.m_known_contexts.length ())
return false;
for (unsigned int i = 0; i < m_known_contexts.length (); i++)
if (!m_known_contexts[i].equal_to (ctx.m_known_contexts[i]))
return false;
for (unsigned int i = 0; i < nargs; i++)
{
if (!ipa_is_param_used_by_indirect_call (params_summary, i))
continue;
if (i >= m_known_vals.length () || !m_known_vals[i])
{
if (i < ctx.m_known_vals.length () && ctx.m_known_vals[i])
return false;
continue;
}
if (i >= ctx.m_known_vals.length () || !ctx.m_known_vals[i])
{
if (i < m_known_vals.length () && m_known_vals[i])
return false;
continue;
}
if (m_known_vals[i] != ctx.m_known_vals[i])
return false;
}
}
if (m_known_aggs.exists ())
if (m_known_contexts.exists () || ctx.m_known_contexts.exists ())
{
if (m_known_aggs.length () != ctx.m_known_aggs.length ())
return false;
for (unsigned int i = 0; i < m_known_aggs.length (); i++)
if (!m_known_aggs[i]->equal_to (*ctx.m_known_aggs[i]))
return false;
for (unsigned int i = 0; i < nargs; i++)
{
if (!ipa_is_param_used_by_polymorphic_call (params_summary, i))
continue;
if (i >= m_known_contexts.length ()
|| m_known_contexts[i].useless_p ())
{
if (i < ctx.m_known_contexts.length ()
&& !ctx.m_known_contexts[i].useless_p ())
return false;
continue;
}
if (i >= ctx.m_known_contexts.length ()
|| ctx.m_known_contexts[i].useless_p ())
{
if (i < m_known_contexts.length ()
&& !m_known_contexts[i].useless_p ())
return false;
continue;
}
if (!m_known_contexts[i].equal_to
(ctx.m_known_contexts[i]))
return false;
}
}
if (m_known_aggs.exists () || ctx.m_known_aggs.exists ())
{
for (unsigned int i = 0; i < nargs; i++)
{
if (!ipa_is_param_used_by_indirect_call (params_summary, i))
continue;
if (i >= m_known_aggs.length () || !m_known_aggs[i])
{
if (i < ctx.m_known_aggs.length () && ctx.m_known_aggs[i])
return false;
continue;
}
if (i >= ctx.m_known_aggs.length () || !ctx.m_known_aggs[i])
{
if (i < m_known_aggs.length () && m_known_aggs[i])
return false;
continue;
}
if (m_known_aggs[i] != ctx.m_known_aggs[i])
return false;
}
}
return true;
}
@ -3319,6 +3447,7 @@ static void
remap_edge_summaries (struct cgraph_edge *inlined_edge,
struct cgraph_node *node,
class ipa_fn_summary *info,
class ipa_node_params *params_summary,
class ipa_fn_summary *callee_info,
vec<int> operand_map,
vec<int> offset_map,
@ -3339,7 +3468,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
if (es->predicate)
{
p = es->predicate->remap_after_inlining
(info, callee_info, operand_map,
(info, params_summary,
callee_info, operand_map,
offset_map, possible_truths,
*toplev_predicate);
edge_set_predicate (e, &p);
@ -3348,7 +3478,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
edge_set_predicate (e, toplev_predicate);
}
else
remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
remap_edge_summaries (inlined_edge, e->callee, info,
params_summary, callee_info,
operand_map, offset_map, possible_truths,
toplev_predicate);
}
@ -3362,7 +3493,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
if (es->predicate)
{
p = es->predicate->remap_after_inlining
(info, callee_info, operand_map, offset_map,
(info, params_summary,
callee_info, operand_map, offset_map,
possible_truths, *toplev_predicate);
edge_set_predicate (e, &p);
}
@ -3375,6 +3507,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
static void
remap_hint_predicate (class ipa_fn_summary *info,
class ipa_node_params *params_summary,
class ipa_fn_summary *callee_info,
predicate **hint,
vec<int> operand_map,
@ -3387,7 +3520,7 @@ remap_hint_predicate (class ipa_fn_summary *info,
if (!*hint)
return;
p = (*hint)->remap_after_inlining
(info, callee_info,
(info, params_summary, callee_info,
operand_map, offset_map,
possible_truths, *toplev_predicate);
if (p != false && p != true)
@ -3415,6 +3548,8 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
int i;
predicate toplev_predicate;
class ipa_call_summary *es = ipa_call_summaries->get (edge);
class ipa_node_params *params_summary = (ipa_node_params_sum
? IPA_NODE_REF (to) : NULL);
if (es->predicate)
toplev_predicate = *es->predicate;
@ -3461,19 +3596,21 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
}
}
operand_map[i] = map;
gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
gcc_assert (map < ipa_get_param_count (params_summary));
}
}
for (i = 0; vec_safe_iterate (callee_info->size_time_table, i, &e); i++)
{
predicate p;
p = e->exec_predicate.remap_after_inlining
(info, callee_info, operand_map,
(info, params_summary,
callee_info, operand_map,
offset_map, clause,
toplev_predicate);
predicate nonconstp;
nonconstp = e->nonconst_predicate.remap_after_inlining
(info, callee_info, operand_map,
(info, params_summary,
callee_info, operand_map,
offset_map, clause,
toplev_predicate);
if (p != false && nonconstp != false)
@ -3491,12 +3628,13 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
info->account_size_time (e->size, add_time, p, nonconstp);
}
}
remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
remap_edge_summaries (edge, edge->callee, info, params_summary,
callee_info, operand_map,
offset_map, clause, &toplev_predicate);
remap_hint_predicate (info, callee_info,
remap_hint_predicate (info, params_summary, callee_info,
&callee_info->loop_iterations,
operand_map, offset_map, clause, &toplev_predicate);
remap_hint_predicate (info, callee_info,
remap_hint_predicate (info, params_summary, callee_info,
&callee_info->loop_stride,
operand_map, offset_map, clause, &toplev_predicate);
@ -3687,6 +3825,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
unsigned int index;
struct cgraph_node *node;
class ipa_fn_summary *info;
class ipa_node_params *params_summary;
class ipa_size_summary *size_info;
lto_symtab_encoder_t encoder;
struct bitpack_d bp;
@ -3698,6 +3837,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
index));
info = node->prevailing_p () ? ipa_fn_summaries->get_create (node) : NULL;
params_summary = node->prevailing_p () ? IPA_NODE_REF (node) : NULL;
size_info = node->prevailing_p ()
? ipa_size_summaries->get_create (node) : NULL;
@ -3746,6 +3886,9 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
c.param_ops = NULL;
if (info)
vec_safe_reserve_exact (c.param_ops, count3);
if (params_summary)
ipa_set_param_used_by_ipa_predicates
(params_summary, c.operand_num, true);
for (k = 0; k < count3; k++)
{
struct expr_eval_op op;

View file

@ -505,6 +505,7 @@ predicate::remap_after_duplication (clause_t possible_truths)
predicate
predicate::remap_after_inlining (class ipa_fn_summary *info,
class ipa_node_params *params_summary,
class ipa_fn_summary *callee_info,
vec<int> operand_map,
vec<int> offset_map,
@ -566,7 +567,7 @@ predicate::remap_after_inlining (class ipa_fn_summary *info,
ap.offset = c->offset + offset_delta;
ap.agg_contents = c->agg_contents;
ap.by_ref = c->by_ref;
cond_predicate = add_condition (info,
cond_predicate = add_condition (info, params_summary,
operand_map[c->operand_num],
c->type, &ap, c->code,
c->val, c->param_ops);
@ -629,7 +630,9 @@ predicate::stream_out (struct output_block *ob)
aggregate. */
predicate
add_condition (class ipa_fn_summary *summary, int operand_num,
add_condition (class ipa_fn_summary *summary,
class ipa_node_params *params_summary,
int operand_num,
tree type, struct agg_position_info *aggpos,
enum tree_code code, tree val, expr_eval_ops param_ops)
{
@ -640,6 +643,9 @@ add_condition (class ipa_fn_summary *summary, int operand_num,
bool agg_contents, by_ref;
expr_eval_op *op;
if (params_summary)
ipa_set_param_used_by_ipa_predicates (params_summary, operand_num, true);
if (aggpos)
{
offset = aggpos->offset;

View file

@ -77,10 +77,14 @@ struct inline_param_summary
Value 0 is reserved for compile time invariants. */
int change_prob;
bool equal_to (const inline_param_summary &other)
bool equal_to (const inline_param_summary &other) const
{
return change_prob == other.change_prob;
}
bool useless_p (void) const
{
return change_prob == REG_BR_PROB_BASE;
}
};
typedef vec<condition, va_gc> *conditions;
@ -233,6 +237,7 @@ public:
/* Return predicate equal to THIS after inlining. */
predicate remap_after_inlining (class ipa_fn_summary *,
class ipa_node_params *params_summary,
class ipa_fn_summary *,
vec<int>, vec<int>, clause_t, const predicate &);
@ -254,7 +259,9 @@ private:
};
void dump_condition (FILE *f, conditions conditions, int cond);
predicate add_condition (class ipa_fn_summary *summary, int operand_num,
predicate add_condition (class ipa_fn_summary *summary,
class ipa_node_params *params_summary,
int operand_num,
tree type, struct agg_position_info *aggpos,
enum tree_code code, tree val,
expr_eval_ops param_ops = NULL);

View file

@ -227,8 +227,10 @@ ipa_populate_param_decls (struct cgraph_node *node,
for (parm = fnargs; parm; parm = DECL_CHAIN (parm))
{
descriptors[param_num].decl_or_type = parm;
descriptors[param_num].move_cost = estimate_move_cost (TREE_TYPE (parm),
true);
unsigned int cost = estimate_move_cost (TREE_TYPE (parm), true);
descriptors[param_num].move_cost = cost;
/* Watch overflow, move_cost is a bitfield. */
gcc_checking_assert (cost == descriptors[param_num].move_cost);
param_num++;
}
}
@ -2116,11 +2118,12 @@ ipa_is_ssa_with_stmt_def (tree t)
/* Find the indirect call graph edge corresponding to STMT and mark it as a
call to a parameter number PARAM_INDEX. NODE is the caller. Return the
indirect call graph edge. */
indirect call graph edge.
If POLYMORPHIC is true record is as a destination of polymorphic call. */
static struct cgraph_edge *
ipa_note_param_call (struct cgraph_node *node, int param_index,
gcall *stmt)
gcall *stmt, bool polymorphic)
{
struct cgraph_edge *cs;
@ -2129,6 +2132,11 @@ ipa_note_param_call (struct cgraph_node *node, int param_index,
cs->indirect_info->agg_contents = 0;
cs->indirect_info->member_ptr = 0;
cs->indirect_info->guaranteed_unmodified = 0;
ipa_set_param_used_by_indirect_call (IPA_NODE_REF (node),
param_index, true);
if (cs->indirect_info->polymorphic || polymorphic)
ipa_set_param_used_by_polymorphic_call
(IPA_NODE_REF (node), param_index, true);
return cs;
}
@ -2204,7 +2212,7 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
tree var = SSA_NAME_VAR (target);
int index = ipa_get_param_decl_index (info, var);
if (index >= 0)
ipa_note_param_call (fbi->node, index, call);
ipa_note_param_call (fbi->node, index, call, false);
return;
}
@ -2216,7 +2224,8 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
gimple_assign_rhs1 (def), &index, &offset,
NULL, &by_ref, &guaranteed_unmodified))
{
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
call, false);
cs->indirect_info->offset = offset;
cs->indirect_info->agg_contents = 1;
cs->indirect_info->by_ref = by_ref;
@ -2317,7 +2326,8 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
if (index >= 0
&& parm_preserved_before_stmt_p (fbi, index, call, rec))
{
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
call, false);
cs->indirect_info->offset = offset;
cs->indirect_info->agg_contents = 1;
cs->indirect_info->member_ptr = 1;
@ -2377,7 +2387,8 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi,
return;
}
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
call, true);
class cgraph_indirect_call_info *ii = cs->indirect_info;
ii->offset = anc_offset;
ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
@ -3510,6 +3521,11 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
if (ici->polymorphic
&& !ipa_get_jf_pass_through_type_preserved (jfunc))
ici->vptr_changed = true;
ipa_set_param_used_by_indirect_call (new_root_info,
ici->param_index, true);
if (ici->polymorphic)
ipa_set_param_used_by_polymorphic_call (new_root_info,
ici->param_index, true);
}
}
else if (jfunc->type == IPA_JF_ANCESTOR)
@ -4055,6 +4071,12 @@ ipa_print_node_params (FILE *f, struct cgraph_node *node)
ipa_dump_param (f, info, i);
if (ipa_is_param_used (info, i))
fprintf (f, " used");
if (ipa_is_param_used_by_ipa_predicates (info, i))
fprintf (f, " used_by_ipa_predicates");
if (ipa_is_param_used_by_indirect_call (info, i))
fprintf (f, " used_by_indirect_call");
if (ipa_is_param_used_by_polymorphic_call (info, i))
fprintf (f, " used_by_polymorphic_call");
c = ipa_get_controlled_uses (info, i);
if (c == IPA_UNDESCRIBED_USE)
fprintf (f, " undescribed_use");
@ -4331,7 +4353,8 @@ ipa_write_indirect_edge_info (struct output_block *ob,
static void
ipa_read_indirect_edge_info (class lto_input_block *ib,
class data_in *data_in,
struct cgraph_edge *cs)
struct cgraph_edge *cs,
class ipa_node_params *info)
{
class cgraph_indirect_call_info *ii = cs->indirect_info;
struct bitpack_d bp;
@ -4354,6 +4377,14 @@ ipa_read_indirect_edge_info (class lto_input_block *ib,
ii->otr_type = stream_read_tree (ib, data_in);
ii->context.stream_in (ib, data_in);
}
if (info && ii->param_index >= 0)
{
if (ii->polymorphic)
ipa_set_param_used_by_polymorphic_call (info,
ii->param_index , true);
ipa_set_param_used_by_indirect_call (info,
ii->param_index, true);
}
}
/* Stream out NODE info to OB. */
@ -4523,7 +4554,7 @@ ipa_read_node_info (class lto_input_block *ib, struct cgraph_node *node,
for (e = node->indirect_calls; e; e = e->next_callee)
{
ipa_read_edge_info (ib, data_in, e, prevails);
ipa_read_indirect_edge_info (ib, data_in, e);
ipa_read_indirect_edge_info (ib, data_in, e, info);
}
}

View file

@ -333,9 +333,12 @@ struct GTY(()) ipa_param_descriptor
says how many there are. If any use could not be described by means of
ipa-prop structures, this is IPA_UNDESCRIBED_USE. */
int controlled_uses;
unsigned int move_cost : 31;
unsigned int move_cost : 28;
/* The parameter is used. */
unsigned used : 1;
unsigned used_by_ipa_predicates : 1;
unsigned used_by_indirect_call : 1;
unsigned used_by_polymorphic_call : 1;
};
/* ipa_node_params stores information related to formal parameters of functions
@ -519,6 +522,36 @@ ipa_set_param_used (class ipa_node_params *info, int i, bool val)
(*info->descriptors)[i].used = val;
}
/* Set the used_by_ipa_predicates flag corresponding to the Ith formal
parameter of the function associated with INFO to VAL. */
static inline void
ipa_set_param_used_by_ipa_predicates (class ipa_node_params *info, int i, bool val)
{
gcc_checking_assert (info->descriptors);
(*info->descriptors)[i].used_by_ipa_predicates = val;
}
/* Set the used_by_indirect_call flag corresponding to the Ith formal
parameter of the function associated with INFO to VAL. */
static inline void
ipa_set_param_used_by_indirect_call (class ipa_node_params *info, int i, bool val)
{
gcc_checking_assert (info->descriptors);
(*info->descriptors)[i].used_by_indirect_call = val;
}
/* Set the .used_by_polymorphic_call flag corresponding to the Ith formal
parameter of the function associated with INFO to VAL. */
static inline void
ipa_set_param_used_by_polymorphic_call (class ipa_node_params *info, int i, bool val)
{
gcc_checking_assert (info->descriptors);
(*info->descriptors)[i].used_by_polymorphic_call = val;
}
/* Return how many uses described by ipa-prop a parameter has or
IPA_UNDESCRIBED_USE if there is a use that is not described by these
structures. */
@ -550,6 +583,36 @@ ipa_is_param_used (class ipa_node_params *info, int i)
return (*info->descriptors)[i].used;
}
/* Return the used_by_ipa_predicates flag corresponding to the Ith formal
parameter of the function associated with INFO. */
static inline bool
ipa_is_param_used_by_ipa_predicates (class ipa_node_params *info, int i)
{
gcc_checking_assert (info->descriptors);
return (*info->descriptors)[i].used_by_ipa_predicates;
}
/* Return the used_by_indirect_call flag corresponding to the Ith formal
parameter of the function associated with INFO. */
static inline bool
ipa_is_param_used_by_indirect_call (class ipa_node_params *info, int i)
{
gcc_checking_assert (info->descriptors);
return (*info->descriptors)[i].used_by_indirect_call;
}
/* Return the used_by_polymorphic_call flag corresponding to the Ith formal
parameter of the function associated with INFO. */
static inline bool
ipa_is_param_used_by_polymorphic_call (class ipa_node_params *info, int i)
{
gcc_checking_assert (info->descriptors);
return (*info->descriptors)[i].used_by_polymorphic_call;
}
/* Information about replacements done in aggregates for a given node (each
node has its linked list). */
struct GTY(()) ipa_agg_replacement_value