Commit 634ab819 by Jan Hubicka Committed by Jan Hubicka

cgraph.c (cgraph_resolve_speculation): Cut frequency to CGRAPH_FREQ_MAX.

	* cgraph.c (cgraph_resolve_speculation): Cut frequency to
	CGRAPH_FREQ_MAX.
	(dump_cgraph_node): Dump profile-id.
	* cgraph.h (cgraph_indirect_call_info): Add common_target_id
	and common_target_probability.
	* lto-cgraph.c (lto_output_edge): Stream common targets.
	(lto_output_node): Stream profile ids.
	(input_node): Stream profile ids.
	(input_edge): Stream common targets.
	* lto-streamer-in.c (fixup_call_stmt_edges_1): Fix formatting.
	* ipa.c: Include value-prof.h
	(ipa_profile_generate_summary): Turn indirect call statement histograms
	into common targets.
	(ipa_profile): Turn common targets into speculative edges.

	* gcc.dg/tree-prof/crossmodule-indircall-1.c: New testcase.
	* gcc.dg/tree-prof/crossmodule-indircall-1a.c: New testcase.

From-SVN: r201639
parent 537a6f7b
2013-08-09 Jan Hubicka <jh@suse.cz>
* cgraph.c (cgraph_resolve_speculation): Cut frequency to
CGRAPH_FREQ_MAX.
(dump_cgraph_node): Dump profile-id.
* cgraph.h (cgraph_indirect_call_info): Add common_target_id
and common_target_probability.
* lto-cgraph.c (lto_output_edge): Stream common targets.
(lto_output_node): Stream profile ids.
(input_node): Stream profile ids.
(input_edge): Stream common targets.
* lto-streamer-in.c (fixup_call_stmt_edges_1): Fix formatting.
* ipa.c: Include value-prof.h
(ipa_profile_generate_summary): Turn indirect call statement histograms
into common targets.
(ipa_profile): Turn common targets into speculative edges.
2013-08-09 Jan Hubicka <jh@suse.cz>
* cgraph.h (cgraph_node): Add profile_id.
* value-prof.c (cgraph_node_map): Turn into pointer_map.
(init_node_map): Rewrite to handle hashes increas of incremental
......
......@@ -1176,6 +1176,8 @@ cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl)
}
edge->count += e2->count;
edge->frequency += e2->frequency;
if (edge->frequency > CGRAPH_FREQ_MAX)
edge->frequency = CGRAPH_FREQ_MAX;
edge->speculative = false;
e2->speculative = false;
if (e2->indirect_unknown_callee || e2->inline_failed)
......@@ -1801,6 +1803,9 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
fprintf (f, " Availability: %s\n",
cgraph_availability_names [cgraph_function_body_availability (node)]);
if (node->profile_id)
fprintf (f, " Profile id: %i\n",
node->profile_id);
fprintf (f, " Function flags:");
if (node->count)
fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x",
......
......@@ -435,6 +435,10 @@ struct GTY(()) cgraph_indirect_call_info
int param_index;
/* ECF flags determined from the caller. */
int ecf_flags;
/* Profile_id of common target obtrained from profile. */
int common_target_id;
/* Probability that call will land in function with COMMON_TARGET_ID. */
int common_target_probability;
/* Set when the call is a virtual call with the parameter being the
associated object pointer rather than a simple direct call. */
......
......@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "params.h"
#include "lto-streamer.h"
#include "data-streamer.h"
#include "value-prof.h"
/* Return true when NODE can not be local. Worker for cgraph_local_node_p. */
......@@ -1291,8 +1292,40 @@ ipa_profile_generate_summary (void)
int size = 0;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
time += estimate_num_insns (gsi_stmt (gsi), &eni_time_weights);
size += estimate_num_insns (gsi_stmt (gsi), &eni_size_weights);
gimple stmt = gsi_stmt (gsi);
if (gimple_code (stmt) == GIMPLE_CALL
&& !gimple_call_fndecl (stmt))
{
histogram_value h;
h = gimple_histogram_value_of_type
(DECL_STRUCT_FUNCTION (node->symbol.decl),
stmt, HIST_TYPE_INDIR_CALL);
/* No need to do sanity check: gimple_ic_transform already
takes away bad histograms. */
if (h)
{
/* counter 0 is target, counter 1 is number of execution we called target,
counter 2 is total number of executions. */
if (h->hvalue.counters[2])
{
struct cgraph_edge * e = cgraph_edge (node, stmt);
e->indirect_info->common_target_id
= h->hvalue.counters [0];
e->indirect_info->common_target_probability
= GCOV_COMPUTE_SCALE (h->hvalue.counters [1], h->hvalue.counters [2]);
if (e->indirect_info->common_target_probability > REG_BR_PROB_BASE)
{
if (dump_file)
fprintf (dump_file, "Probability capped to 1\n");
e->indirect_info->common_target_probability = REG_BR_PROB_BASE;
}
}
gimple_remove_histogram_value (DECL_STRUCT_FUNCTION (node->symbol.decl),
stmt, h);
}
}
time += estimate_num_insns (stmt, &eni_time_weights);
size += estimate_num_insns (stmt, &eni_size_weights);
}
account_time_size (hashtable, histogram, bb->count, time, size);
}
......@@ -1375,6 +1408,53 @@ ipa_profile (void)
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 ();
}
if (dump_file)
dump_histogram (dump_file, histogram);
for (i = 0; i < (int)histogram.length (); i++)
......
......@@ -299,6 +299,14 @@ lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge,
| ECF_NOVOPS)));
}
streamer_write_bitpack (&bp);
if (edge->indirect_unknown_callee)
{
streamer_write_hwi_stream (ob->main_stream,
edge->indirect_info->common_target_id);
if (edge->indirect_info->common_target_id)
streamer_write_hwi_stream
(ob->main_stream, edge->indirect_info->common_target_probability);
}
}
/* Return if LIST contain references from other partitions. */
......@@ -519,6 +527,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
streamer_write_uhwi_stream (ob->main_stream, node->thunk.fixed_offset);
streamer_write_uhwi_stream (ob->main_stream, node->thunk.virtual_value);
}
streamer_write_hwi_stream (ob->main_stream, node->profile_id);
}
/* Output the varpool NODE to OB.
......@@ -1057,6 +1066,7 @@ input_node (struct lto_file_decl_data *file_data,
}
if (node->symbol.alias && !node->symbol.analyzed && node->symbol.weakref)
node->symbol.alias_target = get_alias_symbol (node->symbol.decl);
node->profile_id = streamer_read_hwi (ib);
return node;
}
......@@ -1205,6 +1215,9 @@ input_edge (struct lto_input_block *ib, vec<symtab_node> nodes,
if (bp_unpack_value (&bp, 1))
ecf_flags |= ECF_RETURNS_TWICE;
edge->indirect_info->ecf_flags = ecf_flags;
edge->indirect_info->common_target_id = streamer_read_hwi (ib);
if (edge->indirect_info->common_target_id)
edge->indirect_info->common_target_probability = streamer_read_hwi (ib);
}
}
......
......@@ -765,18 +765,18 @@ fixup_call_stmt_edges_1 (struct cgraph_node *node, gimple *stmts,
for (cedge = node->callees; cedge; cedge = cedge->next_callee)
{
if (gimple_stmt_max_uid (fn) < cedge->lto_stmt_uid)
fatal_error ("Cgraph edge statement index out of range");
fatal_error ("Cgraph edge statement index out of range");
cedge->call_stmt = stmts[cedge->lto_stmt_uid - 1];
if (!cedge->call_stmt)
fatal_error ("Cgraph edge statement index not found");
fatal_error ("Cgraph edge statement index not found");
}
for (cedge = node->indirect_calls; cedge; cedge = cedge->next_callee)
{
if (gimple_stmt_max_uid (fn) < cedge->lto_stmt_uid)
fatal_error ("Cgraph edge statement index out of range");
fatal_error ("Cgraph edge statement index out of range");
cedge->call_stmt = stmts[cedge->lto_stmt_uid - 1];
if (!cedge->call_stmt)
fatal_error ("Cgraph edge statement index not found");
fatal_error ("Cgraph edge statement index not found");
}
for (i = 0;
ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref);
......
2013-08-09 Jan Hubicka <jh@suse.cz>
* gcc.dg/tree-prof/crossmodule-indircall-1.c: New testcase.
* gcc.dg/tree-prof/crossmodule-indircall-1a.c: New testcase.
2013-08-09 Yufeng Zhang <yufeng.zhang@arm.com>
* gcc.dg/lower-subreg-1.c: Skip aarch64*-*-*.
......
/* { dg-require-effective-target lto } */
/* { dg-additional-sources "crossmodule-indircall-1a.c" } */
/* { dg-options "-O3 -flto -DDOJOB=1" } */
int a;
extern void (*p[2])(int n);
void abort (void);
main()
{ int i;
/* This call shall be converted. */
for (i = 0;i<1000;i++)
p[0](1);
/* This call shall not be converted. */
for (i = 0;i<1000;i++)
p[i%2](2);
if (a != 1000)
abort ();
}
/* It seems there is no way to avoid the other source of mulitple
source testcase from being compiled independently. Just avoid
error. */
#ifdef DOJOB
extern int a;
void abort (void);
#ifdef _PROFILE_USE
__attribute__ ((externally_visible))
int constval=1,constval2=2;
#else
__attribute__ ((externally_visible))
int constval=3,constval2=2;
#endif
void
add(int i)
{
/* Verify that inlining happens for first case. */
if (i==constval && !__builtin_constant_p (i))
abort ();
/* Second case has no dominating target; it should not inline. */
if (i==constval2 && __builtin_constant_p (i))
abort ();
a += i;
}
void
sub(int i)
{
a -= i;
}
__attribute__ ((externally_visible))
void (*p[2])(int)={add, sub};
#else
main()
{
return 0;
}
#endif
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