Commit 09ce3660 by Jan Hubicka Committed by Jan Hubicka

cgraph.c (cgraph_turn_edge_to_speculative): Return newly introduced edge; fix typo in sanity check.


	* cgraph.c (cgraph_turn_edge_to_speculative): Return newly
	introduced edge; fix typo in sanity check.
	(cgraph_resolve_speculation): Export; improve diagnostic.
	(cgraph_redirect_edge_call_stmt_to_callee): Better diagnostic; cancel
	speculation at type mismatch.
	* cgraph.h (cgraph_turn_edge_to_speculative): Update.
	(cgraph_resolve_speculation): Declare.
	(symtab_can_be_discarded): New function.
	* value-prof.c (gimple_ic_transform): Remove actual transform code.
	* ipa-inline-transform.c (speculation_removed): New global var.
	(clone_inlined_nodes): See if speculation can be removed.
	(inline_call): If speculations was removed, we growths may not match.
	* ipa-inline.c (can_inline_edge_p): Add DISREGARD_LIMITS parameter.
	(speculation_useful_p): New function.
	(resolve_noninline_speculation): New function.
	(inline_small_functions): Resolve useless speculations.
	* ipa-inline.h (speculation_useful_p): Declare
	* ipa.c (can_replace_by_local_alias): Simplify.
	(ipa_profile): Produce speculative calls in non-lto, too;
	add simple cost model; produce local aliases.

