On 1/2/19 12:50 PM, Jan Hubicka wrote: >> >> Honza, in order to make the test working I would need to backport >> r267495. Is it a good idea? > > Yes, my apologies for the mistake! I should stop looking for failures > via grep and use test_summary consistently since I tend to miss > unresolved tests. Old habits are hard to change. > > Honza >> >> Thanks, >> Martin
Hi. So there's a backport of 3 patches that fix the test-case. Tested and bootstrapped on x86_64-linux-gnu, I'm going to install the patches. Martin
>From 5fd0285a53b7caee98625472adc44cb101bd4873 Mon Sep 17 00:00:00 2001 From: jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Wed, 2 Jan 2019 09:25:59 +0000 Subject: [PATCH 3/3] Backport r267507 gcc/testsuite/ChangeLog: 2019-01-02 Jakub Jelinek <ja...@redhat.com> PR ipa/88561 * g++.dg/tree-prof/devirt.C: Expect _ZThn16 only for lp64 and llp64 targets and expect _ZThn8 for ilp32 targets. --- gcc/testsuite/g++.dg/tree-prof/devirt.C | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gcc/testsuite/g++.dg/tree-prof/devirt.C b/gcc/testsuite/g++.dg/tree-prof/devirt.C index 7d6797dd226..3de5dbcf688 100644 --- a/gcc/testsuite/g++.dg/tree-prof/devirt.C +++ b/gcc/testsuite/g++.dg/tree-prof/devirt.C @@ -1,4 +1,6 @@ +/* PR ipa/88561 */ /* { dg-options "-O3 -fdump-tree-dom3-details" } */ + struct nsISupports { virtual int QueryInterface (const int &aIID, void **aInstancePtr) = 0; @@ -119,5 +121,6 @@ main () __builtin_abort (); } -/* { 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::_ZThn16" 1 "dom3" { target { lp64 || llp64 } } } } */ +/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn8" 1 "dom3" { target ilp32 } } } */ /* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" 1 "dom3" } } */ -- 2.20.1
>From f3a455cffaee5ac5af2ac188e08c51f3a662491a Mon Sep 17 00:00:00 2001 From: marxin <mli...@suse.cz> Date: Wed, 2 Jan 2019 12:54:23 +0100 Subject: [PATCH 2/3] Backport r267495 gcc/ChangeLog: 2019-01-01 Jan Hubicka <hubi...@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. gcc/testsuite/ChangeLog: 2019-01-01 Jan Hubicka <hubi...@ucw.cz> * g++.dg/tree-prof/devirt.C: Update testcase. --- gcc/coverage.c | 2 +- gcc/profile.c | 250 ++++++++++++++---------- gcc/testsuite/g++.dg/tree-prof/devirt.C | 4 +- gcc/tree-profile.c | 28 ++- gcc/value-prof.c | 2 +- gcc/value-prof.h | 3 +- 6 files changed, 177 insertions(+), 112 deletions(-) diff --git a/gcc/coverage.c b/gcc/coverage.c index 75628b1748f..592d3dcef84 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -368,7 +368,7 @@ get_coverage_counts (unsigned counter, unsigned expected, 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 6fde0fd29d1..eb9f7d52668 100644 --- a/gcc/profile.c +++ b/gcc/profile.c @@ -977,6 +977,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, 1, 0, 0, NULL); + 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 @@ -997,7 +1016,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; @@ -1012,118 +1031,121 @@ branch_prob (void) flow_call_edges_add (NULL); add_noreturn_fake_exit_edges (); - /* 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) + { + 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) { - 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 entry edge to bb %i\n", bb->index); - split_block_after_labels (bb); + 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); + } } } } @@ -1155,7 +1177,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. */ @@ -1195,8 +1228,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/g++.dg/tree-prof/devirt.C b/gcc/testsuite/g++.dg/tree-prof/devirt.C index 86cba41452e..7d6797dd226 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 f96bd4b9704..8f8bb4874cd 100644 --- a/gcc/tree-profile.c +++ b/gcc/tree-profile.c @@ -653,7 +653,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. */ @@ -670,22 +671,43 @@ tree_profiling (void) && flag_test_coverage) 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 16cdbd64f46..d845faf5568 100644 --- a/gcc/value-prof.c +++ b/gcc/value-prof.c @@ -1202,7 +1202,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 d0b8cda181f..55b1dd18416 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 */ -- 2.20.1
>From eb618a86fa1f59ee7046c325a4a6acfc696cd990 Mon Sep 17 00:00:00 2001 From: marxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Mon, 31 Dec 2018 14:11:09 +0000 Subject: [PATCH 1/3] Backport r267486 gcc/testsuite/ChangeLog: 2018-12-31 Martin Liska <mli...@suse.cz> * g++.dg/tree-prof/devirt.C: Fix scan pattern and test options. --- gcc/testsuite/g++.dg/tree-prof/devirt.C | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gcc/testsuite/g++.dg/tree-prof/devirt.C b/gcc/testsuite/g++.dg/tree-prof/devirt.C index 05c9a26e7a4..86cba41452e 100644 --- a/gcc/testsuite/g++.dg/tree-prof/devirt.C +++ b/gcc/testsuite/g++.dg/tree-prof/devirt.C @@ -1,4 +1,4 @@ -/* { dg-options "-O3 -fdump-tree-dom3" } */ +/* { dg-options "-O3 -fdump-tree-dom3-details" } */ struct nsISupports { virtual int QueryInterface (const int &aIID, void **aInstancePtr) = 0; @@ -119,5 +119,5 @@ main () __builtin_abort (); } -/* { dg-final-use-not-autofdo { scan-ipa-dump-times 3 "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" "dom3" } } */ -/* { dg-final-use-not-autofdo { scan-ipa-dump-times 3 "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" "dom3" } } */ +/* { 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" } } */ -- 2.20.1