Hi Thanks, On 2019/11/14 17:04, Jan Hubicka wrote: >> PR ipa/69678 >> * cgraph.c (symbol_table::create_edge): Init speculative_id. >> (cgraph_edge::make_speculative): Add param for setting speculative_id. >> (cgraph_edge::speculative_call_info): Find reference by >> speculative_id for multiple indirect targets. >> (cgraph_edge::resolve_speculation): Decrease the speculations >> for indirect edge, drop it's speculative if not direct target >> left. >> (cgraph_edge::redirect_call_stmt_to_callee): Likewise. >> (cgraph_node::verify_node): Don't report error if speculative >> edge not include statement. >> (cgraph_edge::has_multiple_indirect_call_p): New function. >> (cgraph_edge::has_indirect_call_p): New function. >> * cgraph.h (struct indirect_target_info): New struct. >> (indirect_call_targets): New vector variable. >> (make_speculative): Add param for setting speculative_id. >> (cgraph_edge::has_multiple_indirect_call_p): New declare. >> (cgraph_edge::has_indirect_call_p): New declare. >> (speculative_id): New variable. >> * cgraphclones.c (cgraph_node::create_clone): Clone speculative_id. >> * cgraphunit.c: Fix comments typo. >> * ipa-comdats.c: Fix comments typo. >> * ipa-inline.c (inline_small_functions): Fix iterator update. >> * ipa-profile.c (ipa_profile_generate_summary): Add indirect >> multiple targets logic. >> (ipa_profile): Likewise. >> * ipa-ref.h (speculative_id): New variable. >> * ipa.c (process_references): Fix typo. >> * lto-cgraph.c (lto_output_edge): Add indirect multiple targets >> logic. Stream out speculative_id. >> (input_edge): Likewise. >> * predict.c (dump_prediction): Revome edges count assert to be >> precise. >> * symtab.c (symtab_node::create_reference): Init speculative_id. >> (symtab_node::clone_references): Clone speculative_id. >> (symtab_node::clone_referring): Clone speculative_id. >> (symtab_node::clone_reference): Clone speculative_id. >> (symtab_node::clear_stmts_in_references): Clear speculative_id. >> * tree-inline.c (copy_bb): Duplicate all the speculative edges >> if indirect call contains multiple speculative targets. >> * tree-profile.c (gimple_gen_ic_profiler): Use the new variable >> __gcov_indirect_call.counters and __gcov_indirect_call.callee. >> (gimple_gen_ic_func_profiler): Likewise. >> (pass_ipa_tree_profile::gate): Fix comment typos. >> * value-prof.h (check_ic_target): Remove. >> * value-prof.c (gimple_value_profile_transformations): >> Use void function gimple_ic_transform. >> * value-prof.c (gimple_ic_transform): Handle topn case. >> Fix comment typos. Change it to a void function. >> >> gcc/testsuite/ChangeLog >> >> 2019-11-14 Xiong Hu Luo <luo...@linux.ibm.com> >> >> PR ipa/69678 >> * gcc.dg/tree-prof/indir-call-prof-topn.c: New testcase. >> * gcc.dg/tree-prof/crossmodule-indir-call-topn-1.c: New testcase. >> * gcc.dg/tree-prof/crossmodule-indir-call-topn-1a.c: New testcase. >> * gcc.dg/tree-prof/crossmodule-indir-call-topn-2.c: New testcase. >> * lib/scandump.exp: Dump executable file name. >> * lib/scanwpaipa.exp: New scan-pgo-wap-ipa-dump. >> @@ -1089,6 +1093,38 @@ cgraph_edge::make_speculative (cgraph_node *n2, >> profile_count direct_count) >> call) and if one of them exists, all of them must exist. >> >> Given speculative call edge, return all three components. >> + >> + For some indirect edge, it may maps to multiple direct edges, i.e. 1:N. >> + check the speculative_id to return all the three components for specified >> + direct edge or indirect edge. >> + If input is indirect, caller of this function will get the direct edge >> one by >> + one, get_edge will just return one of the direct edge mapped to the >> indirect >> + edge, the returned direct edge will be resolved or redirected by the >> caller, >> + then number of indirect calls (speculations) is deceased in each access. >> + If input is direct, this function will get the indirect edge and >> reference >> + with matched speculative_id, the returned edge will also be resolved or >> + redirected, decrease the speculations accordingly. >> + Speculations of indirect edge will be dropped only if all direct edges >> + be handled. >> + >> + e.g. for indirect edge E statement "call call_dest": >> + >> + Redirect N3 after redirected N2: >> + >> + if (call_dest == N2) >> + n2 (); >> + else if (call_dest == N3) >> + n3 (); >> + else >> + call call_dest >> + >> + Resolve N3 and only redirect N2: >> + >> + if (call_dest == N2) >> + n2 (); >> + else >> + call call_dest >> + > > I find this comment hard to read. Reader probably does not know what > speculative edges are and we only want to describe speculative_call_info > function not also the way we resolve calls. So what about something > like this: > > Speculative calls represent a transformation of indirect calls > which may be later inserted into gimple in the following form: > > if (call_dest == target1) > target1 (); > else if (call_dest == target2) > target (); > else > call_dest (); > > This is a win in case target1 and target2 are common values for > call_dest as determined by ipa-devirt or indirect call profiling. > In particular this may enable inlining and other optimizations. > > Speculative call consists of the following main components: > > 1) One or more direct call > 2) One or more IPA_REF_ADDR references (representing the fact that > code above takes address of target1 and target2) > 3) The fallback indirect call > > Direct calls and corresponidng references are linked by > speculative_id. > > speculative_call_info returns tripple > (direct_call, IPA_REF_ADDR reference, indirect call) > when called on one edge participating in the speculative call. > > If called on direct call its corresponding IPA_REF_ADDR is returned. > > If caled on indirect call it will return one of direct edges and its > matching IPA_REF_ADDR. > > All direct calls corresponding to a given speculative call can be > enumerated by indirect_edge->indirect_info->indirect_call_targets Will update.
>> */ >> >> void >> @@ -1128,7 +1164,7 @@ cgraph_edge::speculative_call_info (cgraph_edge >> *&direct, >> >> reference = NULL; >> for (i = 0; e->caller->iterate_reference (i, ref); i++) >> - if (ref->speculative >> + if (ref->speculative && ref->speculative_id == e->speculative_id >> && ((ref->stmt && ref->stmt == e->call_stmt) >> || (!ref->stmt && ref->lto_stmt_uid == e->lto_stmt_uid))) >> { >> @@ -1189,7 +1225,21 @@ cgraph_edge::resolve_speculation (tree callee_decl) > > Rewrite comment here to make clear what resolve_speculation does for > multiple targets. OK and please be patient with my English :) >> in the functions inlined through it. */ >> } >> edge->count += e2->count; >> - edge->speculative = false; >> + /* edge is indirect, e2 is direct. If edge contains multiple >> speculations, >> + remove one of speculations for this indirect edge, then if edge still >> + contains direct target, keep the speculation, next direct target >> + will continue use it. Give up speculation completely if no direct >> + target is left for this indirect edge. */ >> + if (edge->has_indirect_call_p ()) >> + { >> + /* As the direct targets are sorted by decrease, delete the first >> target >> + when it is resolved. */ >> + edge->indirect_info->indirect_call_targets->ordered_remove (0); >> + if (edge->indirect_info->indirect_call_targets->is_empty ()) >> + edge->speculative = false; >> + } >> + else >> + edge->speculative = false; >> e2->speculative = false; >> ref->remove_reference (); >> if (e2->indirect_unknown_callee || e2->inline_failed) >> @@ -1297,7 +1347,21 @@ cgraph_edge::redirect_call_stmt_to_callee (void) >> e->caller->set_call_stmt_including_clones (e->call_stmt, new_stmt, >> false); >> e->count = gimple_bb (e->call_stmt)->count; >> - e2->speculative = false; >> + /* edge is direct, e2 is indirect here. If e2 contains multiple >> + speculations, remove one of speculations for this indirect edge, >> + then if e2 still contains direct target, keep the speculation, >> + next direct target will continue use it. Give up speculation >> + completely if no direct target is left for this indirect e2. */ >> + if (e2->has_indirect_call_p ()) >> + { >> + /* As the direct targets are sorted by decrease, delete the first >> + target when it is redirected. */ >> + e2->indirect_info->indirect_call_targets->ordered_remove (0); >> + if (e2->indirect_info->indirect_call_targets->is_empty ()) >> + e2->speculative = false; >> + } >> + else >> + e2->speculative = false; > > I think this also needs better explanation (and especially in the > comment in the front of function) >> @@ -3696,6 +3760,22 @@ cgraph_edge::possibly_call_in_translation_unit_p >> (void) >> return node->get_availability () >= AVAIL_INTERPOSABLE; >> } >> >> +/* Return true if this edge has multiple indirect call targets. */ >> +bool >> +cgraph_edge::has_multiple_indirect_call_p (void) > Probaby better as > multiple_speculative_call_targets_p > > It seems to me that here you use indirect_call_targets array which does > not make much sense once the indirect edge is turned into speculative > call. This vector should be freed after that and as I write late > it should not be in the callgraph itself but rather in a ipa-profile > summary. > > (I know that common_target_probability and common_target_id is there > right now but it is code predating summaries and it does not belong there > anymore) > > I would simply add "num_speculative_call_targets" into > cgraph_indirect_call_info datastructure. OK. I used num_of_ics(i.e. num_speculative_call_targets) in early version. Will try restore it. >> +{ >> + return (indirect_info && indirect_info->indirect_call_targets >> + && indirect_info->indirect_call_targets->length () > 1); > > Maybe it would make sense to call this speculative_call_targets? > Since they are after all direct calls... >> +} >> + >> +/* Return true if this edge has at least one indirect call target. */ >> +bool >> +cgraph_edge::has_indirect_call_p (void) >> +{ >> + return (indirect_info && indirect_info->indirect_call_targets >> + && !indirect_info->indirect_call_targets->is_empty ()); > > How this is different from speculative flag on an indirect call? >> +} >> + >> /* A stashed copy of "symtab" for use by selftest::symbol_table_test. >> This needs to be a global so that it can be a GC root, and thus >> prevent the stashed copy from being garbage-collected if the GC runs >> diff --git a/gcc/cgraph.h b/gcc/cgraph.h >> index a4f14743f00..1299702788d 100644 >> --- a/gcc/cgraph.h >> +++ b/gcc/cgraph.h >> @@ -1636,6 +1636,21 @@ private: >> void make_speculative (tree otr_type = NULL); >> }; >> >> +/* Structure containing indirect target information from profile. */ >> + >> +struct GTY (()) indirect_target_info > Probably better as speculative_call_target? >> +{ >> + indirect_target_info (unsigned int id, int prob) >> + : common_target_id (id), common_target_probability (prob) >> + { >> + } >> + >> + /* Profile_id of common target obtained from profile. */ >> + unsigned int common_target_id; >> + /* Probability that call will land in function with COMMON_TARGET_ID. */ >> + int common_target_probability; > > I think this would be more like frequent then common, but perhaps > target_id and target_probablity is better. >> +}; >> + >> /* Structure containing additional information about an indirect call. */ >> >> class GTY(()) cgraph_indirect_call_info >> @@ -1654,10 +1669,9 @@ public: >> int param_index; >> /* ECF flags determined from the caller. */ >> int ecf_flags; >> - /* Profile_id of common target obtained from profile. */ >> - int common_target_id; >> - /* Probability that call will land in function with COMMON_TARGET_ID. */ >> - int common_target_probability; >> + >> + /* An indirect call may contain one or multiple call targets. */ >> + vec<indirect_target_info, va_gc> *indirect_call_targets; > > And speculative_call_targets? > Please put these into cgraph_edge_summary template. > > This is a short lived annotation which is private to ipa-profile and > does not need to be in the core datastructures. So you can then also > delcare it within ipa-profile.c as no one lese cares about it. > Also stream in ipa_profile_write_summary rather than lto-cgraph. Sorry that I don't quite understand your meanning here. I didn't grep the word "cgraph_edge_summary" in source code, do you mean add new structure and related functions like "static ipa_sra_call_summaries *call_sums;" in ipa-sra.c and stream in/out in ipa_profile_write_summary/ipa_profile_read_summary? BTW, there is already an ipa_call_summaries in ipa-profile.c:355, feel apologetic as not familiar with many summaries in it, will take time to go through it: ipa_call_summary *s = ipa_call_summaries->get (edge); > >> + /* speculative id is used by multiple indirect targets when the function >> is > ... is used to link direct calls with their corresponding IPA_REF_ADDR > references when representing speculative cals. */ > > Even if there is only one speculation the values must match, right? :) >> + speculated. */ >> + unsigned int speculative_id; > > The bitfields will pack well with the speculative_id if we make it > 16bit rather than 32bit. I do not think we will ever want to support > more than 64K speculative targets. OK. >> diff --git a/gcc/ipa-comdats.c b/gcc/ipa-comdats.c >> index b496497ff66..0672d6d6575 100644 >> --- a/gcc/ipa-comdats.c >> +++ b/gcc/ipa-comdats.c >> @@ -18,7 +18,7 @@ along with GCC; see the file COPYING3. If not see >> <http://www.gnu.org/licenses/>. */ >> >> /* This is very simple pass that looks for static symbols that are used >> - exlusively by symbol within one comdat group. In this case it makes >> + exclusively by symbol within one comdat group. In this case it makes > This can go in separately as obovius. >> sense to bring the symbol itself into the group to avoid dead code >> that would arrise when the comdat group from current unit is replaced >> by a different copy. Consider for example: >> diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c >> index 78ec0ec685f..8fc67ef88a5 100644 >> --- a/gcc/ipa-inline.c >> +++ b/gcc/ipa-inline.c >> @@ -1945,12 +1945,15 @@ inline_small_functions (void) >> } >> if (has_speculative) >> for (edge = node->callees; edge; edge = next) >> - if (edge->speculative && !speculation_useful_p (edge, >> - edge->aux != NULL)) >> - { >> - edge->resolve_speculation (); >> - update = true; >> - } >> + { >> + next = edge->next_callee; >> + if (edge->speculative >> + && !speculation_useful_p (edge, edge->aux != NULL)) >> + { >> + edge->resolve_speculation (); >> + update = true; >> + } >> + } > > This looks like pasto. So next is initialized only in the loop before > and it happens that it never has speculative flag on it?> > If so, this is also independent fix, so please send it as separate > patch. >> @@ -563,7 +573,7 @@ ipa_profile (void) >> histogram.release (); >> histogram_pool.release (); >> >> - /* Produce speculative calls: we saved common traget from porfiling into >> + /* Produce speculative calls: we saved common target from profiling into > > Also just commit this as obvious. Done. >> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c >> index bdc332dcc23..6c8ebffa11d 100644 >> --- a/gcc/tree-inline.c >> +++ b/gcc/tree-inline.c >> @@ -2194,6 +2194,25 @@ copy_bb (copy_body_data *id, basic_block bb, >> >> gcc_assert (!edge->indirect_unknown_callee); >> old_edge->speculative_call_info (direct, indirect, >> ref); >> + while (old_edge->next_callee >> + && old_edge->next_callee->speculative >> + && indirect->has_multiple_indirect_call_p ()) >> + { >> + /* Some speculative calls may contain more than >> + one direct target, loop iterate it to clone all > I gues better as "Iterate through all direct calls associated to the > speculative call and clone all..." >> + related direct edges before cloning the related >> + indirect edge. */ >> + id->dst_node->clone_reference (ref, stmt); >> + >> + edge = old_edge->next_callee; >> + edge = edge->clone (id->dst_node, call_stmt, >> + gimple_uid (stmt), num, den, >> + true); >> + old_edge = old_edge->next_callee; >> + gcc_assert (!edge->indirect_unknown_callee); >> + old_edge->speculative_call_info (direct, indirect, >> + ref); > Why do you call this at the end of loop? And how do you know that al the > edges are associated to the given speculative call? Speculative targets are sorted by decrease order of execution count in tree-profile. speculative_id in each direct target will ensure the identity in speculative_call_info. Here, speculative_call_info is called first before the while loop, if direct target1 exists, it will be cloned to dst_node. Then speculative_call_info is called second time, if direct target2 exsits, also clone it to dst_node, else the while condition is false, the indirect edge is cloned to dst_node in following code out of the while loop. We all know that you are very busy:), it's so nice of you take the time to review patch to improve code quality. Thanks! Xiong Hu BR >> + } >> >> profile_count indir_cnt = indirect->count; >> indirect = indirect->clone (id->dst_node, call_stmt, >> diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c >> index 6a4e62f5bae..b4435b9b2a8 100644 >> --- a/gcc/tree-profile.c >> +++ b/gcc/tree-profile.c >> @@ -73,8 +73,8 @@ static GTY(()) tree ic_tuple_callee_field; >> /* Do initialization work for the edge profiler. */ >> >> /* Add code: >> - __thread gcov* __gcov_indirect_call_counters; // pointer to actual >> counter >> - __thread void* __gcov_indirect_call_callee; // actual callee address >> + __thread gcov* __gcov_indirect_call.counters; // pointer to actual >> counter >> + __thread void* __gcov_indirect_call.callee; // actual callee address >> __thread int __gcov_function_counter; // time profiler function counter >> */ >> static void >> @@ -381,7 +381,7 @@ gimple_gen_ic_profiler (histogram_value value, unsigned >> tag) >> f_1 = foo; >> __gcov_indirect_call.counters = &__gcov4.main[0]; >> PROF_9 = f_1; >> - __gcov_indirect_call_callee = PROF_9; >> + __gcov_indirect_call.callee = PROF_9; >> _4 = f_1 (); >> */ >> >> @@ -444,11 +444,11 @@ gimple_gen_ic_func_profiler (void) >> >> /* Insert code: >> >> - if (__gcov_indirect_call_callee != NULL) >> + if (__gcov_indirect_call.callee != NULL) >> __gcov_indirect_call_profiler_v3 (profile_id, >> ¤t_function_decl); >> >> The function __gcov_indirect_call_profiler_v3 is responsible for >> - resetting __gcov_indirect_call_callee to NULL. */ >> + resetting __gcov_indirect_call.callee to NULL. */ >> >> gimple_stmt_iterator gsi = gsi_start_bb (cond_bb); >> void0 = build_int_cst (ptr_type_node, 0); >> @@ -890,7 +890,7 @@ pass_ipa_tree_profile::gate (function *) >> { >> /* When profile instrumentation, use or test coverage shall be performed. >> But for AutoFDO, this there is no instrumentation, thus this pass is >> - diabled. */ >> + disabled. */ >> return (!in_lto_p && !flag_auto_profile >> && (flag_branch_probabilities || flag_test_coverage >> || profile_arc_flag)); > > Also commit this independently? > > Patch looks really nice overall. It will be easy to teach ipa-devirt to > use multiple targets too. > > I apologize for very late response and thanks for all the pings > (I will try to get more timely) > Honza >> diff --git a/gcc/value-prof.c b/gcc/value-prof.c >> index cc3542f0295..f64f515c1ee 100644 >> --- a/gcc/value-prof.c >> +++ b/gcc/value-prof.c >> @@ -106,7 +106,7 @@ static bool gimple_divmod_fixed_value_transform >> (gimple_stmt_iterator *); >> static bool gimple_mod_pow2_value_transform (gimple_stmt_iterator *); >> static bool gimple_mod_subtract_transform (gimple_stmt_iterator *); >> static bool gimple_stringops_transform (gimple_stmt_iterator *); >> -static bool gimple_ic_transform (gimple_stmt_iterator *); >> +static void gimple_ic_transform (gimple_stmt_iterator *); >> >> /* Allocate histogram value. */ >> >> @@ -616,8 +616,7 @@ gimple_value_profile_transformations (void) >> if (gimple_mod_subtract_transform (&gsi) >> || gimple_divmod_fixed_value_transform (&gsi) >> || gimple_mod_pow2_value_transform (&gsi) >> - || gimple_stringops_transform (&gsi) >> - || gimple_ic_transform (&gsi)) >> + || gimple_stringops_transform (&gsi)) >> { >> stmt = gsi_stmt (gsi); >> changed = true; >> @@ -628,6 +627,9 @@ gimple_value_profile_transformations (void) >> gsi = gsi_for_stmt (stmt); >> } >> } >> + >> + /* The function never thansforms a GIMPLE statement. */ >> + gimple_ic_transform (&gsi); >> } >> } >> >> @@ -1386,13 +1388,12 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node >> *direct_call, >> return dcall_stmt; >> } >> >> -/* >> - For every checked indirect/virtual call determine if most common pid of >> - function/class method has probability more than 50%. If yes modify code of >> - this call to: >> - */ >> +/* There maybe multiple indirect targets in histogram. Check every >> + indirect/virtual call if callee function exists, if not exist, leave it >> to >> + LTO stage for later process. Modify code of this indirect call to an >> if-else >> + structure in ipa-profile finally. */ >> >> -static bool >> +static void >> gimple_ic_transform (gimple_stmt_iterator *gsi) >> { >> gcall *stmt; >> @@ -1402,52 +1403,58 @@ gimple_ic_transform (gimple_stmt_iterator *gsi) >> >> stmt = dyn_cast <gcall *> (gsi_stmt (*gsi)); >> if (!stmt) >> - return false; >> + return; >> >> if (gimple_call_fndecl (stmt) != NULL_TREE) >> - return false; >> + return; >> >> if (gimple_call_internal_p (stmt)) >> - return false; >> + return; >> >> histogram = gimple_histogram_value_of_type (cfun, stmt, >> HIST_TYPE_INDIR_CALL); >> if (!histogram) >> - return false; >> + return; >> >> - if (!get_nth_most_common_value (NULL, "indirect call", histogram, &val, >> - &count, &all)) >> - return false; >> + count = 0; >> + all = histogram->hvalue.counters[0]; >> >> - if (4 * count <= 3 * all) >> - return false; >> + for (unsigned j = 0; j < GCOV_TOPN_VALUES; j++) >> + { >> + if (!get_nth_most_common_value (NULL, "indirect call", histogram, >> &val, >> + &count, &all, j)) >> + return; >> >> - direct_call = find_func_by_profile_id ((int)val); >> + /* Minimum probability. should be higher than 25%. */ >> + if (4 * count <= all) >> + return; >> >> - if (direct_call == NULL) >> - { >> - if (val) >> + direct_call = find_func_by_profile_id ((int) val); >> + >> + if (direct_call == NULL) >> { >> - if (dump_enabled_p ()) >> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt, >> - "Indirect call -> direct call from other " >> - "module %T=> %i (will resolve only with LTO)\n", >> - gimple_call_fn (stmt), (int)val); >> + if (val) >> + { >> + if (dump_enabled_p ()) >> + dump_printf_loc ( >> + MSG_MISSED_OPTIMIZATION, stmt, >> + "Indirect call -> direct call from other " >> + "module %T=> %i (will resolve only with LTO)\n", >> + gimple_call_fn (stmt), (int) val); >> + } >> + return; >> } >> - return false; >> - } >> >> - if (dump_enabled_p ()) >> - { >> - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, stmt, >> - "Indirect call -> direct call " >> - "%T => %T transformation on insn postponed\n", >> - gimple_call_fn (stmt), direct_call->decl); >> - dump_printf_loc (MSG_NOTE, stmt, >> - "hist->count %" PRId64 >> - " hist->all %" PRId64"\n", count, all); >> + if (dump_enabled_p ()) >> + { >> + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, stmt, >> + "Indirect call -> direct call " >> + "%T => %T transformation on insn postponed\n", >> + gimple_call_fn (stmt), direct_call->decl); >> + dump_printf_loc (MSG_NOTE, stmt, >> + "hist->count %" PRId64 " hist->all %" PRId64 "\n", >> + count, all); >> + } >> } >> - >> - return true; >> } >> >> /* Return true if the stringop CALL shall be profiled. SIZE_ARG be >> diff --git a/gcc/value-prof.h b/gcc/value-prof.h >> index 77c06f60096..b3eeb57d37d 100644 >> --- a/gcc/value-prof.h >> +++ b/gcc/value-prof.h >> @@ -89,7 +89,6 @@ void verify_histograms (void); >> void free_histograms (function *); >> void stringop_block_profile (gimple *, unsigned int *, HOST_WIDE_INT *); >> gcall *gimple_ic (gcall *, struct cgraph_node *, profile_probability); >> -bool check_ic_target (gcall *, struct cgraph_node *); >> bool get_nth_most_common_value (gimple *stmt, const char *counter_type, >> histogram_value hist, gcov_type *value, >> gcov_type *count, gcov_type *all, >> -- >> 2.21.0.777.g83232e3864 >> >>