aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2013-08-10 00:53:00 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2013-08-09 22:53:00 +0000
commit634ab819546e358bae26a7f798652f1271ae099d (patch)
tree8a4fa2cb049df6b6085971ee7b7c3615601cc693
parent537a6f7b4752b04a5ce4cb1fb96f1f1e9c407402 (diff)
downloadgcc-634ab819546e358bae26a7f798652f1271ae099d.zip
gcc-634ab819546e358bae26a7f798652f1271ae099d.tar.gz
gcc-634ab819546e358bae26a7f798652f1271ae099d.tar.bz2
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
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/cgraph.c5
-rw-r--r--gcc/cgraph.h4
-rw-r--r--gcc/ipa.c84
-rw-r--r--gcc/lto-cgraph.c13
-rw-r--r--gcc/lto-streamer-in.c8
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c19
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c40
9 files changed, 189 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bca5102..83b73b7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,22 @@
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
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 43b4994..b3b9e25 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -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",
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index f67287f..e430533 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -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. */
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 9905ba7..c870a6f 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -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++)
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index e0d0991..fcba1b9 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -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);
}
}
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 0684cda..6430359 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e440403..39fee31 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+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*-*-*.
diff --git a/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c
new file mode 100644
index 0000000..3021425
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c
@@ -0,0 +1,19 @@
+/* { 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 ();
+}
diff --git a/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c
new file mode 100644
index 0000000..a94195c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c
@@ -0,0 +1,40 @@
+/* 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