From 6a261305108413215d49b3914ac78faa5572231c Mon Sep 17 00:00:00 2001 From: hubicka Date: Fri, 9 Aug 2013 22:53:00 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@201639 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 17 ++++ gcc/cgraph.c | 5 ++ gcc/cgraph.h | 4 + gcc/ipa.c | 84 ++++++++++++++++++- gcc/lto-cgraph.c | 13 +++ gcc/lto-streamer-in.c | 8 +- gcc/testsuite/ChangeLog | 5 ++ .../tree-prof/crossmodule-indircall-1.c | 19 +++++ .../tree-prof/crossmodule-indircall-1a.c | 40 +++++++++ 9 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bca5102de92b..83b73b72c250 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2013-08-09 Jan Hubicka + + * 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 * cgraph.h (cgraph_node): Add profile_id. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 43b499489f90..b3b9e2586287 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 f67287fc78dd..e43053333830 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 9905ba78d665..c870a6f06784 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 e0d09913ae75..fcba1b92acd0 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 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 0684cdaa7bad..643035932722 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 e44040390893..39fee31b1e68 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-08-09 Jan Hubicka + + * 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 * 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 000000000000..3021425893f7 --- /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 000000000000..a94195cd95fe --- /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 -- 2.47.2