aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2019-01-01 13:49:18 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2019-01-01 12:49:18 +0000
commit962e88a9f5a19736412f8b17b24464e2b700f002 (patch)
tree1f3f47a623168992283688de2d7a2a6b07341b11
parenta5544970246db337977bb8b69ab120e9ef209317 (diff)
downloadgcc-962e88a9f5a19736412f8b17b24464e2b700f002.zip
gcc-962e88a9f5a19736412f8b17b24464e2b700f002.tar.gz
gcc-962e88a9f5a19736412f8b17b24464e2b700f002.tar.bz2
coverage.c (get_coverage_counts): Use current_function_decl.
* coverage.c (get_coverage_counts): Use current_function_decl. * profile.c (read_thunk_profile): New function. (branch_prob): Add THUNK parameter. * tree-profile.c (tree_profiling): Handle thunks. * value-prof.c (init_node_map): Handle thunks. * value-prof.h (branch_prob): Upate prototype. (read_thunk_profile): Declare. * g++.dg/tree-prof/devirt.C: Update testcase. From-SVN: r267495
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/coverage.c2
-rw-r--r--gcc/profile.c250
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/tree-prof/devirt.C4
-rw-r--r--gcc/tree-profile.c28
-rw-r--r--gcc/value-prof.c2
-rw-r--r--gcc/value-prof.h3
8 files changed, 191 insertions, 112 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 53e546f..f7c7109 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2019-01-01 Jan Hubicka <hubicka@ucw.cz>
+
+ * coverage.c (get_coverage_counts): Use current_function_decl.
+ * profile.c (read_thunk_profile): New function.
+ (branch_prob): Add THUNK parameter.
+ * tree-profile.c (tree_profiling): Handle thunks.
+ * value-prof.c (init_node_map): Handle thunks.
+ * value-prof.h (branch_prob): Upate prototype.
+ (read_thunk_profile): Declare.
+
2019-01-01 Jakub Jelinek <jakub@redhat.com>
Update copyright years.
diff --git a/gcc/coverage.c b/gcc/coverage.c
index 0e1873b..a34c5da 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -329,7 +329,7 @@ get_coverage_counts (unsigned counter, unsigned cfg_checksum,
else
{
gcc_assert (coverage_node_map_initialized_p ());
- elt.ident = cgraph_node::get (cfun->decl)->profile_id;
+ elt.ident = cgraph_node::get (current_function_decl)->profile_id;
}
elt.ctr = counter;
entry = counts_hash->find (&elt);
diff --git a/gcc/profile.c b/gcc/profile.c
index 14b35ff..7374b0d 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -963,6 +963,25 @@ compare_freqs (const void *p1, const void *p2)
return e2->dest->index - e1->dest->index;
}
+/* Only read execution count for thunks. */
+
+void
+read_thunk_profile (struct cgraph_node *node)
+{
+ tree old = current_function_decl;
+ current_function_decl = node->decl;
+ gcov_type *counts = get_coverage_counts (GCOV_COUNTER_ARCS, 0, 0, 1);
+ if (counts)
+ {
+ node->callees->count = node->count
+ = profile_count::from_gcov_type (counts[0]);
+ free (counts);
+ }
+ current_function_decl = old;
+ return;
+}
+
+
/* Instrument and/or analyze program behavior based on program the CFG.
This function creates a representation of the control flow graph (of
@@ -983,7 +1002,7 @@ compare_freqs (const void *p1, const void *p2)
Main entry point of this file. */
void
-branch_prob (void)
+branch_prob (bool thunk)
{
basic_block bb;
unsigned i;
@@ -1000,118 +1019,121 @@ branch_prob (void)
hash_set <location_triplet_hash> streamed_locations;
- /* We can't handle cyclic regions constructed using abnormal edges.
- To avoid these we replace every source of abnormal edge by a fake
- edge from entry node and every destination by fake edge to exit.
- This keeps graph acyclic and our calculation exact for all normal
- edges except for exit and entrance ones.
-
- We also add fake exit edges for each call and asm statement in the
- basic, since it may not return. */
-
- FOR_EACH_BB_FN (bb, cfun)
+ if (!thunk)
{
- int need_exit_edge = 0, need_entry_edge = 0;
- int have_exit_edge = 0, have_entry_edge = 0;
- edge e;
- edge_iterator ei;
+ /* We can't handle cyclic regions constructed using abnormal edges.
+ To avoid these we replace every source of abnormal edge by a fake
+ edge from entry node and every destination by fake edge to exit.
+ This keeps graph acyclic and our calculation exact for all normal
+ edges except for exit and entrance ones.
- /* Functions returning multiple times are not handled by extra edges.
- Instead we simply allow negative counts on edges from exit to the
- block past call and corresponding probabilities. We can't go
- with the extra edges because that would result in flowgraph that
- needs to have fake edges outside the spanning tree. */
+ We also add fake exit edges for each call and asm statement in the
+ basic, since it may not return. */
- FOR_EACH_EDGE (e, ei, bb->succs)
+ FOR_EACH_BB_FN (bb, cfun)
{
- gimple_stmt_iterator gsi;
- gimple *last = NULL;
-
- /* It may happen that there are compiler generated statements
- without a locus at all. Go through the basic block from the
- last to the first statement looking for a locus. */
- for (gsi = gsi_last_nondebug_bb (bb);
- !gsi_end_p (gsi);
- gsi_prev_nondebug (&gsi))
+ int need_exit_edge = 0, need_entry_edge = 0;
+ int have_exit_edge = 0, have_entry_edge = 0;
+ edge e;
+ edge_iterator ei;
+
+ /* Functions returning multiple times are not handled by extra edges.
+ Instead we simply allow negative counts on edges from exit to the
+ block past call and corresponding probabilities. We can't go
+ with the extra edges because that would result in flowgraph that
+ needs to have fake edges outside the spanning tree. */
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
{
- last = gsi_stmt (gsi);
- if (!RESERVED_LOCATION_P (gimple_location (last)))
- break;
- }
+ gimple_stmt_iterator gsi;
+ gimple *last = NULL;
+
+ /* It may happen that there are compiler generated statements
+ without a locus at all. Go through the basic block from the
+ last to the first statement looking for a locus. */
+ for (gsi = gsi_last_nondebug_bb (bb);
+ !gsi_end_p (gsi);
+ gsi_prev_nondebug (&gsi))
+ {
+ last = gsi_stmt (gsi);
+ if (!RESERVED_LOCATION_P (gimple_location (last)))
+ break;
+ }
- /* Edge with goto locus might get wrong coverage info unless
- it is the only edge out of BB.
- Don't do that when the locuses match, so
- if (blah) goto something;
- is not computed twice. */
- if (last
- && gimple_has_location (last)
- && !RESERVED_LOCATION_P (e->goto_locus)
- && !single_succ_p (bb)
- && (LOCATION_FILE (e->goto_locus)
- != LOCATION_FILE (gimple_location (last))
- || (LOCATION_LINE (e->goto_locus)
- != LOCATION_LINE (gimple_location (last)))))
+ /* Edge with goto locus might get wrong coverage info unless
+ it is the only edge out of BB.
+ Don't do that when the locuses match, so
+ if (blah) goto something;
+ is not computed twice. */
+ if (last
+ && gimple_has_location (last)
+ && !RESERVED_LOCATION_P (e->goto_locus)
+ && !single_succ_p (bb)
+ && (LOCATION_FILE (e->goto_locus)
+ != LOCATION_FILE (gimple_location (last))
+ || (LOCATION_LINE (e->goto_locus)
+ != LOCATION_LINE (gimple_location (last)))))
+ {
+ basic_block new_bb = split_edge (e);
+ edge ne = single_succ_edge (new_bb);
+ ne->goto_locus = e->goto_locus;
+ }
+ if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
+ && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
+ need_exit_edge = 1;
+ if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+ have_exit_edge = 1;
+ }
+ FOR_EACH_EDGE (e, ei, bb->preds)
{
- basic_block new_bb = split_edge (e);
- edge ne = single_succ_edge (new_bb);
- ne->goto_locus = e->goto_locus;
+ if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
+ && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+ need_entry_edge = 1;
+ if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun))
+ have_entry_edge = 1;
}
- if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
- && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
- need_exit_edge = 1;
- if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
- have_exit_edge = 1;
- }
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
- && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
- need_entry_edge = 1;
- if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun))
- have_entry_edge = 1;
- }
- if (need_exit_edge && !have_exit_edge)
- {
- if (dump_file)
- fprintf (dump_file, "Adding fake exit edge to bb %i\n",
- bb->index);
- make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
- }
- if (need_entry_edge && !have_entry_edge)
- {
- if (dump_file)
- fprintf (dump_file, "Adding fake entry edge to bb %i\n",
- bb->index);
- make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FAKE);
- /* Avoid bbs that have both fake entry edge and also some
- exit edge. One of those edges wouldn't be added to the
- spanning tree, but we can't instrument any of them. */
- if (have_exit_edge || need_exit_edge)
+ if (need_exit_edge && !have_exit_edge)
{
- gimple_stmt_iterator gsi;
- gimple *first;
-
- gsi = gsi_start_nondebug_after_labels_bb (bb);
- gcc_checking_assert (!gsi_end_p (gsi));
- first = gsi_stmt (gsi);
- /* Don't split the bbs containing __builtin_setjmp_receiver
- or ABNORMAL_DISPATCHER calls. These are very
- special and don't expect anything to be inserted before
- them. */
- if (is_gimple_call (first)
- && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
- || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
- || (gimple_call_internal_p (first)
- && (gimple_call_internal_fn (first)
- == IFN_ABNORMAL_DISPATCHER))))
- continue;
-
if (dump_file)
- fprintf (dump_file, "Splitting bb %i after labels\n",
+ fprintf (dump_file, "Adding fake exit edge to bb %i\n",
bb->index);
- split_block_after_labels (bb);
+ make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
+ }
+ if (need_entry_edge && !have_entry_edge)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Adding fake entry edge to bb %i\n",
+ bb->index);
+ make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FAKE);
+ /* Avoid bbs that have both fake entry edge and also some
+ exit edge. One of those edges wouldn't be added to the
+ spanning tree, but we can't instrument any of them. */
+ if (have_exit_edge || need_exit_edge)
+ {
+ gimple_stmt_iterator gsi;
+ gimple *first;
+
+ gsi = gsi_start_nondebug_after_labels_bb (bb);
+ gcc_checking_assert (!gsi_end_p (gsi));
+ first = gsi_stmt (gsi);
+ /* Don't split the bbs containing __builtin_setjmp_receiver
+ or ABNORMAL_DISPATCHER calls. These are very
+ special and don't expect anything to be inserted before
+ them. */
+ if (is_gimple_call (first)
+ && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
+ || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
+ || (gimple_call_internal_p (first)
+ && (gimple_call_internal_fn (first)
+ == IFN_ABNORMAL_DISPATCHER))))
+ continue;
+
+ if (dump_file)
+ fprintf (dump_file, "Splitting bb %i after labels\n",
+ bb->index);
+ split_block_after_labels (bb);
+ }
}
}
}
@@ -1143,7 +1165,18 @@ branch_prob (void)
on the spanning tree. We insert as many abnormal and critical edges
as possible to minimize number of edge splits necessary. */
- find_spanning_tree (el);
+ if (!thunk)
+ find_spanning_tree (el);
+ else
+ {
+ edge e;
+ edge_iterator ei;
+ /* Keep only edge from entry block to be instrumented. */
+ FOR_EACH_BB_FN (bb, cfun)
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ EDGE_INFO (e)->ignore = true;
+ }
+
/* Fake edges that are not on the tree will not be instrumented, so
mark them ignored. */
@@ -1183,8 +1216,17 @@ branch_prob (void)
the checksum in only once place, since it depends on the shape
of the control flow which can change during
various transformations. */
- cfg_checksum = coverage_compute_cfg_checksum (cfun);
- lineno_checksum = coverage_compute_lineno_checksum ();
+ if (thunk)
+ {
+ /* At stream in time we do not have CFG, so we can not do checksums. */
+ cfg_checksum = 0;
+ lineno_checksum = 0;
+ }
+ else
+ {
+ cfg_checksum = coverage_compute_cfg_checksum (cfun);
+ lineno_checksum = coverage_compute_lineno_checksum ();
+ }
/* Write the data from which gcov can reconstruct the basic block
graph and function line numbers (the gcno file). */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4c9083a..0f75fff 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2019-01-01 Jan Hubicka <hubicka@ucw.cz>
+
+ * g++.dg/tree-prof/devirt.C: Update testcase.
+
2019-01-01 Jakub Jelinek <jakub@redhat.com>
Update copyright years.
diff --git a/gcc/testsuite/g++.dg/tree-prof/devirt.C b/gcc/testsuite/g++.dg/tree-prof/devirt.C
index 86cba41..7d6797d 100644
--- a/gcc/testsuite/g++.dg/tree-prof/devirt.C
+++ b/gcc/testsuite/g++.dg/tree-prof/devirt.C
@@ -119,5 +119,5 @@ main ()
__builtin_abort ();
}
-/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" 3 "dom3" } } */
-/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" 3 "dom3" } } */
+/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" 1 "dom3" } } */
+/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" 1 "dom3" } } */
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index ab4a439..30fadde 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -739,7 +739,8 @@ tree_profiling (void)
FOR_EACH_DEFINED_FUNCTION (node)
{
- if (!gimple_has_body_p (node->decl))
+ bool thunk = false;
+ if (!gimple_has_body_p (node->decl) && !node->thunk.thunk_p)
continue;
/* Don't profile functions produced for builtin stuff. */
@@ -760,22 +761,43 @@ tree_profiling (void)
if (!include_source_file_for_profile (file))
continue;
+ if (node->thunk.thunk_p)
+ {
+ /* We can not expand variadic thunks to Gimple. */
+ if (stdarg_p (TREE_TYPE (node->decl)))
+ continue;
+ thunk = true;
+ /* When generate profile, expand thunk to gimple so it can be
+ instrumented same way as other functions. */
+ if (profile_arc_flag)
+ node->expand_thunk (false, true);
+ /* Read cgraph profile but keep function as thunk at profile-use
+ time. */
+ else
+ {
+ read_thunk_profile (node);
+ continue;
+ }
+ }
+
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
if (dump_file)
dump_function_header (dump_file, cfun->decl, dump_flags);
/* Local pure-const may imply need to fixup the cfg. */
- if (execute_fixup_cfg () & TODO_cleanup_cfg)
+ if (gimple_has_body_p (node->decl)
+ && (execute_fixup_cfg () & TODO_cleanup_cfg))
cleanup_tree_cfg ();
- branch_prob ();
+ branch_prob (thunk);
if (! flag_branch_probabilities
&& flag_profile_values)
gimple_gen_ic_func_profiler ();
if (flag_branch_probabilities
+ && !thunk
&& flag_profile_values
&& flag_value_profile_transformations)
gimple_value_profile_transformations ();
diff --git a/gcc/value-prof.c b/gcc/value-prof.c
index fbca652..5013956 100644
--- a/gcc/value-prof.c
+++ b/gcc/value-prof.c
@@ -1188,7 +1188,7 @@ init_node_map (bool local)
cgraph_node_map = new hash_map<profile_id_hash, cgraph_node *>;
FOR_EACH_DEFINED_FUNCTION (n)
- if (n->has_gimple_body_p ())
+ if (n->has_gimple_body_p () || n->thunk.thunk_p)
{
cgraph_node **val;
if (local)
diff --git a/gcc/value-prof.h b/gcc/value-prof.h
index 3e0e058..1251fa9 100644
--- a/gcc/value-prof.h
+++ b/gcc/value-prof.h
@@ -112,7 +112,8 @@ extern struct cgraph_node* find_func_by_profile_id (int func_id);
/* In profile.c. */
extern void init_branch_prob (void);
-extern void branch_prob (void);
+extern void branch_prob (bool);
+extern void read_thunk_profile (struct cgraph_node *);
extern void end_branch_prob (void);
#endif /* GCC_VALUE_PROF_H */