Commit c628d1c3 by Martin Jambor Committed by Martin Jambor

Limit AA walking in IPA summary generation

2019-01-20  Martin Jambor  <mjambor@suse.cz>

	PR ipa/87615
	* ipa-prop.h (struct ipa_func_body_info): Replaced field aa_walked
	with aa_walk_budget.
	* cgraph.h (ipa_polymorphic_call_context::get_dynamic_type): Add
	aa_walk_budget_p parameter.
	* ipa-fnsummary.c (unmodified_parm_1): New parameter fbi.  Limit AA
	walk.  Updated all callers.
	(unmodified_parm): New parameter fbi, pass it to unmodified_parm_1.
	(eliminated_by_inlining_prob): New parameter fbi, pass it on to
	unmodified_parm.
	(will_be_nonconstant_expr_predicate): New parameter fbi, removed
	parameter info.  Extract info from fbi.  Pass fbi to recursive calls
	and to unmodified_parm.
	(phi_result_unknown_predicate): New parameter fbi, removed parameter
	info, updated call to will_be_nonconstant_expr_predicate.
	(param_change_prob): New parameter fbi, limit AA walking.
	(analyze_function_body): Initialize aa_walk_budget in fbi.  Update
	calls to various above functions.
	* ipa-polymorphic-call.c (get_dynamic_type): Add aa_walk_budget_p
	parameter.  Use it to limit AA walking.
	* ipa-prop.c (detect_type_change_from_memory_writes): New parameter
	fbi, limit AA walk.
	(detect_type_change): New parameter fbi, pass it on to
	detect_type_change_from_memory_writes.
	(detect_type_change_ssa): Likewise.
	(aa_overwalked): Removed.
	(parm_preserved_before_stmt_p): Assume fbi is never NULL, stream line
	accordingly, adjust to the neew AA limiting scheme.
	(parm_ref_data_preserved_p): Likewise.
	(ipa_compute_jump_functions_for_edge): Adjust call to
	get_dynamic_type.
	(ipa_analyze_call_uses): Likewise.
	(ipa_analyze_virtual_call_uses): Pass fbi to detect_type_change_ssa.
	(ipa_analyze_node): Initialize aa_walk_budget.
	(ipcp_transform_function): Likewise.
	* tree-ssa-sccvn.c (eliminate_dom_walker::eliminate_stmt): Update call
	to get_dynamic_type.