From-SVN: r201683
parent 537e035c
2013-08-13 Jan Hubicka <jh@suse.cz>
* cgraph.c (cgraph_turn_edge_to_speculative): Return newly
introduced edge; fix typo in sanity check.
(cgraph_resolve_speculation): Export; improve diagnostic.
(cgraph_redirect_edge_call_stmt_to_callee): Better diagnostic; cancel
speculation at type mismatch.
* cgraph.h (cgraph_turn_edge_to_speculative): Update.
(cgraph_resolve_speculation): Declare.
(symtab_can_be_discarded): New function.
* value-prof.c (gimple_ic_transform): Remove actual transform code.
* ipa-inline-transform.c (speculation_removed): New global var.
(clone_inlined_nodes): See if speculation can be removed.
(inline_call): If speculations was removed, we growths may not match.
* ipa-inline.c (can_inline_edge_p): Add DISREGARD_LIMITS parameter.
(speculation_useful_p): New function.
(resolve_noninline_speculation): New function.
(inline_small_functions): Resolve useless speculations.
* ipa-inline.h (speculation_useful_p): Declare
* ipa.c (can_replace_by_local_alias): Simplify.
(ipa_profile): Produce speculative calls in non-lto, too;
add simple cost model; produce local aliases.
2013-08-13 David Malcolm <dmalcolm@redhat.com>
* config/i386/t-i386 (i386.o): Rename stray PIPELINE_H to
......
......@@ -1040,9 +1040,11 @@ cgraph_set_edge_callee (struct cgraph_edge *e, struct cgraph_node *n)
At this time the function just creates the direct call,
the referencd representing the if conditional and attaches
them all to the orginal indirect call statement. */
them all to the orginal indirect call statement.
void
Return direct edge created. */
struct cgraph_edge *
cgraph_turn_edge_to_speculative (struct cgraph_edge *e,
struct cgraph_node *n2,
gcov_type direct_count,
......@@ -1073,6 +1075,7 @@ cgraph_turn_edge_to_speculative (struct cgraph_edge *e,
IPA_REF_ADDR, e->call_stmt);
ref->lto_stmt_uid = e->lto_stmt_uid;
ref->speculative = e->speculative;
return e2;
}
/* Speculative call consist of three components:
......@@ -1107,7 +1110,7 @@ cgraph_speculative_call_info (struct cgraph_edge *e,
if (e2->call_stmt)
{
e = cgraph_edge (e->caller, e2->call_stmt);
gcc_assert (!e->speculative && !e->indirect_unknown_callee);
gcc_assert (e->speculative && !e->indirect_unknown_callee);
}
else
for (e = e->caller->callees;
......@@ -1147,7 +1150,7 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n)
Remove the speculative call sequence and return edge representing the call.
It is up to caller to redirect the call as appropriate. */
static struct cgraph_edge *
struct cgraph_edge *
cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl)
{
struct cgraph_edge *e2;
......@@ -1159,12 +1162,21 @@ cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl)
{
if (dump_file)
{
fprintf (dump_file, "Speculative indirect call %s/%i => %s/%i has "
"turned out to have contradicitng known target ",
xstrdup (cgraph_node_name (edge->caller)), edge->caller->symbol.order,
xstrdup (cgraph_node_name (e2->callee)), e2->callee->symbol.order);
print_generic_expr (dump_file, callee_decl, 0);
fprintf (dump_file, "\n");
if (callee_decl)
{
fprintf (dump_file, "Speculative indirect call %s/%i => %s/%i has "
"turned out to have contradicting known target ",
xstrdup (cgraph_node_name (edge->caller)), edge->caller->symbol.order,
xstrdup (cgraph_node_name (e2->callee)), e2->callee->symbol.order);
print_generic_expr (dump_file, callee_decl, 0);
fprintf (dump_file, "\n");
}
else
{
fprintf (dump_file, "Removing speculative call %s/%i => %s/%i\n",
xstrdup (cgraph_node_name (edge->caller)), edge->caller->symbol.order,
xstrdup (cgraph_node_name (e2->callee)), e2->callee->symbol.order);
}
}
}
else
......@@ -1264,12 +1276,24 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
cgraph_speculative_call_info (e, e, e2, ref);
if (gimple_call_fndecl (e->call_stmt))
e = cgraph_resolve_speculation (e, gimple_call_fndecl (e->call_stmt));
else
if (!gimple_check_call_matching_types (e->call_stmt, e->callee->symbol.decl,
true))
{
e = cgraph_resolve_speculation (e, NULL);
if (dump_file)
fprintf (dump_file, "Expanding speculative call of %s/%i -> %s/%i\n",
fprintf (dump_file, "Not expanding speculative call of %s/%i -> %s/%i\n"
"Type mismatch.\n",
xstrdup (cgraph_node_name (e->caller)), e->caller->symbol.order,
xstrdup (cgraph_node_name (e->callee)), e->callee->symbol.order);
}
else
{
if (dump_file)
fprintf (dump_file, "Expanding speculative call of %s/%i -> %s/%i count:"
HOST_WIDEST_INT_PRINT_DEC"\n",
xstrdup (cgraph_node_name (e->caller)), e->caller->symbol.order,
xstrdup (cgraph_node_name (e->callee)), e->callee->symbol.order,
(HOST_WIDEST_INT)e->count);
gcc_assert (e2->speculative);
push_cfun (DECL_STRUCT_FUNCTION (e->caller->symbol.decl));
new_stmt = gimple_ic (e->call_stmt, cgraph (ref->referred),
......
......@@ -726,7 +726,7 @@ bool cgraph_propagate_frequency (struct cgraph_node *node);
struct cgraph_node * cgraph_function_node (struct cgraph_node *,
enum availability *avail = NULL);
bool cgraph_get_body (struct cgraph_node *node);
void
struct cgraph_edge *
cgraph_turn_edge_to_speculative (struct cgraph_edge *,
struct cgraph_node *,
gcov_type, int);
......@@ -783,6 +783,7 @@ struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
basic_block, const char *);
void tree_function_versioning (tree, tree, vec<ipa_replace_map_p, va_gc> *,
bool, bitmap, bool, bitmap, basic_block);
struct cgraph_edge *cgraph_resolve_speculation (struct cgraph_edge *, tree);
/* In cgraphbuild.c */
unsigned int rebuild_cgraph_edges (void);
......@@ -1398,4 +1399,16 @@ symtab_real_symbol_p (symtab_node node)
return false;
return true;
}
/* Return true if NODE can be discarded by linker from the binary. */
static inline bool
symtab_can_be_discarded (symtab_node node)
{
return (DECL_EXTERNAL (node->symbol.decl)
|| (DECL_ONE_ONLY (node->symbol.decl)
&& node->symbol.resolution != LDPR_PREVAILING_DEF
&& node->symbol.resolution != LDPR_PREVAILING_DEF_IRONLY
&& node->symbol.resolution != LDPR_PREVAILING_DEF_IRONLY_EXP));
}
#endif /* GCC_CGRAPH_H */
......@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
int ncalls_inlined;
int nfunctions_inlined;
bool speculation_removed;
/* Scale frequency of NODE edges by FREQ_SCALE. */
......@@ -134,6 +135,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
bool update_original, int *overall_size)
{
struct cgraph_node *inlining_into;
struct cgraph_edge *next;
if (e->caller->global.inlined_to)
inlining_into = e->caller->global.inlined_to;
......@@ -186,9 +188,17 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
e->callee->global.inlined_to = inlining_into;
/* Recursively clone all bodies. */
for (e = e->callee->callees; e; e = e->next_callee)
if (!e->inline_failed)
clone_inlined_nodes (e, duplicate, update_original, overall_size);
for (e = e->callee->callees; e; e = next)
{
next = e->next_callee;
if (!e->inline_failed)
clone_inlined_nodes (e, duplicate, update_original, overall_size);
if (e->speculative && !speculation_useful_p (e, true))
{
cgraph_resolve_speculation (e, NULL);
speculation_removed = true;
}
}
}
......@@ -218,6 +228,7 @@ inline_call (struct cgraph_edge *e, bool update_original,
bool predicated = inline_edge_summary (e)->predicate != NULL;
#endif
speculation_removed = false;
/* Don't inline inlined edges. */
gcc_assert (e->inline_failed);
/* Don't even think of inlining inline clone. */
......@@ -267,6 +278,7 @@ inline_call (struct cgraph_edge *e, bool update_original,
error due to INLINE_SIZE_SCALE roudoff errors. */
gcc_assert (!update_overall_summary || !overall_size || new_edges_found
|| abs (estimated_growth - (new_size - old_size)) <= 1
|| speculation_removed
/* FIXME: a hack. Edges with false predicate are accounted
wrong, we should remove them from callgraph. */
|| predicated);
......
......@@ -226,6 +226,7 @@ inline_hints do_estimate_edge_hints (struct cgraph_edge *edge);
void initialize_growth_caches (void);
void free_growth_caches (void);
void compute_inline_parameters (struct cgraph_node *, bool);
bool speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining);
/* In ipa-inline-transform.c */
bool inline_call (struct cgraph_edge *, bool, vec<cgraph_edge_p> *, int *, bool);
......
......@@ -768,11 +768,7 @@ bool
can_replace_by_local_alias (symtab_node node)
{
return (symtab_node_availability (node) > AVAIL_OVERWRITABLE
&& !DECL_EXTERNAL (node->symbol.decl)
&& (!DECL_ONE_ONLY (node->symbol.decl)
|| node->symbol.resolution == LDPR_PREVAILING_DEF
|| node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY
|| node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP));
&& !symtab_can_be_discarded (node));
}
/* Mark visibility of all functions.
......@@ -1407,53 +1403,9 @@ ipa_profile (void)
bool something_changed = false;
int i;
gcov_type overall_time = 0, cutoff = 0, cumulated = 0, overall_size = 0;
/* Produce speculative calls: we saved common traget from porfiling into
e->common_target_id. Now, at link time, we can look up corresponding
function node and produce speculative call. */
if (in_lto_p)
{
struct cgraph_edge *e;
struct cgraph_node *n,*n2;
init_node_map (false);
FOR_EACH_DEFINED_FUNCTION (n)
{
bool update = false;
for (e = n->indirect_calls; e; e = e->next_callee)
if (e->indirect_info->common_target_id)
{
n2 = find_func_by_profile_id (e->indirect_info->common_target_id);
if (n2)
{
if (dump_file)
{
fprintf (dump_file, "Indirect call -> direct call from"
" other module %s/%i => %s/%i, prob %3.2f\n",
xstrdup (cgraph_node_name (n)), n->symbol.order,
xstrdup (cgraph_node_name (n2)), n2->symbol.order,
e->indirect_info->common_target_probability
/ (float)REG_BR_PROB_BASE);
}
cgraph_turn_edge_to_speculative
(e, n2,
apply_scale (e->count,
e->indirect_info->common_target_probability),
apply_scale (e->frequency,
e->indirect_info->common_target_probability));
update = true;
}
else
if (dump_file)
fprintf (dump_file, "Function with profile-id %i not found.\n",
e->indirect_info->common_target_id);
}
if (update)
inline_update_overall_summary (n);
}
del_node_map ();
}
struct cgraph_node *n,*n2;
int nindirect = 0, ncommon = 0, nunknown = 0, nuseless = 0, nconverted = 0;
bool node_map_initialized = false;
if (dump_file)
dump_histogram (dump_file, histogram);
......@@ -1523,6 +1475,106 @@ ipa_profile (void)
histogram.release();
free_alloc_pool (histogram_pool);
/* Produce speculative calls: we saved common traget from porfiling into
e->common_target_id. Now, at link time, we can look up corresponding
function node and produce speculative call. */
FOR_EACH_DEFINED_FUNCTION (n)
{
bool update = false;
for (e = n->indirect_calls; e; e = e->next_callee)
{
if (n->count)
nindirect++;
if (e->indirect_info->common_target_id)
{
if (!node_map_initialized)
init_node_map (false);
node_map_initialized = true;
ncommon++;
n2 = find_func_by_profile_id (e->indirect_info->common_target_id);
if (n2)
{
if (dump_file)
{
fprintf (dump_file, "Indirect call -> direct call from"
" other module %s/%i => %s/%i, prob %3.2f\n",
xstrdup (cgraph_node_name (n)), n->symbol.order,
xstrdup (cgraph_node_name (n2)), n2->symbol.order,
e->indirect_info->common_target_probability
/ (float)REG_BR_PROB_BASE);
}
if (e->indirect_info->common_target_probability
< REG_BR_PROB_BASE / 2)
{
nuseless++;
if (dump_file)
fprintf (dump_file,
"Not speculating: probability is too low.\n");
}
else if (!cgraph_maybe_hot_edge_p (e))
{
nuseless++;
if (dump_file)
fprintf (dump_file,
"Not speculating: call is cold.\n");
}
else if (cgraph_function_body_availability (n2)
<= AVAIL_OVERWRITABLE
&& symtab_can_be_discarded ((symtab_node) n2))
{
nuseless++;
if (dump_file)
fprintf (dump_file,
"Not speculating: target is overwritable "
"and can be discarded.\n");
}
else
{
/* Target may be overwritable, but profile says that
control flow goes to this particular implementation
of N2. Speculate on the local alias to allow inlining.
*/
if (!symtab_can_be_discarded ((symtab_node) n2))
n2 = cgraph (symtab_nonoverwritable_alias ((symtab_node)n2));
nconverted++;
cgraph_turn_edge_to_speculative
(e, n2,
apply_scale (e->count,
e->indirect_info->common_target_probability),
apply_scale (e->frequency,
e->indirect_info->common_target_probability));
update = true;
}
}
else
{
if (dump_file)
fprintf (dump_file, "Function with profile-id %i not found.\n",
e->indirect_info->common_target_id);
nunknown++;
}
}
}
if (update)
inline_update_overall_summary (n);
}
if (node_map_initialized)
del_node_map ();
if (dump_file && nindirect)
fprintf (dump_file,
"%i indirect calls trained.\n"
"%i (%3.2f%%) have common target.\n"
"%i (%3.2f%%) targets was not found.\n"
"%i (%3.2f%%) speculations seems useless.\n"
"%i (%3.2f%%) speculations produced.\n",
nindirect,
ncommon, ncommon * 100.0 / nindirect,
nunknown, nunknown * 100.0 / nindirect,
nuseless, nuseless * 100.0 / nindirect,
nconverted, nconverted * 100.0 / nindirect);
order_pos = ipa_reverse_postorder (order);
for (i = order_pos - 1; i >= 0; i--)
{
......
......@@ -1431,8 +1431,6 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
gimple stmt = gsi_stmt (*gsi);
histogram_value histogram;
gcov_type val, count, all, bb_all;
gcov_type prob;
gimple modify;
struct cgraph_node *direct_call;
if (gimple_code (stmt) != GIMPLE_CALL)
......@@ -1452,12 +1450,6 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
count = histogram->hvalue.counters [1];
all = histogram->hvalue.counters [2];
if (4 * count <= 3 * all)
{
gimple_remove_histogram_value (cfun, stmt, histogram);
return false;
}
bb_all = gimple_bb (stmt)->count;
/* The order of CHECK_COUNTER calls is important -
since check_counter can correct the third parameter
......@@ -1469,10 +1461,9 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
return false;
}
if (all > 0)
prob = GCOV_COMPUTE_SCALE (count, all);
else
prob = 0;
if (4 * count <= 3 * all)
return false;
direct_call = find_func_by_profile_id ((int)val);
if (direct_call == NULL)
......@@ -1488,12 +1479,21 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
}
return false;
}
gimple_remove_histogram_value (cfun, stmt, histogram);
if (!check_ic_target (stmt, direct_call))
return false;
modify = gimple_ic (stmt, direct_call, prob, count, all);
{
if (dump_file)
{
fprintf (dump_file, "Indirect call -> direct call ");
print_generic_expr (dump_file, gimple_call_fn (stmt), TDF_SLIM);
fprintf (dump_file, "=> ");
print_generic_expr (dump_file, direct_call->symbol.decl, TDF_SLIM);
fprintf (dump_file, " transformation skipped because of type mismatch");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
gimple_remove_histogram_value (cfun, stmt, histogram);
return false;
}
if (dump_file)
{
......@@ -1501,10 +1501,8 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
print_generic_expr (dump_file, gimple_call_fn (stmt), TDF_SLIM);
fprintf (dump_file, "=> ");
print_generic_expr (dump_file, direct_call->symbol.decl, TDF_SLIM);
fprintf (dump_file, " transformation on insn ");
fprintf (dump_file, " transformation on insn postponned to ipa-profile");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
fprintf (dump_file, " to ");
print_gimple_stmt (dump_file, modify, 0, TDF_SLIM);
fprintf (dump_file, "hist->count "HOST_WIDEST_INT_PRINT_DEC
" hist->all "HOST_WIDEST_INT_PRINT_DEC"\n", count, all);
}
......
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