File gcc9-value-prof.patch of Package gcc9
# The patch is backport of following revisions:
# git repo: https://github.com/marxin/gcc/tree/single-value-profile-gcc-9
# r272179
# r272143
# r272116
# r272114
# r272111
# r272108
# r272107
# r272106
# r272030
Index: gcc-9.3.1+git2380/gcc/doc/invoke.texi
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/doc/invoke.texi
+++ gcc-9.3.1+git2380/gcc/doc/invoke.texi
@@ -12155,9 +12155,6 @@ will not try to thread through its block
Maximum number of nested calls to search for control dependencies
during uninitialized variable analysis.
-@item indir-call-topn-profile
-Track top N target addresses in indirect-call profile.
-
@item max-once-peeled-insns
The maximum number of insns of a peeled loop that rolls only once.
Index: gcc-9.3.1+git2380/gcc/gcov-counter.def
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/gcov-counter.def
+++ gcc-9.3.1+git2380/gcc/gcov-counter.def
@@ -49,6 +49,3 @@ DEF_GCOV_COUNTER(GCOV_COUNTER_IOR, "ior"
/* Time profile collecting first run of a function */
DEF_GCOV_COUNTER(GCOV_TIME_PROFILER, "time_profiler", _time_profile)
-
-/* Top N value tracking for indirect calls. */
-DEF_GCOV_COUNTER(GCOV_COUNTER_ICALL_TOPNV, "indirect_call_topn", _icall_topn)
Index: gcc-9.3.1+git2380/gcc/gcov-io.h
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/gcov-io.h
+++ gcc-9.3.1+git2380/gcc/gcov-io.h
@@ -266,11 +266,12 @@ GCOV_COUNTERS
#define GCOV_N_VALUE_COUNTERS \
(GCOV_LAST_VALUE_COUNTER - GCOV_FIRST_VALUE_COUNTER + 1)
-/* The number of hottest callees to be tracked. */
-#define GCOV_ICALL_TOPN_VAL 2
+/* Number of single value histogram values that live
+ on disk representation. */
+#define GCOV_DISK_SINGLE_VALUES 4
-/* The number of counter entries per icall callsite. */
-#define GCOV_ICALL_TOPN_NCOUNTS (1 + GCOV_ICALL_TOPN_VAL * 4)
+/* Total number of single value counters. */
+#define GCOV_SINGLE_VALUE_COUNTERS (2 * GCOV_DISK_SINGLE_VALUES + 1)
/* Convert a counter index to a tag. */
#define GCOV_TAG_FOR_COUNTER(COUNT) \
Index: gcc-9.3.1+git2380/gcc/ipa-icf.c
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/ipa-icf.c
+++ gcc-9.3.1+git2380/gcc/ipa-icf.c
@@ -2768,20 +2768,20 @@ sem_item_optimizer::build_graph (void)
void
sem_item_optimizer::parse_nonsingleton_classes (void)
{
- unsigned int init_called_count = 0;
+ unsigned int counter = 0;
for (unsigned i = 0; i < m_items.length (); i++)
if (m_items[i]->cls->members.length () > 1)
{
m_items[i]->init ();
- init_called_count++;
+ ++counter;
}
if (dump_file)
- fprintf (dump_file, "Init called for %u items (%.2f%%).\n",
- init_called_count,
- m_items.length () ? 100.0f * init_called_count / m_items.length ()
- : 0.0f);
+ {
+ float f = m_items.length () ? 100.0f * counter / m_items.length () : 0.0f;
+ fprintf (dump_file, "Init called for %u items (%.2f%%).\n", counter, f);
+ }
}
/* Equality function for semantic items is used to subdivide existing
@@ -3300,13 +3300,9 @@ sem_item_optimizer::dump_cong_classes (v
if (!dump_file)
return;
- fprintf (dump_file,
- "Congruence classes: %u (unique hash values: %lu), with total: "
- "%u items\n", m_classes_count,
- (unsigned long) m_classes.elements (), m_items.length ());
-
/* Histogram calculation. */
unsigned int max_index = 0;
+ unsigned int single_element_classes = 0;
unsigned int* histogram = XCNEWVEC (unsigned int, m_items.length () + 1);
for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
@@ -3318,21 +3314,25 @@ sem_item_optimizer::dump_cong_classes (v
if (c > max_index)
max_index = c;
+
+ if (c == 1)
+ ++single_element_classes;
}
fprintf (dump_file,
+ "Congruence classes: %lu with total: %u items (in a non-singular "
+ "class: %u)\n", (unsigned long) m_classes.elements (),
+ m_items.length (), m_items.length () - single_element_classes);
+ fprintf (dump_file,
"Class size histogram [num of members]: number of classe number "
"of classess\n");
-
for (unsigned int i = 0; i <= max_index; i++)
if (histogram[i])
- fprintf (dump_file, "[%u]: %u classes\n", i, histogram[i]);
-
- fprintf (dump_file, "\n\n");
+ fprintf (dump_file, "%6u: %6u\n", i, histogram[i]);
if (dump_flags & TDF_DETAILS)
- for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
- it != m_classes.end (); ++it)
+ for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
+ it != m_classes.end (); ++it)
{
fprintf (dump_file, " group: with %u classes:\n",
(*it)->classes.length ());
Index: gcc-9.3.1+git2380/gcc/ipa-profile.c
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/ipa-profile.c
+++ gcc-9.3.1+git2380/gcc/ipa-profile.c
@@ -191,17 +191,17 @@ ipa_profile_generate_summary (void)
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])
+ gcov_type val, count, all;
+ if (get_most_common_single_value (NULL, "indirect call",
+ h, &val, &count, &all))
{
struct cgraph_edge * e = node->get_edge (stmt);
if (e && !e->indirect_unknown_callee)
continue;
- e->indirect_info->common_target_id
- = h->hvalue.counters [0];
+
+ e->indirect_info->common_target_id = val;
e->indirect_info->common_target_probability
- = GCOV_COMPUTE_SCALE (h->hvalue.counters [1], h->hvalue.counters [2]);
+ = GCOV_COMPUTE_SCALE (count, all);
if (e->indirect_info->common_target_probability > REG_BR_PROB_BASE)
{
if (dump_file)
Index: gcc-9.3.1+git2380/gcc/params.def
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/params.def
+++ gcc-9.3.1+git2380/gcc/params.def
@@ -992,14 +992,6 @@ DEFPARAM (PARAM_PROFILE_FUNC_INTERNAL_ID
"Use internal function id in profile lookup.",
0, 0, 1)
-/* When the parameter is 1, track the most frequent N target
- addresses in indirect-call profile. This disables
- indirect_call_profiler_v3 which tracks single target. */
-DEFPARAM (PARAM_INDIR_CALL_TOPN_PROFILE,
- "indir-call-topn-profile",
- "Track top N target addresses in indirect-call profile.",
- 0, 0, 1)
-
/* Avoid SLP vectorization of large basic blocks. */
DEFPARAM (PARAM_SLP_MAX_INSNS_IN_BB,
"slp-max-insns-in-bb",
Index: gcc-9.3.1+git2380/gcc/profile.c
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/profile.c
+++ gcc-9.3.1+git2380/gcc/profile.c
@@ -172,7 +172,6 @@ instrument_values (histogram_values valu
break;
case HIST_TYPE_INDIR_CALL:
- case HIST_TYPE_INDIR_CALL_TOPN:
gimple_gen_ic_profiler (hist, t, 0);
break;
Index: gcc-9.3.1+git2380/gcc/testsuite/gcc.dg/ipa/pr68035.c
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/testsuite/gcc.dg/ipa/pr68035.c
+++ gcc-9.3.1+git2380/gcc/testsuite/gcc.dg/ipa/pr68035.c
@@ -105,4 +105,4 @@ list_49,
};
-/* { dg-final { scan-ipa-dump "unique hash values: 51" "icf" } } */
+/* { dg-final { scan-ipa-dump "Congruence classes: 51" "icf" } } */
Index: gcc-9.3.1+git2380/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c
+++ gcc-9.3.1+git2380/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c
@@ -19,6 +19,6 @@ int main ()
}
/* { dg-final { scan-tree-dump-times "__gcov0\\.main.* = PROF_edge_counter" 1 "optimized"} } */
-/* { dg-final { scan-tree-dump-times "__gcov_indirect_call_profiler_v3" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "__gcov_indirect_call_profiler_v" 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "__gcov_time_profiler_counter = " 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "__gcov_init" 1 "optimized" } } */
Index: gcc-9.3.1+git2380/gcc/tree-profile.c
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/tree-profile.c
+++ gcc-9.3.1+git2380/gcc/tree-profile.c
@@ -101,11 +101,7 @@ init_ic_make_global_vars (void)
ic_tuple_var
= build_decl (UNKNOWN_LOCATION, VAR_DECL,
- get_identifier (
- (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
- "__gcov_indirect_call_topn" :
- "__gcov_indirect_call")),
- tuple_type);
+ get_identifier ("__gcov_indirect_call"), tuple_type);
TREE_PUBLIC (ic_tuple_var) = 1;
DECL_ARTIFICIAL (ic_tuple_var) = 1;
DECL_INITIAL (ic_tuple_var) = NULL;
@@ -169,10 +165,10 @@ gimple_init_gcov_profiler (void)
= build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node,
NULL_TREE);
- fn_name = concat ("__gcov_one_value_profiler", fn_suffix, NULL);
+ fn_name = concat ("__gcov_one_value_profiler_v2", fn_suffix, NULL);
tree_one_value_profiler_fn = build_fn_decl (fn_name,
one_value_profiler_fn_type);
- free (CONST_CAST (char *, fn_name));
+
TREE_NOTHROW (tree_one_value_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_one_value_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL,
@@ -186,9 +182,7 @@ gimple_init_gcov_profiler (void)
gcov_type_node,
ptr_type_node,
NULL_TREE);
- profiler_fn_name = "__gcov_indirect_call_profiler_v3";
- if (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE))
- profiler_fn_name = "__gcov_indirect_call_topn_profiler";
+ profiler_fn_name = "__gcov_indirect_call_profiler_v4";
tree_indirect_call_profiler_fn
= build_fn_decl (profiler_fn_name, ic_profiler_fn_type);
@@ -376,12 +370,6 @@ gimple_gen_ic_profiler (histogram_value
gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
tree ref_ptr = tree_coverage_counter_addr (tag, base);
- if ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) &&
- tag == GCOV_COUNTER_V_INDIR) ||
- (!PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) &&
- tag == GCOV_COUNTER_ICALL_TOPNV))
- return;
-
ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
true, NULL_TREE, true, GSI_SAME_STMT);
Index: gcc-9.3.1+git2380/gcc/value-prof.c
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/value-prof.c
+++ gcc-9.3.1+git2380/gcc/value-prof.c
@@ -228,109 +228,77 @@ dump_histogram_value (FILE *dump_file, h
switch (hist->type)
{
case HIST_TYPE_INTERVAL:
- fprintf (dump_file, "Interval counter range %d -- %d",
- hist->hdata.intvl.int_start,
- (hist->hdata.intvl.int_start
- + hist->hdata.intvl.steps - 1));
if (hist->hvalue.counters)
{
- unsigned int i;
- fprintf (dump_file, " [");
- for (i = 0; i < hist->hdata.intvl.steps; i++)
- fprintf (dump_file, " %d:%" PRId64,
- hist->hdata.intvl.int_start + i,
- (int64_t) hist->hvalue.counters[i]);
- fprintf (dump_file, " ] outside range:%" PRId64,
- (int64_t) hist->hvalue.counters[i]);
+ fprintf (dump_file, "Interval counter range [%d,%d]: [",
+ hist->hdata.intvl.int_start,
+ (hist->hdata.intvl.int_start
+ + hist->hdata.intvl.steps - 1));
+
+ unsigned int i;
+ for (i = 0; i < hist->hdata.intvl.steps; i++)
+ {
+ fprintf (dump_file, "%d:%" PRId64,
+ hist->hdata.intvl.int_start + i,
+ (int64_t) hist->hvalue.counters[i]);
+ if (i != hist->hdata.intvl.steps - 1)
+ fprintf (dump_file, ", ");
+ }
+ fprintf (dump_file, "] outside range: %" PRId64 ".\n",
+ (int64_t) hist->hvalue.counters[i]);
}
- fprintf (dump_file, ".\n");
break;
case HIST_TYPE_POW2:
- fprintf (dump_file, "Pow2 counter ");
if (hist->hvalue.counters)
- {
- fprintf (dump_file, "pow2:%" PRId64
- " nonpow2:%" PRId64,
- (int64_t) hist->hvalue.counters[1],
- (int64_t) hist->hvalue.counters[0]);
- }
- fprintf (dump_file, ".\n");
+ fprintf (dump_file, "Pow2 counter pow2:%" PRId64
+ " nonpow2:%" PRId64 ".\n",
+ (int64_t) hist->hvalue.counters[1],
+ (int64_t) hist->hvalue.counters[0]);
break;
case HIST_TYPE_SINGLE_VALUE:
- fprintf (dump_file, "Single value ");
+ case HIST_TYPE_INDIR_CALL:
if (hist->hvalue.counters)
{
- fprintf (dump_file, "value:%" PRId64
- " match:%" PRId64
- " wrong:%" PRId64,
- (int64_t) hist->hvalue.counters[0],
- (int64_t) hist->hvalue.counters[1],
- (int64_t) hist->hvalue.counters[2]);
+ fprintf (dump_file,
+ (hist->type == HIST_TYPE_SINGLE_VALUE
+ ? "Single value counter " : "Indirect call counter"));
+ if (hist->hvalue.counters)
+ {
+ fprintf (dump_file, "all: %" PRId64 ", values: ",
+ (int64_t) hist->hvalue.counters[0]);
+ for (unsigned i = 0; i < GCOV_DISK_SINGLE_VALUES; i++)
+ {
+ fprintf (dump_file, "[%" PRId64 ":%" PRId64 "]",
+ (int64_t) hist->hvalue.counters[2 * i + 1],
+ (int64_t) hist->hvalue.counters[2 * i + 2]);
+ if (i != GCOV_DISK_SINGLE_VALUES - 1)
+ fprintf (dump_file, ", ");
+ }
+ fprintf (dump_file, ".\n");
+ }
}
- fprintf (dump_file, ".\n");
break;
case HIST_TYPE_AVERAGE:
- fprintf (dump_file, "Average value ");
if (hist->hvalue.counters)
- {
- fprintf (dump_file, "sum:%" PRId64
- " times:%" PRId64,
- (int64_t) hist->hvalue.counters[0],
- (int64_t) hist->hvalue.counters[1]);
- }
- fprintf (dump_file, ".\n");
+ fprintf (dump_file, "Average value sum:%" PRId64
+ " times:%" PRId64 ".\n",
+ (int64_t) hist->hvalue.counters[0],
+ (int64_t) hist->hvalue.counters[1]);
break;
case HIST_TYPE_IOR:
- fprintf (dump_file, "IOR value ");
if (hist->hvalue.counters)
- {
- fprintf (dump_file, "ior:%" PRId64,
- (int64_t) hist->hvalue.counters[0]);
- }
- fprintf (dump_file, ".\n");
+ fprintf (dump_file, "IOR value ior:%" PRId64 ".\n",
+ (int64_t) hist->hvalue.counters[0]);
break;
- case HIST_TYPE_INDIR_CALL:
- fprintf (dump_file, "Indirect call ");
- if (hist->hvalue.counters)
- {
- fprintf (dump_file, "value:%" PRId64
- " match:%" PRId64
- " all:%" PRId64,
- (int64_t) hist->hvalue.counters[0],
- (int64_t) hist->hvalue.counters[1],
- (int64_t) hist->hvalue.counters[2]);
- }
- fprintf (dump_file, ".\n");
- break;
case HIST_TYPE_TIME_PROFILE:
- fprintf (dump_file, "Time profile ");
if (hist->hvalue.counters)
- {
- fprintf (dump_file, "time:%" PRId64,
- (int64_t) hist->hvalue.counters[0]);
- }
- fprintf (dump_file, ".\n");
- break;
- case HIST_TYPE_INDIR_CALL_TOPN:
- fprintf (dump_file, "Indirect call topn ");
- if (hist->hvalue.counters)
- {
- int i;
-
- fprintf (dump_file, "accu:%" PRId64, hist->hvalue.counters[0]);
- for (i = 1; i < (GCOV_ICALL_TOPN_VAL << 2); i += 2)
- {
- fprintf (dump_file, " target:%" PRId64 " value:%" PRId64,
- (int64_t) hist->hvalue.counters[i],
- (int64_t) hist->hvalue.counters[i+1]);
- }
- }
- fprintf (dump_file, ".\n");
+ fprintf (dump_file, "Time profile time:%" PRId64 ".\n",
+ (int64_t) hist->hvalue.counters[0]);
break;
case HIST_TYPE_MAX:
gcc_unreachable ();
@@ -363,7 +331,7 @@ stream_out_histogram_value (struct outpu
/* When user uses an unsigned type with a big value, constant converted
to gcov_type (a signed type) can be negative. */
gcov_type value = hist->hvalue.counters[i];
- if ((hist->type == HIST_TYPE_SINGLE_VALUE && i == 0)
+ if ((hist->type == HIST_TYPE_SINGLE_VALUE && i > 0)
|| hist->type == HIST_TYPE_IOR)
/* Note that the IOR counter tracks pointer values and these can have
sign bit set. */
@@ -411,7 +379,7 @@ stream_in_histogram_value (struct lto_in
case HIST_TYPE_SINGLE_VALUE:
case HIST_TYPE_INDIR_CALL:
- ncounters = 3;
+ ncounters = GCOV_SINGLE_VALUE_COUNTERS;
break;
case HIST_TYPE_IOR:
@@ -419,10 +387,6 @@ stream_in_histogram_value (struct lto_in
ncounters = 1;
break;
- case HIST_TYPE_INDIR_CALL_TOPN:
- ncounters = (GCOV_ICALL_TOPN_VAL << 2) + 1;
- break;
-
case HIST_TYPE_MAX:
gcc_unreachable ();
}
@@ -752,6 +716,48 @@ gimple_divmod_fixed_value (gassign *stmt
return tmp2;
}
+/* Return most common value of SINGLE_VALUE histogram. If
+ there's a unique value, return true and set VALUE and COUNT
+ arguments. */
+
+bool
+get_most_common_single_value (gimple *stmt, const char *counter_type,
+ histogram_value hist,
+ gcov_type *value, gcov_type *count,
+ gcov_type *all)
+{
+ if (hist->hvalue.counters[2] == -1)
+ return false;
+
+ *count = 0;
+ *value = 0;
+
+ gcov_type read_all = hist->hvalue.counters[0];
+
+ for (unsigned i = 0; i < GCOV_DISK_SINGLE_VALUES; i++)
+ {
+ gcov_type v = hist->hvalue.counters[2 * i + 1];
+ gcov_type c = hist->hvalue.counters[2 * i + 2];
+
+ /* Indirect calls can't be vereified. */
+ if (stmt && check_counter (stmt, counter_type, &c, &read_all,
+ gimple_bb (stmt)->count))
+ return false;
+
+ *all = read_all;
+
+ if (c > *count)
+ {
+ *value = v;
+ *count = c;
+ }
+ else if (c == *count && v > *value)
+ *value = v;
+ }
+
+ return true;
+}
+
/* Do transform 1) on INSN if applicable. */
static bool
@@ -781,23 +787,19 @@ gimple_divmod_fixed_value_transform (gim
if (!histogram)
return false;
+ if (!get_most_common_single_value (stmt, "divmod", histogram, &val, &count,
+ &all))
+ return false;
+
value = histogram->hvalue.value;
- val = histogram->hvalue.counters[0];
- count = histogram->hvalue.counters[1];
- all = histogram->hvalue.counters[2];
gimple_remove_histogram_value (cfun, stmt, histogram);
- /* We require that count is at least half of all; this means
- that for the transformation to fire the value must be constant
- at least 50% of time (and 75% gives the guarantee of usage). */
+ /* We require that count is at least half of all. */
if (simple_cst_equal (gimple_assign_rhs2 (stmt), value) != 1
|| 2 * count < all
|| optimize_bb_for_size_p (gimple_bb (stmt)))
return false;
- if (check_counter (stmt, "value", &count, &all, gimple_bb (stmt)->count))
- return false;
-
/* Compute probability of taking the optimal path. */
if (all > 0)
prob = profile_probability::probability_in_gcov_type (count, all);
@@ -1116,7 +1118,6 @@ gimple_mod_subtract_transform (gimple_st
count1 = histogram->hvalue.counters[0];
count2 = histogram->hvalue.counters[1];
- /* Compute probability of taking the optimal path. */
if (check_counter (stmt, "interval", &count1, &all, gimple_bb (stmt)->count))
{
gimple_remove_histogram_value (cfun, stmt, histogram);
@@ -1424,7 +1425,7 @@ gimple_ic_transform (gimple_stmt_iterato
{
gcall *stmt;
histogram_value histogram;
- gcov_type val, count, all, bb_all;
+ gcov_type val, count, all;
struct cgraph_node *direct_call;
stmt = dyn_cast <gcall *> (gsi_stmt (*gsi));
@@ -1441,21 +1442,9 @@ gimple_ic_transform (gimple_stmt_iterato
if (!histogram)
return false;
- val = histogram->hvalue.counters [0];
- count = histogram->hvalue.counters [1];
- all = histogram->hvalue.counters [2];
-
- bb_all = gimple_bb (stmt)->count.ipa ().to_gcov_type ();
- /* The order of CHECK_COUNTER calls is important -
- since check_counter can correct the third parameter
- and we want to make count <= all <= bb_all. */
- if (check_counter (stmt, "ic", &all, &bb_all, gimple_bb (stmt)->count)
- || check_counter (stmt, "ic", &count, &all,
- profile_count::from_gcov_type (all)))
- {
- gimple_remove_histogram_value (cfun, stmt, histogram);
- return false;
- }
+ if (!get_most_common_single_value (NULL, "indirect call", histogram, &val,
+ &count, &all))
+ return false;
if (4 * count <= 3 * all)
return false;
@@ -1667,19 +1656,19 @@ gimple_stringops_transform (gimple_stmt_
if (TREE_CODE (blck_size) == INTEGER_CST)
return false;
- histogram = gimple_histogram_value_of_type (cfun, stmt, HIST_TYPE_SINGLE_VALUE);
+ histogram = gimple_histogram_value_of_type (cfun, stmt,
+ HIST_TYPE_SINGLE_VALUE);
if (!histogram)
return false;
- val = histogram->hvalue.counters[0];
- count = histogram->hvalue.counters[1];
- all = histogram->hvalue.counters[2];
+ if (!get_most_common_single_value (stmt, "stringops", histogram, &val,
+ &count, &all))
+ return false;
+
gimple_remove_histogram_value (cfun, stmt, histogram);
- /* We require that count is at least half of all; this means
- that for the transformation to fire the value must be constant
- at least 80% of time. */
- if ((6 * count / 5) < all || optimize_bb_for_size_p (gimple_bb (stmt)))
+ /* We require that count is at least half of all. */
+ if (2 * count < all || optimize_bb_for_size_p (gimple_bb (stmt)))
return false;
if (check_counter (stmt, "value", &count, &all, gimple_bb (stmt)->count))
return false;
@@ -1868,12 +1857,8 @@ gimple_indirect_call_to_profile (gimple
values->reserve (3);
- values->quick_push (gimple_alloc_histogram_value (
- cfun,
- PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
- HIST_TYPE_INDIR_CALL_TOPN :
- HIST_TYPE_INDIR_CALL,
- stmt, callee));
+ values->quick_push (gimple_alloc_histogram_value (cfun, HIST_TYPE_INDIR_CALL,
+ stmt, callee));
return;
}
@@ -1955,11 +1940,11 @@ gimple_find_values_to_profile (histogram
break;
case HIST_TYPE_SINGLE_VALUE:
- hist->n_counters = 3;
+ hist->n_counters = GCOV_SINGLE_VALUE_COUNTERS;
break;
- case HIST_TYPE_INDIR_CALL:
- hist->n_counters = 3;
+ case HIST_TYPE_INDIR_CALL:
+ hist->n_counters = GCOV_SINGLE_VALUE_COUNTERS;
break;
case HIST_TYPE_TIME_PROFILE:
@@ -1974,10 +1959,6 @@ gimple_find_values_to_profile (histogram
hist->n_counters = 1;
break;
- case HIST_TYPE_INDIR_CALL_TOPN:
- hist->n_counters = GCOV_ICALL_TOPN_NCOUNTS;
- break;
-
default:
gcc_unreachable ();
}
Index: gcc-9.3.1+git2380/gcc/value-prof.h
===================================================================
--- gcc-9.3.1+git2380.orig/gcc/value-prof.h
+++ gcc-9.3.1+git2380/gcc/value-prof.h
@@ -33,8 +33,6 @@ enum hist_type
HIST_TYPE_AVERAGE, /* Compute average value (sum of all values). */
HIST_TYPE_IOR, /* Used to compute expected alignment. */
HIST_TYPE_TIME_PROFILE, /* Used for time profile */
- HIST_TYPE_INDIR_CALL_TOPN, /* Tries to identify the top N most frequently
- called functions in indirect call. */
HIST_TYPE_MAX
};
@@ -92,6 +90,10 @@ 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_most_common_single_value (gimple *stmt, const char *counter_type,
+ histogram_value hist,
+ gcov_type *value, gcov_type *count,
+ gcov_type *all);
/* In tree-profile.c. */
Index: gcc-9.3.1+git2380/libgcc/Makefile.in
===================================================================
--- gcc-9.3.1+git2380.orig/libgcc/Makefile.in
+++ gcc-9.3.1+git2380/libgcc/Makefile.in
@@ -888,20 +888,19 @@ include $(iterator)
# Build libgcov components.
LIBGCOV_MERGE = _gcov_merge_add _gcov_merge_single \
- _gcov_merge_ior _gcov_merge_time_profile _gcov_merge_icall_topn
+ _gcov_merge_ior _gcov_merge_time_profile
LIBGCOV_PROFILER = _gcov_interval_profiler \
_gcov_interval_profiler_atomic \
_gcov_pow2_profiler \
_gcov_pow2_profiler_atomic \
- _gcov_one_value_profiler \
- _gcov_one_value_profiler_atomic \
+ _gcov_one_value_profiler_v2 \
+ _gcov_one_value_profiler_v2_atomic \
_gcov_average_profiler \
_gcov_average_profiler_atomic \
_gcov_ior_profiler \
_gcov_ior_profiler_atomic \
- _gcov_indirect_call_profiler_v3 \
- _gcov_time_profiler \
- _gcov_indirect_call_topn_profiler
+ _gcov_indirect_call_profiler_v4 \
+ _gcov_time_profiler
LIBGCOV_INTERFACE = _gcov_dump _gcov_flush _gcov_fork \
_gcov_execl _gcov_execlp \
_gcov_execle _gcov_execv _gcov_execvp _gcov_execve _gcov_reset
Index: gcc-9.3.1+git2380/libgcc/libgcov-driver.c
===================================================================
--- gcc-9.3.1+git2380.orig/libgcc/libgcov-driver.c
+++ gcc-9.3.1+git2380/libgcc/libgcov-driver.c
@@ -415,84 +415,6 @@ merge_summary (int run_counted, struct g
}
}
-/* Sort N entries in VALUE_ARRAY in descending order.
- Each entry in VALUE_ARRAY has two values. The sorting
- is based on the second value. */
-
-GCOV_LINKAGE void
-gcov_sort_n_vals (gcov_type *value_array, int n)
-{
- int j, k;
-
- for (j = 2; j < n; j += 2)
- {
- gcov_type cur_ent[2];
-
- cur_ent[0] = value_array[j];
- cur_ent[1] = value_array[j + 1];
- k = j - 2;
- while (k >= 0 && value_array[k + 1] < cur_ent[1])
- {
- value_array[k + 2] = value_array[k];
- value_array[k + 3] = value_array[k+1];
- k -= 2;
- }
- value_array[k + 2] = cur_ent[0];
- value_array[k + 3] = cur_ent[1];
- }
-}
-
-/* Sort the profile counters for all indirect call sites. Counters
- for each call site are allocated in array COUNTERS. */
-
-static void
-gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
-{
- int i;
- gcov_type *values;
- int n = counters->num;
-
- gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
- values = counters->values;
-
- for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
- {
- gcov_type *value_array = &values[i + 1];
- gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
- }
-}
-
-/* Sort topn indirect_call profile counters in GI_PTR. */
-
-static void
-gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
-{
- unsigned int i;
- int f_ix;
- const struct gcov_fn_info *gfi_ptr;
- const struct gcov_ctr_info *ci_ptr;
-
- if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV])
- return;
-
- for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
- {
- gfi_ptr = gi_ptr->functions[f_ix];
- ci_ptr = gfi_ptr->ctrs;
- for (i = 0; i < GCOV_COUNTERS; i++)
- {
- if (!gi_ptr->merge[i])
- continue;
- if (i == GCOV_COUNTER_ICALL_TOPNV)
- {
- gcov_sort_icall_topn_counter (ci_ptr);
- break;
- }
- ci_ptr++;
- }
- }
-}
-
/* Dump the coverage counts for one gcov_info object. We merge with existing
counts when possible, to avoid growing the .da files ad infinitum. We use
this program's checksum to make sure we only accumulate whole program
@@ -510,8 +432,6 @@ dump_one_gcov (struct gcov_info *gi_ptr,
fn_buffer = 0;
- gcov_sort_topn_counter_arrays (gi_ptr);
-
error = gcov_exit_open_gcda_file (gi_ptr, gf);
if (error == -1)
return;
Index: gcc-9.3.1+git2380/libgcc/libgcov-merge.c
===================================================================
--- gcc-9.3.1+git2380.orig/libgcc/libgcov-merge.c
+++ gcc-9.3.1+git2380/libgcc/libgcov-merge.c
@@ -35,7 +35,7 @@ void __gcov_merge_add (gcov_type *counte
#ifdef L_gcov_merge_single
void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)),
- unsigned n_counters __attribute__ ((unused))) {}
+ unsigned n_counters __attribute__ ((unused))) {}
#endif
#else
@@ -85,103 +85,73 @@ __gcov_merge_time_profile (gcov_type *co
#endif /* L_gcov_merge_time_profile */
#ifdef L_gcov_merge_single
-/* The profile merging function for choosing the most common value.
- It is given an array COUNTERS of N_COUNTERS old counters and it
- reads the same number of counters from the gcov file. The counters
- are split into 3-tuples where the members of the tuple have
- meanings:
- -- the stored candidate on the most common value of the measured entity
- -- counter
- -- total number of evaluations of the value */
-void
-__gcov_merge_single (gcov_type *counters, unsigned n_counters)
+static void
+merge_single_value_set (gcov_type *counters)
{
- unsigned i, n_measures;
- gcov_type value, counter, all;
+ unsigned j;
+ gcov_type value, counter;
+
+ /* First value is number of total executions of the profiler. */
+ gcov_type all = gcov_get_counter_ignore_scaling (-1);
+ counters[0] += all;
+ ++counters;
- gcc_assert (!(n_counters % 3));
- n_measures = n_counters / 3;
- for (i = 0; i < n_measures; i++, counters += 3)
+ for (unsigned i = 0; i < GCOV_DISK_SINGLE_VALUES; i++)
{
value = gcov_get_counter_target ();
- counter = gcov_get_counter ();
- all = gcov_get_counter ();
+ counter = gcov_get_counter_ignore_scaling (-1);
- if (counters[0] == value)
- counters[1] += counter;
- else if (counter > counters[1])
- {
- counters[0] = value;
- counters[1] = counter - counters[1];
- }
- else
- counters[1] -= counter;
- counters[2] += all;
+ if (counter == -1)
+ {
+ counters[1] = -1;
+ /* We can't return as we need to read all counters. */
+ continue;
+ }
+ else if (counter == 0 || counters[1] == -1)
+ {
+ /* We can't return as we need to read all counters. */
+ continue;
+ }
+
+ for (j = 0; j < GCOV_DISK_SINGLE_VALUES; j++)
+ {
+ if (counters[2 * j] == value)
+ {
+ counters[2 * j + 1] += counter;
+ break;
+ }
+ else if (counters[2 * j + 1] == 0)
+ {
+ counters[2 * j] = value;
+ counters[2 * j + 1] = counter;
+ break;
+ }
+ }
+
+ /* We haven't found a free slot for the value, mark overflow. */
+ if (j == GCOV_DISK_SINGLE_VALUES)
+ counters[1] = -1;
}
}
-#endif /* L_gcov_merge_single */
-#ifdef L_gcov_merge_icall_topn
-/* The profile merging function used for merging indirect call counts
- This function is given array COUNTERS of N_COUNTERS old counters and it
- reads the same number of counters from the gcov file. */
+/* The profile merging function for choosing the most common value.
+ It is given an array COUNTERS of N_COUNTERS old counters and it
+ reads the same number of counters from the gcov file. The counters
+ are split into pairs where the members of the tuple have
+ meanings:
+ -- the stored candidate on the most common value of the measured entity
+ -- counter
+ */
void
-__gcov_merge_icall_topn (gcov_type *counters, unsigned n_counters)
+__gcov_merge_single (gcov_type *counters, unsigned n_counters)
{
- unsigned i, j, k, m;
+ gcc_assert (!(n_counters % GCOV_SINGLE_VALUE_COUNTERS));
- gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
- for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
- {
- gcov_type *value_array = &counters[i + 1];
- unsigned tmp_size = 2 * (GCOV_ICALL_TOPN_NCOUNTS - 1);
- gcov_type *tmp_array
- = (gcov_type *) alloca (tmp_size * sizeof (gcov_type));
-
- for (j = 0; j < tmp_size; j++)
- tmp_array[j] = 0;
-
- for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
- {
- tmp_array[j] = value_array[j];
- tmp_array[j + 1] = value_array [j + 1];
- }
-
- /* Skip the number_of_eviction entry. */
- gcov_get_counter ();
- for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
- {
- int found = 0;
- gcov_type global_id = gcov_get_counter_target ();
- gcov_type call_count = gcov_get_counter ();
- for (m = 0; m < j; m += 2)
- {
- if (tmp_array[m] == global_id)
- {
- found = 1;
- tmp_array[m + 1] += call_count;
- break;
- }
- }
- if (!found)
- {
- tmp_array[j] = global_id;
- tmp_array[j + 1] = call_count;
- j += 2;
- }
- }
- /* Now sort the temp array */
- gcov_sort_n_vals (tmp_array, j);
-
- /* Now copy back the top half of the temp array */
- for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
- {
- value_array[k] = tmp_array[k];
- value_array[k + 1] = tmp_array[k + 1];
- }
- }
+ for (unsigned i = 0; i < (n_counters / GCOV_SINGLE_VALUE_COUNTERS); i++)
+ merge_single_value_set (counters + (i * GCOV_SINGLE_VALUE_COUNTERS));
}
-#endif /* L_gcov_merge_icall_topn */
+#endif /* L_gcov_merge_single */
+
#endif /* inhibit_libc */
Index: gcc-9.3.1+git2380/libgcc/libgcov-profiler.c
===================================================================
--- gcc-9.3.1+git2380.orig/libgcc/libgcov-profiler.c
+++ gcc-9.3.1+git2380/libgcc/libgcov-profiler.c
@@ -112,40 +112,37 @@ __gcov_pow2_profiler_atomic (gcov_type *
COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
function is called more than 50% of the time with one value, this value
- will be in COUNTERS[0] in the end.
-
- In any case, COUNTERS[2] is incremented. If USE_ATOMIC is set to 1,
- COUNTERS[2] is updated with an atomic instruction. */
+ will be in COUNTERS[0] in the end. */
static inline void
__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value,
int use_atomic)
{
- if (value == counters[0])
- counters[1]++;
- else if (counters[1] == 0)
+ if (value == counters[1])
+ counters[2]++;
+ else if (counters[2] == 0)
{
- counters[1] = 1;
- counters[0] = value;
+ counters[2] = 1;
+ counters[1] = value;
}
else
- counters[1]--;
+ counters[2]--;
if (use_atomic)
- __atomic_fetch_add (&counters[2], 1, __ATOMIC_RELAXED);
+ __atomic_fetch_add (&counters[0], 1, __ATOMIC_RELAXED);
else
- counters[2]++;
+ counters[0]++;
}
-#ifdef L_gcov_one_value_profiler
+#ifdef L_gcov_one_value_profiler_v2
void
-__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
+__gcov_one_value_profiler_v2 (gcov_type *counters, gcov_type value)
{
__gcov_one_value_profiler_body (counters, value, 0);
}
#endif
-#if defined(L_gcov_one_value_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
+#if defined(L_gcov_one_value_profiler_v2_atomic) && GCOV_SUPPORTS_ATOMIC
/* Update one value profilers (COUNTERS) for a given VALUE.
@@ -157,146 +154,13 @@ __gcov_one_value_profiler (gcov_type *co
https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */
void
-__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value)
+__gcov_one_value_profiler_v2_atomic (gcov_type *counters, gcov_type value)
{
__gcov_one_value_profiler_body (counters, value, 1);
}
#endif
-#ifdef L_gcov_indirect_call_topn_profiler
-/* Tries to keep track the most frequent N values in the counters where
- N is specified by parameter TOPN_VAL. To track top N values, 2*N counter
- entries are used.
- counter[0] --- the accumative count of the number of times one entry in
- in the counters gets evicted/replaced due to limited capacity.
- When this value reaches a threshold, the bottom N values are
- cleared.
- counter[1] through counter[2*N] records the top 2*N values collected so far.
- Each value is represented by two entries: count[2*i+1] is the ith value, and
- count[2*i+2] is the number of times the value is seen. */
-
-static void
-__gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value)
-{
- unsigned i, found = 0, have_zero_count = 0;
- gcov_type *entry;
- gcov_type *lfu_entry = &counters[1];
- gcov_type *value_array = &counters[1];
- gcov_type *num_eviction = &counters[0];
- gcov_unsigned_t topn_val = GCOV_ICALL_TOPN_VAL;
-
- /* There are 2*topn_val values tracked, each value takes two slots in the
- counter array. */
- for (i = 0; i < (topn_val << 2); i += 2)
- {
- entry = &value_array[i];
- if (entry[0] == value)
- {
- entry[1]++ ;
- found = 1;
- break;
- }
- else if (entry[1] == 0)
- {
- lfu_entry = entry;
- have_zero_count = 1;
- }
- else if (entry[1] < lfu_entry[1])
- lfu_entry = entry;
- }
-
- if (found)
- return;
-
- /* lfu_entry is either an empty entry or an entry
- with lowest count, which will be evicted. */
- lfu_entry[0] = value;
- lfu_entry[1] = 1;
-
-#define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000
-
- /* Too many evictions -- time to clear bottom entries to
- avoid hot values bumping each other out. */
- if (!have_zero_count
- && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD)
- {
- unsigned i, j;
- gcov_type *p, minv;
- gcov_type* tmp_cnts
- = (gcov_type *)alloca (topn_val * sizeof (gcov_type));
-
- *num_eviction = 0;
-
- for (i = 0; i < topn_val; i++)
- tmp_cnts[i] = 0;
-
- /* Find the largest topn_val values from the group of
- 2*topn_val values and put them into tmp_cnts. */
-
- for (i = 0; i < 2 * topn_val; i += 2)
- {
- p = 0;
- for (j = 0; j < topn_val; j++)
- {
- if (!p || tmp_cnts[j] < *p)
- p = &tmp_cnts[j];
- }
- if (value_array[i + 1] > *p)
- *p = value_array[i + 1];
- }
-
- minv = tmp_cnts[0];
- for (j = 1; j < topn_val; j++)
- {
- if (tmp_cnts[j] < minv)
- minv = tmp_cnts[j];
- }
- /* Zero out low value entries. */
- for (i = 0; i < 2 * topn_val; i += 2)
- {
- if (value_array[i + 1] < minv)
- {
- value_array[i] = 0;
- value_array[i + 1] = 0;
- }
- }
- }
-}
-
-/* These two variables are used to actually track caller and callee. Keep
- them in TLS memory so races are not common (they are written to often).
- The variables are set directly by GCC instrumented code, so declaration
- here must match one in tree-profile.c. */
-
-#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
-__thread
-#endif
-struct indirect_call_tuple __gcov_indirect_call_topn;
-
-#ifdef TARGET_VTABLE_USES_DESCRIPTORS
-#define VTABLE_USES_DESCRIPTORS 1
-#else
-#define VTABLE_USES_DESCRIPTORS 0
-#endif
-
-/* This fucntion is instrumented at function entry to track topn indirect
- calls to CUR_FUNC. */
-
-void
-__gcov_indirect_call_topn_profiler (gcov_type value, void* cur_func)
-{
- void *callee_func = __gcov_indirect_call_topn.callee;
- /* If the C++ virtual tables contain function descriptors then one
- function may have multiple descriptors and we need to dereference
- the descriptors to see if they point to the same function. */
- if (cur_func == callee_func
- || (VTABLE_USES_DESCRIPTORS && callee_func
- && *(void **) cur_func == *(void **) callee_func))
- __gcov_topn_value_profiler_body (__gcov_indirect_call_topn.counters, value);
-}
-#endif
-
-#ifdef L_gcov_indirect_call_profiler_v3
+#ifdef L_gcov_indirect_call_profiler_v4
/* These two variables are used to actually track caller and callee. Keep
them in TLS memory so races are not common (they are written to often).
@@ -318,7 +182,7 @@ struct indirect_call_tuple __gcov_indire
/* Tries to determine the most common value among its inputs. */
void
-__gcov_indirect_call_profiler_v3 (gcov_type value, void* cur_func)
+__gcov_indirect_call_profiler_v4 (gcov_type value, void* cur_func)
{
/* If the C++ virtual tables contain function descriptors then one
function may have multiple descriptors and we need to dereference
Index: gcc-9.3.1+git2380/libgcc/libgcov-util.c
===================================================================
--- gcc-9.3.1+git2380.orig/libgcc/libgcov-util.c
+++ gcc-9.3.1+git2380/libgcc/libgcov-util.c
@@ -739,25 +739,6 @@ __gcov_single_counter_op (gcov_type *cou
}
}
-/* Performing FN upon indirect-call profile counters. */
-
-static void
-__gcov_icall_topn_counter_op (gcov_type *counters, unsigned n_counters,
- counter_op_fn fn, void *data1, void *data2)
-{
- unsigned i;
-
- gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
- for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
- {
- unsigned j;
- gcov_type *value_array = &counters[i + 1];
-
- for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
- value_array[j + 1] = fn (value_array[j + 1], data1, data2);
- }
-}
-
/* Scaling the counter value V by multiplying *(float*) DATA1. */
static gcov_type
Index: gcc-9.3.1+git2380/libgcc/libgcov.h
===================================================================
--- gcc-9.3.1+git2380.orig/libgcc/libgcov.h
+++ gcc-9.3.1+git2380/libgcc/libgcov.h
@@ -102,7 +102,6 @@ typedef unsigned gcov_type_unsigned __at
#define gcov_read_unsigned __gcov_read_unsigned
#define gcov_read_counter __gcov_read_counter
#define gcov_read_summary __gcov_read_summary
-#define gcov_sort_n_vals __gcov_sort_n_vals
#else /* IN_GCOV_TOOL */
/* About the host. */
@@ -130,7 +129,6 @@ typedef unsigned gcov_position_t;
#define L_gcov_merge_single 1
#define L_gcov_merge_ior 1
#define L_gcov_merge_time_profile 1
-#define L_gcov_merge_icall_topn 1
extern gcov_type gcov_read_counter_mem ();
extern unsigned gcov_get_merge_weight ();
@@ -267,26 +265,21 @@ extern void __gcov_merge_single (gcov_ty
/* The merge function that just ors the counters together. */
extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-/* The merge function is used for topn indirect call counters. */
-extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-
/* The profiler functions. */
extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned);
extern void __gcov_interval_profiler_atomic (gcov_type *, gcov_type, int,
unsigned);
extern void __gcov_pow2_profiler (gcov_type *, gcov_type);
extern void __gcov_pow2_profiler_atomic (gcov_type *, gcov_type);
-extern void __gcov_one_value_profiler (gcov_type *, gcov_type);
-extern void __gcov_one_value_profiler_atomic (gcov_type *, gcov_type);
-extern void __gcov_indirect_call_profiler_v3 (gcov_type, void *);
+extern void __gcov_one_value_profiler_v2 (gcov_type *, gcov_type);
+extern void __gcov_one_value_profiler_v2_atomic (gcov_type *, gcov_type);
+extern void __gcov_indirect_call_profiler_v4 (gcov_type, void *);
extern void __gcov_time_profiler (gcov_type *);
extern void __gcov_time_profiler_atomic (gcov_type *);
extern void __gcov_average_profiler (gcov_type *, gcov_type);
extern void __gcov_average_profiler_atomic (gcov_type *, gcov_type);
extern void __gcov_ior_profiler (gcov_type *, gcov_type);
extern void __gcov_ior_profiler_atomic (gcov_type *, gcov_type);
-extern void __gcov_indirect_call_topn_profiler (gcov_type, void *);
-extern void gcov_sort_n_vals (gcov_type *, int);
#ifndef inhibit_libc
/* The wrappers around some library functions.. */
@@ -331,6 +324,29 @@ gcov_get_counter (void)
#endif
}
+/* Similar function as gcov_get_counter(), but do not scale
+ when read value is equal to IGNORE_SCALING. */
+
+static inline gcov_type
+gcov_get_counter_ignore_scaling (gcov_type ignore_scaling ATTRIBUTE_UNUSED)
+{
+#ifndef IN_GCOV_TOOL
+ /* This version is for reading count values in libgcov runtime:
+ we read from gcda files. */
+
+ return gcov_read_counter ();
+#else
+ /* This version is for gcov-tool. We read the value from memory and
+ multiply it by the merge weight. */
+
+ gcov_type v = gcov_read_counter_mem ();
+ if (v != ignore_scaling)
+ v *= gcov_get_merge_weight ();
+
+ return v;
+#endif
+}
+
/* Similar function as gcov_get_counter(), but handles target address
counters. */