From-SVN: r268107
parent 49686677
2019-01-20 Martin Jambor <mjambor@suse.cz>
PR ipa/87615
* ipa-prop.h (struct ipa_func_body_info): Replaced field aa_walked
with aa_walk_budget.
* cgraph.h (ipa_polymorphic_call_context::get_dynamic_type): Add
aa_walk_budget_p parameter.
* ipa-fnsummary.c (unmodified_parm_1): New parameter fbi. Limit AA
walk. Updated all callers.
(unmodified_parm): New parameter fbi, pass it to unmodified_parm_1.
(eliminated_by_inlining_prob): New parameter fbi, pass it on to
unmodified_parm.
(will_be_nonconstant_expr_predicate): New parameter fbi, removed
parameter info. Extract info from fbi. Pass fbi to recursive calls
and to unmodified_parm.
(phi_result_unknown_predicate): New parameter fbi, removed parameter
info, updated call to will_be_nonconstant_expr_predicate.
(param_change_prob): New parameter fbi, limit AA walking.
(analyze_function_body): Initialize aa_walk_budget in fbi. Update
calls to various above functions.
* ipa-polymorphic-call.c (get_dynamic_type): Add aa_walk_budget_p
parameter. Use it to limit AA walking.
* ipa-prop.c (detect_type_change_from_memory_writes): New parameter
fbi, limit AA walk.
(detect_type_change): New parameter fbi, pass it on to
detect_type_change_from_memory_writes.
(detect_type_change_ssa): Likewise.
(aa_overwalked): Removed.
(parm_preserved_before_stmt_p): Assume fbi is never NULL, stream line
accordingly, adjust to the neew AA limiting scheme.
(parm_ref_data_preserved_p): Likewise.
(ipa_compute_jump_functions_for_edge): Adjust call to
get_dynamic_type.
(ipa_analyze_call_uses): Likewise.
(ipa_analyze_virtual_call_uses): Pass fbi to detect_type_change_ssa.
(ipa_analyze_node): Initialize aa_walk_budget.
(ipcp_transform_function): Likewise.
* tree-ssa-sccvn.c (eliminate_dom_walker::eliminate_stmt): Update call
to get_dynamic_type.
2019-01-19 Jakub Jelinek <jakub@redhat.com> 2019-01-19 Jakub Jelinek <jakub@redhat.com>
* config/aarch64/aarch64.c (aarch64_stack_protect_guard): Move * config/aarch64/aarch64.c (aarch64_stack_protect_guard): Move
......
...@@ -1557,7 +1557,7 @@ public: ...@@ -1557,7 +1557,7 @@ public:
/* Look for vtable stores or constructor calls to work out dynamic type /* Look for vtable stores or constructor calls to work out dynamic type
of memory location. */ of memory location. */
bool get_dynamic_type (tree, tree, tree, gimple *); bool get_dynamic_type (tree, tree, tree, gimple *, unsigned *);
/* Make context non-speculative. */ /* Make context non-speculative. */
void clear_speculation (); void clear_speculation ();
......
...@@ -941,7 +941,8 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED, ...@@ -941,7 +941,8 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
PARM_DECL) will be stored to *SIZE_P in that case too. */ PARM_DECL) will be stored to *SIZE_P in that case too. */
static tree static tree
unmodified_parm_1 (gimple *stmt, tree op, HOST_WIDE_INT *size_p) unmodified_parm_1 (ipa_func_body_info *fbi, gimple *stmt, tree op,
HOST_WIDE_INT *size_p)
{ {
/* SSA_NAME referring to parm default def? */ /* SSA_NAME referring to parm default def? */
if (TREE_CODE (op) == SSA_NAME if (TREE_CODE (op) == SSA_NAME
...@@ -959,8 +960,14 @@ unmodified_parm_1 (gimple *stmt, tree op, HOST_WIDE_INT *size_p) ...@@ -959,8 +960,14 @@ unmodified_parm_1 (gimple *stmt, tree op, HOST_WIDE_INT *size_p)
ao_ref refd; ao_ref refd;
ao_ref_init (&refd, op); ao_ref_init (&refd, op);
walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified, int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt),
NULL); mark_modified, &modified, NULL, NULL,
fbi->aa_walk_budget + 1);
if (walked < 0)
{
fbi->aa_walk_budget = 0;
return NULL_TREE;
}
if (!modified) if (!modified)
{ {
if (size_p) if (size_p)
...@@ -977,16 +984,17 @@ unmodified_parm_1 (gimple *stmt, tree op, HOST_WIDE_INT *size_p) ...@@ -977,16 +984,17 @@ unmodified_parm_1 (gimple *stmt, tree op, HOST_WIDE_INT *size_p)
stored to *SIZE_P in that case too. */ stored to *SIZE_P in that case too. */
static tree static tree
unmodified_parm (gimple *stmt, tree op, HOST_WIDE_INT *size_p) unmodified_parm (ipa_func_body_info *fbi, gimple *stmt, tree op,
HOST_WIDE_INT *size_p)
{ {
tree res = unmodified_parm_1 (stmt, op, size_p); tree res = unmodified_parm_1 (fbi, stmt, op, size_p);
if (res) if (res)
return res; return res;
if (TREE_CODE (op) == SSA_NAME if (TREE_CODE (op) == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (op) && !SSA_NAME_IS_DEFAULT_DEF (op)
&& gimple_assign_single_p (SSA_NAME_DEF_STMT (op))) && gimple_assign_single_p (SSA_NAME_DEF_STMT (op)))
return unmodified_parm (SSA_NAME_DEF_STMT (op), return unmodified_parm (fbi, SSA_NAME_DEF_STMT (op),
gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)), gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)),
size_p); size_p);
return NULL_TREE; return NULL_TREE;
...@@ -1005,7 +1013,7 @@ unmodified_parm_or_parm_agg_item (struct ipa_func_body_info *fbi, ...@@ -1005,7 +1013,7 @@ unmodified_parm_or_parm_agg_item (struct ipa_func_body_info *fbi,
HOST_WIDE_INT *size_p, HOST_WIDE_INT *size_p,
struct agg_position_info *aggpos) struct agg_position_info *aggpos)
{ {
tree res = unmodified_parm_1 (stmt, op, size_p); tree res = unmodified_parm_1 (fbi, stmt, op, size_p);
gcc_checking_assert (aggpos); gcc_checking_assert (aggpos);
if (res) if (res)
...@@ -1044,7 +1052,7 @@ unmodified_parm_or_parm_agg_item (struct ipa_func_body_info *fbi, ...@@ -1044,7 +1052,7 @@ unmodified_parm_or_parm_agg_item (struct ipa_func_body_info *fbi,
penalty wrappers. */ penalty wrappers. */
static int static int
eliminated_by_inlining_prob (gimple *stmt) eliminated_by_inlining_prob (ipa_func_body_info *fbi, gimple *stmt)
{ {
enum gimple_code code = gimple_code (stmt); enum gimple_code code = gimple_code (stmt);
enum tree_code rhs_code; enum tree_code rhs_code;
...@@ -1084,7 +1092,7 @@ eliminated_by_inlining_prob (gimple *stmt) ...@@ -1084,7 +1092,7 @@ eliminated_by_inlining_prob (gimple *stmt)
inner_lhs = lhs; inner_lhs = lhs;
/* Reads of parameter are expected to be free. */ /* Reads of parameter are expected to be free. */
if (unmodified_parm (stmt, inner_rhs, NULL)) if (unmodified_parm (fbi, stmt, inner_rhs, NULL))
rhs_free = true; rhs_free = true;
/* Match expressions of form &this->field. Those will most likely /* Match expressions of form &this->field. Those will most likely
combine with something upstream after inlining. */ combine with something upstream after inlining. */
...@@ -1094,7 +1102,8 @@ eliminated_by_inlining_prob (gimple *stmt) ...@@ -1094,7 +1102,8 @@ eliminated_by_inlining_prob (gimple *stmt)
if (TREE_CODE (op) == PARM_DECL) if (TREE_CODE (op) == PARM_DECL)
rhs_free = true; rhs_free = true;
else if (TREE_CODE (op) == MEM_REF else if (TREE_CODE (op) == MEM_REF
&& unmodified_parm (stmt, TREE_OPERAND (op, 0), NULL)) && unmodified_parm (fbi, stmt, TREE_OPERAND (op, 0),
NULL))
rhs_free = true; rhs_free = true;
} }
...@@ -1107,7 +1116,7 @@ eliminated_by_inlining_prob (gimple *stmt) ...@@ -1107,7 +1116,7 @@ eliminated_by_inlining_prob (gimple *stmt)
/* Reads of parameters passed by reference /* Reads of parameters passed by reference
expected to be free (i.e. optimized out after inlining). */ expected to be free (i.e. optimized out after inlining). */
if (TREE_CODE (inner_rhs) == MEM_REF if (TREE_CODE (inner_rhs) == MEM_REF
&& unmodified_parm (stmt, TREE_OPERAND (inner_rhs, 0), NULL)) && unmodified_parm (fbi, stmt, TREE_OPERAND (inner_rhs, 0), NULL))
rhs_free = true; rhs_free = true;
/* Copying parameter passed by reference into gimple register is /* Copying parameter passed by reference into gimple register is
...@@ -1148,7 +1157,8 @@ eliminated_by_inlining_prob (gimple *stmt) ...@@ -1148,7 +1157,8 @@ eliminated_by_inlining_prob (gimple *stmt)
if (TREE_CODE (inner_lhs) == PARM_DECL if (TREE_CODE (inner_lhs) == PARM_DECL
|| TREE_CODE (inner_lhs) == RESULT_DECL || TREE_CODE (inner_lhs) == RESULT_DECL
|| (TREE_CODE (inner_lhs) == MEM_REF || (TREE_CODE (inner_lhs) == MEM_REF
&& (unmodified_parm (stmt, TREE_OPERAND (inner_lhs, 0), NULL) && (unmodified_parm (fbi, stmt, TREE_OPERAND (inner_lhs, 0),
NULL)
|| (TREE_CODE (TREE_OPERAND (inner_lhs, 0)) == SSA_NAME || (TREE_CODE (TREE_OPERAND (inner_lhs, 0)) == SSA_NAME
&& SSA_NAME_VAR (TREE_OPERAND (inner_lhs, 0)) && SSA_NAME_VAR (TREE_OPERAND (inner_lhs, 0))
&& TREE_CODE (SSA_NAME_VAR (TREE_OPERAND && TREE_CODE (SSA_NAME_VAR (TREE_OPERAND
...@@ -1396,7 +1406,7 @@ compute_bb_predicates (struct ipa_func_body_info *fbi, ...@@ -1396,7 +1406,7 @@ compute_bb_predicates (struct ipa_func_body_info *fbi,
a compile time constant. */ a compile time constant. */
static predicate static predicate
will_be_nonconstant_expr_predicate (struct ipa_node_params *info, will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
struct ipa_fn_summary *summary, struct ipa_fn_summary *summary,
tree expr, tree expr,
vec<predicate> nonconstant_names) vec<predicate> nonconstant_names)
...@@ -1408,8 +1418,8 @@ will_be_nonconstant_expr_predicate (struct ipa_node_params *info, ...@@ -1408,8 +1418,8 @@ will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
while (UNARY_CLASS_P (expr)) while (UNARY_CLASS_P (expr))
expr = TREE_OPERAND (expr, 0); expr = TREE_OPERAND (expr, 0);
parm = unmodified_parm (NULL, expr, &size); parm = unmodified_parm (fbi, NULL, expr, &size);
if (parm && (index = ipa_get_param_decl_index (info, parm)) >= 0) if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
return add_condition (summary, index, size, NULL, predicate::changed, return add_condition (summary, index, size, NULL, predicate::changed,
NULL_TREE); NULL_TREE);
if (is_gimple_min_invariant (expr)) if (is_gimple_min_invariant (expr))
...@@ -1418,34 +1428,36 @@ will_be_nonconstant_expr_predicate (struct ipa_node_params *info, ...@@ -1418,34 +1428,36 @@ will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
return nonconstant_names[SSA_NAME_VERSION (expr)]; return nonconstant_names[SSA_NAME_VERSION (expr)];
if (BINARY_CLASS_P (expr) || COMPARISON_CLASS_P (expr)) if (BINARY_CLASS_P (expr) || COMPARISON_CLASS_P (expr))
{ {
predicate p1 = will_be_nonconstant_expr_predicate predicate p1
(info, summary, TREE_OPERAND (expr, 0), = will_be_nonconstant_expr_predicate (fbi, summary,
nonconstant_names); TREE_OPERAND (expr, 0),
nonconstant_names);
if (p1 == true) if (p1 == true)
return p1; return p1;
predicate p2; predicate p2
p2 = will_be_nonconstant_expr_predicate (info, summary, = will_be_nonconstant_expr_predicate (fbi, summary,
TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 1),
nonconstant_names); nonconstant_names);
return p1.or_with (summary->conds, p2); return p1.or_with (summary->conds, p2);
} }
else if (TREE_CODE (expr) == COND_EXPR) else if (TREE_CODE (expr) == COND_EXPR)
{ {
predicate p1 = will_be_nonconstant_expr_predicate predicate p1
(info, summary, TREE_OPERAND (expr, 0), = will_be_nonconstant_expr_predicate (fbi, summary,
nonconstant_names); TREE_OPERAND (expr, 0),
nonconstant_names);
if (p1 == true) if (p1 == true)
return p1; return p1;
predicate p2; predicate p2
p2 = will_be_nonconstant_expr_predicate (info, summary, = will_be_nonconstant_expr_predicate (fbi, summary,
TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 1),
nonconstant_names); nonconstant_names);
if (p2 == true) if (p2 == true)
return p2; return p2;
p1 = p1.or_with (summary->conds, p2); p1 = p1.or_with (summary->conds, p2);
p2 = will_be_nonconstant_expr_predicate (info, summary, p2 = will_be_nonconstant_expr_predicate (fbi, summary,
TREE_OPERAND (expr, 2), TREE_OPERAND (expr, 2),
nonconstant_names); nonconstant_names);
return p2.or_with (summary->conds, p1); return p2.or_with (summary->conds, p1);
...@@ -1511,7 +1523,7 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi, ...@@ -1511,7 +1523,7 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
adding conditionals. */ adding conditionals. */
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
{ {
tree parm = unmodified_parm (stmt, use, NULL); tree parm = unmodified_parm (fbi, stmt, use, NULL);
/* For arguments we can build a condition. */ /* For arguments we can build a condition. */
if (parm && ipa_get_param_decl_index (fbi->info, parm) >= 0) if (parm && ipa_get_param_decl_index (fbi->info, parm) >= 0)
continue; continue;
...@@ -1533,7 +1545,7 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi, ...@@ -1533,7 +1545,7 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
{ {
HOST_WIDE_INT size; HOST_WIDE_INT size;
tree parm = unmodified_parm (stmt, use, &size); tree parm = unmodified_parm (fbi, stmt, use, &size);
int index; int index;
if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0) if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
...@@ -1620,7 +1632,7 @@ record_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data) ...@@ -1620,7 +1632,7 @@ record_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
ought to be REG_BR_PROB_BASE / estimated_iters. */ ought to be REG_BR_PROB_BASE / estimated_iters. */
static int static int
param_change_prob (gimple *stmt, int i) param_change_prob (ipa_func_body_info *fbi, gimple *stmt, int i)
{ {
tree op = gimple_call_arg (stmt, i); tree op = gimple_call_arg (stmt, i);
basic_block bb = gimple_bb (stmt); basic_block bb = gimple_bb (stmt);
...@@ -1680,12 +1692,18 @@ param_change_prob (gimple *stmt, int i) ...@@ -1680,12 +1692,18 @@ param_change_prob (gimple *stmt, int i)
info.op = op; info.op = op;
info.stmt = stmt; info.stmt = stmt;
info.bb_set = BITMAP_ALLOC (NULL); info.bb_set = BITMAP_ALLOC (NULL);
walk_aliased_vdefs (&refd, gimple_vuse (stmt), record_modified, &info, int walked
NULL); = walk_aliased_vdefs (&refd, gimple_vuse (stmt), record_modified, &info,
if (bitmap_bit_p (info.bb_set, bb->index)) NULL, NULL, fbi->aa_walk_budget);
if (walked < 0 || bitmap_bit_p (info.bb_set, bb->index))
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, " Set in same BB as used.\n"); {
if (walked < 0)
fprintf (dump_file, " Ran out of AA walking budget.\n");
else
fprintf (dump_file, " Set in same BB as used.\n");
}
BITMAP_FREE (info.bb_set); BITMAP_FREE (info.bb_set);
return REG_BR_PROB_BASE; return REG_BR_PROB_BASE;
} }
...@@ -1719,7 +1737,7 @@ param_change_prob (gimple *stmt, int i) ...@@ -1719,7 +1737,7 @@ param_change_prob (gimple *stmt, int i)
return true and store the pointer the predicate in *P. */ return true and store the pointer the predicate in *P. */
static bool static bool
phi_result_unknown_predicate (struct ipa_node_params *info, phi_result_unknown_predicate (ipa_func_body_info *fbi,
ipa_fn_summary *summary, basic_block bb, ipa_fn_summary *summary, basic_block bb,
predicate *p, predicate *p,
vec<predicate> nonconstant_names) vec<predicate> nonconstant_names)
...@@ -1764,7 +1782,7 @@ phi_result_unknown_predicate (struct ipa_node_params *info, ...@@ -1764,7 +1782,7 @@ phi_result_unknown_predicate (struct ipa_node_params *info,
|| !is_gimple_ip_invariant (gimple_cond_rhs (stmt))) || !is_gimple_ip_invariant (gimple_cond_rhs (stmt)))
return false; return false;
*p = will_be_nonconstant_expr_predicate (info, summary, *p = will_be_nonconstant_expr_predicate (fbi, summary,
gimple_cond_lhs (stmt), gimple_cond_lhs (stmt),
nonconstant_names); nonconstant_names);
if (*p == true) if (*p == true)
...@@ -2018,7 +2036,9 @@ analyze_function_body (struct cgraph_node *node, bool early) ...@@ -2018,7 +2036,9 @@ analyze_function_body (struct cgraph_node *node, bool early)
fbi.info = IPA_NODE_REF (node); fbi.info = IPA_NODE_REF (node);
fbi.bb_infos = vNULL; fbi.bb_infos = vNULL;
fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun)); fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun));
fbi.param_count = count_formal_params(node->decl); fbi.param_count = count_formal_params (node->decl);
fbi.aa_walk_budget = PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
nonconstant_names.safe_grow_cleared nonconstant_names.safe_grow_cleared
(SSANAMES (my_function)->length ()); (SSANAMES (my_function)->length ());
} }
...@@ -2083,7 +2103,7 @@ analyze_function_body (struct cgraph_node *node, bool early) ...@@ -2083,7 +2103,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
gsi_next (&bsi)) gsi_next (&bsi))
{ {
if (first_phi if (first_phi
&& !phi_result_unknown_predicate (fbi.info, info, bb, && !phi_result_unknown_predicate (&fbi, info, bb,
&phi_predicate, &phi_predicate,
nonconstant_names)) nonconstant_names))
break; break;
...@@ -2173,7 +2193,7 @@ analyze_function_body (struct cgraph_node *node, bool early) ...@@ -2173,7 +2193,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
es->param.safe_grow_cleared (count); es->param.safe_grow_cleared (count);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
int prob = param_change_prob (stmt, i); int prob = param_change_prob (&fbi, stmt, i);
gcc_assert (prob >= 0 && prob <= REG_BR_PROB_BASE); gcc_assert (prob >= 0 && prob <= REG_BR_PROB_BASE);
es->param[i].change_prob = prob; es->param[i].change_prob = prob;
} }
...@@ -2209,7 +2229,7 @@ analyze_function_body (struct cgraph_node *node, bool early) ...@@ -2209,7 +2229,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
{ {
sreal final_time = (sreal)this_time * freq; sreal final_time = (sreal)this_time * freq;
prob = eliminated_by_inlining_prob (stmt); prob = eliminated_by_inlining_prob (&fbi, stmt);
if (prob == 1 && dump_file && (dump_flags & TDF_DETAILS)) if (prob == 1 && dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, fprintf (dump_file,
"\t\t50%% will be eliminated by inlining\n"); "\t\t50%% will be eliminated by inlining\n");
...@@ -2286,7 +2306,7 @@ analyze_function_body (struct cgraph_node *node, bool early) ...@@ -2286,7 +2306,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
&& !is_gimple_min_invariant (niter_desc.niter)) && !is_gimple_min_invariant (niter_desc.niter))
{ {
predicate will_be_nonconstant predicate will_be_nonconstant
= will_be_nonconstant_expr_predicate (fbi.info, info, = will_be_nonconstant_expr_predicate (&fbi, info,
niter_desc.niter, niter_desc.niter,
nonconstant_names); nonconstant_names);
if (will_be_nonconstant != true) if (will_be_nonconstant != true)
...@@ -2331,8 +2351,7 @@ analyze_function_body (struct cgraph_node *node, bool early) ...@@ -2331,8 +2351,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
continue; continue;
predicate will_be_nonconstant predicate will_be_nonconstant
= will_be_nonconstant_expr_predicate (fbi.info, info, = will_be_nonconstant_expr_predicate (&fbi, info, iv.step,
iv.step,
nonconstant_names); nonconstant_names);
if (will_be_nonconstant != true) if (will_be_nonconstant != true)
will_be_nonconstant = bb_predicate & will_be_nonconstant; will_be_nonconstant = bb_predicate & will_be_nonconstant;
......
...@@ -1554,13 +1554,18 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data) ...@@ -1554,13 +1554,18 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
We do not include this analysis in the context analysis itself, because We do not include this analysis in the context analysis itself, because
it needs memory SSA to be fully built and the walk may be expensive. it needs memory SSA to be fully built and the walk may be expensive.
So it is not suitable for use withing fold_stmt and similar uses. */ So it is not suitable for use withing fold_stmt and similar uses.
AA_WALK_BUDGET_P, if not NULL, is how statements we should allow
walk_aliased_vdefs to examine. The value should be decremented by the
number of stetements we examined or set to zero if exhausted. */
bool bool
ipa_polymorphic_call_context::get_dynamic_type (tree instance, ipa_polymorphic_call_context::get_dynamic_type (tree instance,
tree otr_object, tree otr_object,
tree otr_type, tree otr_type,
gimple *call) gimple *call,
unsigned *aa_walk_budget_p)
{ {
struct type_change_info tci; struct type_change_info tci;
ao_ref ao; ao_ref ao;
...@@ -1723,8 +1728,13 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance, ...@@ -1723,8 +1728,13 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
tci.speculative = 0; tci.speculative = 0;
tci.seen_unanalyzed_store = false; tci.seen_unanalyzed_store = false;
walk_aliased_vdefs (&ao, gimple_vuse (stmt), check_stmt_for_type_change, unsigned aa_walk_budget = 0;
&tci, NULL, &function_entry_reached); if (aa_walk_budget_p)
aa_walk_budget = *aa_walk_budget_p + 1;
int walked
= walk_aliased_vdefs (&ao, gimple_vuse (stmt), check_stmt_for_type_change,
&tci, NULL, &function_entry_reached, aa_walk_budget);
/* If we did not find any type changing statements, we may still drop /* If we did not find any type changing statements, we may still drop
maybe_in_construction flag if the context already have outer type. maybe_in_construction flag if the context already have outer type.
...@@ -1772,6 +1782,16 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance, ...@@ -1772,6 +1782,16 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
only if there was dyanmic type store that may affect given variable only if there was dyanmic type store that may affect given variable
(seen_unanalyzed_store) */ (seen_unanalyzed_store) */
if (walked < 0)
{
if (dump_file)
fprintf (dump_file, " AA walk budget exhausted.\n");
*aa_walk_budget_p = 0;
return false;
}
else if (aa_walk_budget_p)
*aa_walk_budget_p -= walked;
if (!tci.type_maybe_changed if (!tci.type_maybe_changed
|| (outer_type || (outer_type
&& !dynamic && !dynamic
......
...@@ -746,13 +746,13 @@ param_type_may_change_p (tree function, tree arg, gimple *call) ...@@ -746,13 +746,13 @@ param_type_may_change_p (tree function, tree arg, gimple *call)
that does the heavy work which is usually unnecesary. */ that does the heavy work which is usually unnecesary. */
static bool static bool
detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type, detect_type_change_from_memory_writes (ipa_func_body_info *fbi, tree arg,
gcall *call, struct ipa_jump_func *jfunc, tree base, tree comp_type, gcall *call,
struct ipa_jump_func *jfunc,
HOST_WIDE_INT offset) HOST_WIDE_INT offset)
{ {
struct prop_type_change_info tci; struct prop_type_change_info tci;
ao_ref ao; ao_ref ao;
bool entry_reached = false;
gcc_checking_assert (DECL_P (arg) gcc_checking_assert (DECL_P (arg)
|| TREE_CODE (arg) == MEM_REF || TREE_CODE (arg) == MEM_REF
...@@ -780,9 +780,11 @@ detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type, ...@@ -780,9 +780,11 @@ detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type,
tci.object = get_base_address (arg); tci.object = get_base_address (arg);
tci.type_maybe_changed = false; tci.type_maybe_changed = false;
walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change, int walked
&tci, NULL, &entry_reached); = walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change,
if (!tci.type_maybe_changed) &tci, NULL, NULL, fbi->aa_walk_budget + 1);
if (walked >= 0 && !tci.type_maybe_changed)
return false; return false;
ipa_set_jf_unknown (jfunc); ipa_set_jf_unknown (jfunc);
...@@ -796,8 +798,9 @@ detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type, ...@@ -796,8 +798,9 @@ detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type,
returned by get_ref_base_and_extent, as is the offset. */ returned by get_ref_base_and_extent, as is the offset. */
static bool static bool
detect_type_change (tree arg, tree base, tree comp_type, gcall *call, detect_type_change (ipa_func_body_info *fbi, tree arg, tree base,
struct ipa_jump_func *jfunc, HOST_WIDE_INT offset) tree comp_type, gcall *call, struct ipa_jump_func *jfunc,
HOST_WIDE_INT offset)
{ {
if (!flag_devirtualize) if (!flag_devirtualize)
return false; return false;
...@@ -807,7 +810,7 @@ detect_type_change (tree arg, tree base, tree comp_type, gcall *call, ...@@ -807,7 +810,7 @@ detect_type_change (tree arg, tree base, tree comp_type, gcall *call,
TREE_OPERAND (base, 0), TREE_OPERAND (base, 0),
call)) call))
return false; return false;
return detect_type_change_from_memory_writes (arg, base, comp_type, return detect_type_change_from_memory_writes (fbi, arg, base, comp_type,
call, jfunc, offset); call, jfunc, offset);
} }
...@@ -816,7 +819,7 @@ detect_type_change (tree arg, tree base, tree comp_type, gcall *call, ...@@ -816,7 +819,7 @@ detect_type_change (tree arg, tree base, tree comp_type, gcall *call,
be zero). */ be zero). */
static bool static bool
detect_type_change_ssa (tree arg, tree comp_type, detect_type_change_ssa (ipa_func_body_info *fbi, tree arg, tree comp_type,
gcall *call, struct ipa_jump_func *jfunc) gcall *call, struct ipa_jump_func *jfunc)
{ {
gcc_checking_assert (TREE_CODE (arg) == SSA_NAME); gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
...@@ -830,7 +833,7 @@ detect_type_change_ssa (tree arg, tree comp_type, ...@@ -830,7 +833,7 @@ detect_type_change_ssa (tree arg, tree comp_type,
arg = build2 (MEM_REF, ptr_type_node, arg, arg = build2 (MEM_REF, ptr_type_node, arg,
build_int_cst (ptr_type_node, 0)); build_int_cst (ptr_type_node, 0));
return detect_type_change_from_memory_writes (arg, arg, comp_type, return detect_type_change_from_memory_writes (fbi, arg, arg, comp_type,
call, jfunc, 0); call, jfunc, 0);
} }
...@@ -846,16 +849,6 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED, ...@@ -846,16 +849,6 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
return true; return true;
} }
/* Return true if we have already walked so many statements in AA that we
should really just start giving up. */
static bool
aa_overwalked (struct ipa_func_body_info *fbi)
{
gcc_checking_assert (fbi);
return fbi->aa_walked > (unsigned) PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
}
/* Find the nearest valid aa status for parameter specified by INDEX that /* Find the nearest valid aa status for parameter specified by INDEX that
dominates BB. */ dominates BB. */
...@@ -922,28 +915,24 @@ parm_preserved_before_stmt_p (struct ipa_func_body_info *fbi, int index, ...@@ -922,28 +915,24 @@ parm_preserved_before_stmt_p (struct ipa_func_body_info *fbi, int index,
if (TREE_READONLY (base)) if (TREE_READONLY (base))
return true; return true;
/* FIXME: FBI can be NULL if we are being called from outside gcc_checking_assert (fbi);
ipa_node_analysis or ipcp_transform_function, which currently happens paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
during inlining analysis. It would be great to extend fbi's lifetime and if (paa->parm_modified)
always have it. Currently, we are just not afraid of too much walking in return false;
that case. */
if (fbi)
{
if (aa_overwalked (fbi))
return false;
paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
if (paa->parm_modified)
return false;
}
else
paa = NULL;
gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE); gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
ao_ref_init (&refd, parm_load); ao_ref_init (&refd, parm_load);
int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
&modified, NULL); &modified, NULL, NULL,
if (fbi) fbi->aa_walk_budget + 1);
fbi->aa_walked += walked; if (walked < 0)
{
modified = true;
if (fbi)
fbi->aa_walk_budget = 0;
}
else if (fbi)
fbi->aa_walk_budget -= walked;
if (paa && modified) if (paa && modified)
paa->parm_modified = true; paa->parm_modified = true;
return !modified; return !modified;
...@@ -988,29 +977,24 @@ parm_ref_data_preserved_p (struct ipa_func_body_info *fbi, ...@@ -988,29 +977,24 @@ parm_ref_data_preserved_p (struct ipa_func_body_info *fbi,
bool modified = false; bool modified = false;
ao_ref refd; ao_ref refd;
/* FIXME: FBI can be NULL if we are being called from outside gcc_checking_assert (fbi);
ipa_node_analysis or ipcp_transform_function, which currently happens paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
during inlining analysis. It would be great to extend fbi's lifetime and if (paa->ref_modified)
always have it. Currently, we are just not afraid of too much walking in return false;
that case. */
if (fbi)
{
if (aa_overwalked (fbi))
return false;
paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
if (paa->ref_modified)
return false;
}
else
paa = NULL;
gcc_checking_assert (gimple_vuse (stmt)); gcc_checking_assert (gimple_vuse (stmt));
ao_ref_init (&refd, ref); ao_ref_init (&refd, ref);
int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
&modified, NULL); &modified, NULL, NULL,
if (fbi) fbi->aa_walk_budget + 1);
fbi->aa_walked += walked; if (walked < 0)
if (paa && modified) {
modified = true;
fbi->aa_walk_budget = 0;
}
else
fbi->aa_walk_budget -= walked;
if (modified)
paa->ref_modified = true; paa->ref_modified = true;
return !modified; return !modified;
} }
...@@ -1030,8 +1014,7 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index, ...@@ -1030,8 +1014,7 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index,
function because it is not goin to use it. But do not cache the result function because it is not goin to use it. But do not cache the result
either. Also, no such calculations for non-pointers. */ either. Also, no such calculations for non-pointers. */
if (!gimple_vuse (call) if (!gimple_vuse (call)
|| !POINTER_TYPE_P (TREE_TYPE (parm)) || !POINTER_TYPE_P (TREE_TYPE (parm)))
|| aa_overwalked (fbi))
return false; return false;
struct ipa_param_aa_status *paa = parm_bb_aa_status_for_bb (fbi, struct ipa_param_aa_status *paa = parm_bb_aa_status_for_bb (fbi,
...@@ -1042,8 +1025,15 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index, ...@@ -1042,8 +1025,15 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index,
ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE); ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
int walked = walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, int walked = walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified,
&modified, NULL); &modified, NULL, NULL,
fbi->aa_walked += walked; fbi->aa_walk_budget + 1);
if (walked < 0)
{
fbi->aa_walk_budget = 0;
modified = true;
}
else
fbi->aa_walk_budget -= walked;
if (modified) if (modified)
paa->pt_modified = true; paa->pt_modified = true;
return !modified; return !modified;
...@@ -1851,7 +1841,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi, ...@@ -1851,7 +1841,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
struct ipa_polymorphic_call_context context (cs->caller->decl, struct ipa_polymorphic_call_context context (cs->caller->decl,
arg, cs->call_stmt, arg, cs->call_stmt,
&instance); &instance);
context.get_dynamic_type (instance, arg, NULL, cs->call_stmt); context.get_dynamic_type (instance, arg, NULL, cs->call_stmt,
&fbi->aa_walk_budget);
*ipa_get_ith_polymorhic_call_context (args, n) = context; *ipa_get_ith_polymorhic_call_context (args, n) = context;
if (!context.useless_p ()) if (!context.useless_p ())
useful_context = true; useful_context = true;
...@@ -2324,7 +2315,7 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi, ...@@ -2324,7 +2315,7 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi,
anc_offset = 0; anc_offset = 0;
index = ipa_get_param_decl_index (info, SSA_NAME_VAR (obj)); index = ipa_get_param_decl_index (info, SSA_NAME_VAR (obj));
gcc_assert (index >= 0); gcc_assert (index >= 0);
if (detect_type_change_ssa (obj, obj_type_ref_class (target), if (detect_type_change_ssa (fbi, obj, obj_type_ref_class (target),
call, &jfunc)) call, &jfunc))
return; return;
} }
...@@ -2340,7 +2331,7 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi, ...@@ -2340,7 +2331,7 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi,
index = ipa_get_param_decl_index (info, index = ipa_get_param_decl_index (info,
SSA_NAME_VAR (TREE_OPERAND (expr, 0))); SSA_NAME_VAR (TREE_OPERAND (expr, 0)));
gcc_assert (index >= 0); gcc_assert (index >= 0);
if (detect_type_change (obj, expr, obj_type_ref_class (target), if (detect_type_change (fbi, obj, expr, obj_type_ref_class (target),
call, &jfunc, anc_offset)) call, &jfunc, anc_offset))
return; return;
} }
...@@ -2388,7 +2379,8 @@ ipa_analyze_call_uses (struct ipa_func_body_info *fbi, gcall *call) ...@@ -2388,7 +2379,8 @@ ipa_analyze_call_uses (struct ipa_func_body_info *fbi, gcall *call)
cs->indirect_info->vptr_changed cs->indirect_info->vptr_changed
= !context.get_dynamic_type (instance, = !context.get_dynamic_type (instance,
OBJ_TYPE_REF_OBJECT (target), OBJ_TYPE_REF_OBJECT (target),
obj_type_ref_class (target), call); obj_type_ref_class (target), call,
&fbi->aa_walk_budget);
cs->indirect_info->context = context; cs->indirect_info->context = context;
} }
...@@ -2588,7 +2580,7 @@ ipa_analyze_node (struct cgraph_node *node) ...@@ -2588,7 +2580,7 @@ ipa_analyze_node (struct cgraph_node *node)
fbi.bb_infos = vNULL; fbi.bb_infos = vNULL;
fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun)); fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun));
fbi.param_count = ipa_get_param_count (info); fbi.param_count = ipa_get_param_count (info);
fbi.aa_walked = 0; fbi.aa_walk_budget = PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee) for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee)
{ {
...@@ -5157,7 +5149,7 @@ ipcp_transform_function (struct cgraph_node *node) ...@@ -5157,7 +5149,7 @@ ipcp_transform_function (struct cgraph_node *node)
fbi.bb_infos = vNULL; fbi.bb_infos = vNULL;
fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun)); fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun));
fbi.param_count = param_count; fbi.param_count = param_count;
fbi.aa_walked = 0; fbi.aa_walk_budget = PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
vec_safe_grow_cleared (descriptors, param_count); vec_safe_grow_cleared (descriptors, param_count);
ipa_populate_param_decls (node, *descriptors); ipa_populate_param_decls (node, *descriptors);
......
...@@ -428,8 +428,9 @@ struct ipa_func_body_info ...@@ -428,8 +428,9 @@ struct ipa_func_body_info
/* Number of parameters. */ /* Number of parameters. */
int param_count; int param_count;
/* Number of statements already walked by when analyzing this function. */ /* Number of statements we are still allowed to walked by when analyzing this
unsigned int aa_walked; function. */
unsigned int aa_walk_budget;
}; };
/* ipa_node_params access functions. Please use these to access fields that /* ipa_node_params access functions. Please use these to access fields that
......
...@@ -5275,7 +5275,7 @@ eliminate_dom_walker::eliminate_stmt (basic_block b, gimple_stmt_iterator *gsi) ...@@ -5275,7 +5275,7 @@ eliminate_dom_walker::eliminate_stmt (basic_block b, gimple_stmt_iterator *gsi)
ipa_polymorphic_call_context context (current_function_decl, ipa_polymorphic_call_context context (current_function_decl,
fn, stmt, &instance); fn, stmt, &instance);
context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn),
otr_type, stmt); otr_type, stmt, NULL);
bool final; bool final;
vec <cgraph_node *> targets vec <cgraph_node *> targets
= possible_polymorphic_call_targets (obj_type_ref_class (fn), = possible_polymorphic_call_targets (obj_type_ref_class (fn),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment