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

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 29585cf15aa..af940fa66d4 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12128,9 +12128,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.
 
diff --git a/gcc/gcov-counter.def b/gcc/gcov-counter.def
index 3a0e620987a..b0596c8dc6b 100644
--- a/gcc/gcov-counter.def
+++ b/gcc/gcov-counter.def
@@ -49,6 +49,3 @@ DEF_GCOV_COUNTER(GCOV_COUNTER_IOR, "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)
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index 9edb2923982..0f2905c17ec 100644
--- a/gcc/gcov-io.h
+++ b/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)				\
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index e4c9dda0df1..91425022036 100644
--- a/gcc/ipa-icf.c
+++ b/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 (void)
   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 (void)
 
 	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 ());
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index de9563d808c..c80ea7a9b95 100644
--- a/gcc/ipa-profile.c
+++ b/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)
diff --git a/gcc/params.def b/gcc/params.def
index 3c9c5fc0f13..f38798a60c4 100644
--- a/gcc/params.def
+++ b/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",
diff --git a/gcc/profile.c b/gcc/profile.c
index a1dba1ac8fb..9aff9ef2b21 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -172,7 +172,6 @@ instrument_values (histogram_values values)
 	  break;
 
  	case HIST_TYPE_INDIR_CALL:
- 	case HIST_TYPE_INDIR_CALL_TOPN:
  	  gimple_gen_ic_profiler (hist, t, 0);
   	  break;
 
diff --git a/gcc/testsuite/gcc.dg/ipa/pr68035.c b/gcc/testsuite/gcc.dg/ipa/pr68035.c
index a8cb77971f6..f6adad9f24d 100644
--- a/gcc/testsuite/gcc.dg/ipa/pr68035.c
+++ b/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"  } } */
diff --git a/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c b/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c
index 41d745532fa..0c7e0961824 100644
--- a/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c
+++ b/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" } } */
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index 9b6f351a3d6..5ca4c3e80b6 100644
--- a/gcc/tree-profile.c
+++ b/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 value, unsigned tag, unsigned base)
   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);
 
diff --git a/gcc/value-prof.c b/gcc/value-prof.c
index 5013956cf86..6fda339a3c2 100644
--- a/gcc/value-prof.c
+++ b/gcc/value-prof.c
@@ -228,109 +228,77 @@ dump_histogram_value (FILE *dump_file, histogram_value hist)
   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 output_block *ob, histogram_value hist)
       /* 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)
 	;
       else
 	gcc_assert (value >= 0);
@@ -408,7 +376,7 @@ stream_in_histogram_value (struct lto_input_block *ib, gimple *stmt)
 
 	case HIST_TYPE_SINGLE_VALUE:
 	case HIST_TYPE_INDIR_CALL:
-	  ncounters = 3;
+	  ncounters = GCOV_SINGLE_VALUE_COUNTERS;
 	  break;
 
 	case HIST_TYPE_IOR:
@@ -416,10 +384,6 @@ stream_in_histogram_value (struct lto_input_block *ib, gimple *stmt)
 	  ncounters = 1;
 	  break;
 
-        case HIST_TYPE_INDIR_CALL_TOPN:
-          ncounters = (GCOV_ICALL_TOPN_VAL << 2) + 1;
-          break;
-
 	case HIST_TYPE_MAX:
 	  gcc_unreachable ();
 	}
@@ -749,6 +713,48 @@ gimple_divmod_fixed_value (gassign *stmt, tree value, profile_probability prob,
   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
@@ -778,23 +784,19 @@ gimple_divmod_fixed_value_transform (gimple_stmt_iterator *si)
   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);
@@ -1113,7 +1115,6 @@ gimple_mod_subtract_transform (gimple_stmt_iterator *si)
   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);
@@ -1421,7 +1422,7 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
 {
   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));
@@ -1438,21 +1439,9 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
   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;
@@ -1664,19 +1653,19 @@ gimple_stringops_transform (gimple_stmt_iterator *gsi)
   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;
@@ -1865,12 +1854,8 @@ gimple_indirect_call_to_profile (gimple *stmt, histogram_values *values)
 
   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;
 }
@@ -1952,11 +1937,11 @@ gimple_find_values_to_profile (histogram_values *values)
 	  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:
@@ -1971,10 +1956,6 @@ gimple_find_values_to_profile (histogram_values *values)
 	  hist->n_counters = 1;
 	  break;
 
-        case HIST_TYPE_INDIR_CALL_TOPN:
-          hist->n_counters = GCOV_ICALL_TOPN_NCOUNTS;
-          break;
-
 	default:
 	  gcc_unreachable ();
 	}
diff --git a/gcc/value-prof.h b/gcc/value-prof.h
index 1251fa95e31..25b03f7591a 100644
--- a/gcc/value-prof.h
+++ b/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.  */
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index ea390a5bbea..33b83809cfc 100644
--- a/libgcc/Makefile.in
+++ b/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
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 5dc51df914f..f03868e34bb 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -415,84 +415,6 @@ merge_summary (int run_counted, struct gcov_summary *summary,
     }
 }
 
-/* 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, struct gcov_filename *gf,
 
   fn_buffer = 0;
 
-  gcov_sort_topn_counter_arrays (gi_ptr);
-
   error = gcov_exit_open_gcda_file (gi_ptr, gf);
   if (error == -1)
     return;
diff --git a/libgcc/libgcov-merge.c b/libgcc/libgcov-merge.c
index 046ed5718bb..f778cc4b6b7 100644
--- a/libgcc/libgcov-merge.c
+++ b/libgcc/libgcov-merge.c
@@ -35,7 +35,7 @@ void __gcov_merge_add (gcov_type *counters  __attribute__ ((unused)),
 
 #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 *counters, unsigned n_counters)
 #endif /* L_gcov_merge_time_profile */
 
 #ifdef L_gcov_merge_single
+
+static void
+merge_single_value_set (gcov_type *counters)
+{
+  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;
+
+  for (unsigned i = 0; i < GCOV_DISK_SINGLE_VALUES; i++)
+    {
+      value = gcov_get_counter_target ();
+      counter = gcov_get_counter_ignore_scaling (-1);
+
+      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;
+    }
+}
+
 /* 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
+   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
-   -- total number of evaluations of the value  */
+   */
 void
 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
 {
-  unsigned i, n_measures;
-  gcov_type value, counter, all;
+  gcc_assert (!(n_counters % GCOV_SINGLE_VALUE_COUNTERS));
 
-  gcc_assert (!(n_counters % 3));
-  n_measures = n_counters / 3;
-  for (i = 0; i < n_measures; i++, counters += 3)
-    {
-      value = gcov_get_counter_target ();
-      counter = gcov_get_counter ();
-      all = gcov_get_counter ();
-
-      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;
-    }
+  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_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.  */
-
-void
-__gcov_merge_icall_topn (gcov_type *counters, unsigned n_counters)
-{
-  unsigned i, j, k, m;
-
-  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];
-        }
-    }
-}
-#endif /* L_gcov_merge_icall_topn */
 #endif /* inhibit_libc */
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c
index 7116330252b..9ba65b90df3 100644
--- a/libgcc/libgcov-profiler.c
+++ b/libgcc/libgcov-profiler.c
@@ -112,40 +112,37 @@ __gcov_pow2_profiler_atomic (gcov_type *counters, gcov_type value)
    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 *counters, gcov_type value)
    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_indirect_call;
 
 /* 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
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index ae0dd017204..45d46f2219e 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -740,25 +740,6 @@ __gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
     }
 }
 
-/* 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
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index 993db8fb057..7f316146d49 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -102,7 +102,6 @@ typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
 #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_type *, unsigned) ATTRIBUTE_HIDDEN;
 /* 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.  */