Index: gcc/gcov-tool.c
===================================================================
--- gcc/gcov-tool.c	(revision 207488)
+++ gcc/gcov-tool.c	(working copy)
@@ -43,8 +43,7 @@ see the files COPYING3 and COPYING.RUNTIME respect
 
 extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
 extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
-extern int gcov_profile_scale (struct gcov_info*, float);
-extern int gcov_profile_scale2 (struct gcov_info*, int, int);
+extern int gcov_profile_scale (struct gcov_info*, float, int, int);
 extern struct gcov_info* gcov_read_profile_dir (const char*, int);
 extern void gcov_exit (void);
 extern void set_gcov_list (struct gcov_info *);
@@ -227,45 +226,13 @@ do_merge (int argc, char **argv)
   return ret;
 }
 
-/* Scale the counters in profile DIR by a factor of N/D.
-   Result is written to dir OUT. Return 0 on success.  */
-
-static int
-profile_rewrite2 (const char *dir, const char *out, int n, int d)
-{
-  char *pwd;
-  int ret;
-  struct gcov_info * profile;
-
-
-  profile = gcov_read_profile_dir (dir, 0);
-  if (!profile)
-    return 1;
-
-  /* Output new profile.  */
-  unlink_profile_dir (out);
-  mkdir (out, 0755);
-  pwd = getcwd (NULL, 0);
-  gcc_assert (pwd);
-  ret = chdir (out);
-  gcc_assert (ret == 0);
-
-  gcov_profile_scale2 (profile, n, d);
-
-  set_gcov_list (profile);
-  gcov_exit ();
-
-  ret = chdir (pwd);
-  free (pwd);
-  return 0;
-}
-
 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
    counter value to N_VAL and scale others counters proportionally.
    Otherwise, multiply the all counters by SCALE.  */
 
 static int
-profile_rewrite (const char *d1, const char *out, long long n_val, float scale)
+profile_rewrite (const char *d1, const char *out, long long n_val,
+                 float scale, int n, int d)
 {
   char *pwd;
   int ret;
@@ -287,7 +254,7 @@ static int
   if (n_val)
     gcov_profile_normalize (d1_profile, (gcov_type) n_val);
   else
-    gcov_profile_scale (d1_profile, scale);
+    gcov_profile_scale (d1_profile, scale, n, d);
 
   set_gcov_list (d1_profile);
   gcov_exit ();
@@ -604,9 +571,9 @@ do_rewrite (int argc, char **argv)
   if (argc - optind == 1)
     {
       if (denominator > 0)
-        ret = profile_rewrite2 (argv[optind],  output_dir, numerator, denominator);
+        ret = profile_rewrite (argv[optind],  output_dir, 0, 0.0, numerator, denominator);
       else
-        ret = profile_rewrite (argv[optind],  output_dir, normalize_val, scale);
+        ret = profile_rewrite (argv[optind],  output_dir, normalize_val, scale, 0, 0);
     }
   else
     rewrite_usage ();
Index: libgcc/libgcov-util.c
===================================================================
--- libgcc/libgcov-util.c	(revision 207488)
+++ libgcc/libgcov-util.c	(working copy)
@@ -873,39 +873,38 @@ gcov_profile_merge (struct gcov_info *tgt_profile,
   return 0;
 }
 
-/* This part of code is to scale profile counters.  */
+typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
 
-/* Type of function used to normalize counters.  */
-typedef void (*gcov_scale_fn) (gcov_type *, gcov_unsigned_t, double);
+/* Performing FN upon arc counters.  */
 
-/* Scale arc counters. N_COUNTERS of counter value in COUNTERS array are
-   multiplied by a factor F.  */
-
 static void
-__gcov_scale_add (gcov_type *counters, unsigned n_counters, double f)
+__gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
+                       counter_op_fn fn, void *data1, void *data2)
 {
   for (; n_counters; counters++, n_counters--)
     {
       gcov_type val = *counters;
-      *counters = val * f;
+      *counters = fn(val, data1, data2);
     }
 }
 
-/* Scale ior counters.  */
+/* Performing FN upon ior counters.  */
 
 static void
-__gcov_scale_ior (gcov_type *counters ATTRIBUTE_UNUSED,
-                      unsigned n_counters ATTRIBUTE_UNUSED,
-                      double f ATTRIBUTE_UNUSED)
+__gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
+                       unsigned n_counters ATTRIBUTE_UNUSED,
+                       counter_op_fn fn ATTRIBUTE_UNUSED,
+                       void *data1 ATTRIBUTE_UNUSED,
+                       void *data2 ATTRIBUTE_UNUSED)
 {
   /* Do nothing.  */
 }
 
-/* Scale delta counters. Multiplied the counters in COUNTERS array
-   by a factor of F.  */
+/* Performaing FN upon delta counters.  */
 
 static void
-__gcov_scale_delta (gcov_type *counters, unsigned n_counters, double f)
+__gcov_delta_counter_op (gcov_type *counters, unsigned n_counters,
+                         counter_op_fn fn, void *data1, void *data2)
 {
   unsigned i, n_measures;
 
@@ -913,16 +912,16 @@ static void
   n_measures = n_counters / 4;
   for (i = 0; i < n_measures; i++, counters += 4)
     {
-      counters[2] *= f;
-      counters[3] *= f;
+      counters[2] = fn (counters[2], data1, data2);
+      counters[3] = fn (counters[3], data1, data2);
     }
 }
 
-/* Scale single counters. Multiplied the counters in COUNTERS array
-   by a factor of F.  */
+/* Performing FN upon single counters.  */
 
 static void
-__gcov_scale_single (gcov_type *counters, unsigned n_counters, double f)
+__gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
+                          counter_op_fn fn, void *data1, void *data2)
 {
   unsigned i, n_measures;
 
@@ -930,16 +929,16 @@ static void
   n_measures = n_counters / 3;
   for (i = 0; i < n_measures; i++, counters += 3)
     {
-      counters[1] *= f;
-      counters[2] *= f;
+      counters[1] = fn (counters[1], data1, data2);
+      counters[2] = fn (counters[2], data1, data2);
     }
 }
 
-/* Scale indirect-call profile counters. Multiplied the counters in COUNTERS
-   array by a factor of F.  */
+/* Performing FN upon indirect-call profile counters.  */
 
 static void
-__gcov_scale_icall_topn (gcov_type *counters, unsigned n_counters, double f)
+__gcov_icall_topn_op (gcov_type *counters, unsigned n_counters,
+                      counter_op_fn fn, void *data1, void *data2)
 {
   unsigned i;
 
@@ -950,41 +949,65 @@ static void
       gcov_type *value_array = &counters[i + 1];
 
       for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
-        value_array[1] *= f;
+        value_array[j + 1] = fn (value_array[j + 1], data1, data2);
     }
 }
 
-/* Scale direct-call profile counters. Multiplied the counters in COUNTERS
-   by a factor of F.  */
+/* Performing FN upon direct-call profile counters.  */
 
 static void
-__gcov_scale_dc (gcov_type *counters, unsigned n_counters, double f)
+__gcov_dc_op (gcov_type *counters, unsigned n_counters,
+              counter_op_fn fn, void *data1, void *data2)
 {
   unsigned i;
 
   gcc_assert (!(n_counters % 2));
   for (i = 0; i < n_counters; i += 2)
-    counters[1] *= f;
+    counters[i + 1] = fn (counters[i + 1], data1, data2);
 }
 
-/* Scaling functions for counters.  */
-static gcov_scale_fn ctr_scale_functions[GCOV_COUNTERS] = {
-    __gcov_scale_add,
-    __gcov_scale_add,
-    __gcov_scale_add,
-    __gcov_scale_single,
-    __gcov_scale_delta,
-    __gcov_scale_single,
-    __gcov_scale_add,
-    __gcov_scale_ior,
-    __gcov_scale_icall_topn,
-    __gcov_scale_dc,
+
+/* Scaling the counter value V by multiplying *(float*) DATA1.  */
+
+static gcov_type
+fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
+{
+  float f = *(float *) data1;
+  return (gcov_type) (v * f);
+}
+
+/* Scaling the counter value V by multiplying DATA2/DATA1.  */
+
+static gcov_type
+int_scale (gcov_type v, void *data1, void *data2)
+{
+  int n = *(int *) data1;
+  int d = *(int *) data2;
+  return (gcov_type) ((v / d) * n);
+}
+
+/* Type of function used to process counters.  */
+typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
+                          counter_op_fn, void *, void *); 
+
+/* Function array to process profile counters.  */
+static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = { 
+    __gcov_add_counter_op,
+    __gcov_add_counter_op,
+    __gcov_add_counter_op,
+    __gcov_single_counter_op,
+    __gcov_delta_counter_op,
+    __gcov_single_counter_op,
+    __gcov_add_counter_op,
+    __gcov_ior_counter_op,
+    __gcov_icall_topn_op,
+    __gcov_dc_op,
 };
 
 /* Driver for scaling profile counters.  */
 
 int
-gcov_profile_scale (struct gcov_info *profile, float scale_factor)
+gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
 {
   struct gcov_info *gi_ptr;
   unsigned f_ix;
@@ -1010,7 +1033,12 @@ int
 
             if (!merge)
               continue;
-            (*ctr_scale_functions[t_ix]) (ci_ptr->values, ci_ptr->num, scale_factor);
+            if (d == 0)
+              (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
+                                      fp_scale, &scale_factor, NULL);
+            else
+              (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
+                                      int_scale, &n, &d);
             ci_ptr++;
           }
       }
@@ -1054,149 +1082,5 @@ gcov_profile_normalize (struct gcov_info *profile,
   if (verbose)
     fprintf (stdout, "max_val is %lld\n", (long long) curr_max_val);
 
-  return gcov_profile_scale (profile, scale_factor);
+  return gcov_profile_scale (profile, scale_factor, 0, 0);
 }
-
-/* Type of function used to normalize counters.  */
-typedef void (*gcov_scale2_fn) (gcov_type *, gcov_unsigned_t, int, int);
-
-/* Scale2 arc counters.  */
-
-static void
-__gcov_scale2_add (gcov_type *counters, unsigned n_counters, int n, int d)
-{
-  for (; n_counters; counters++, n_counters--)
-    {
-      gcov_type val = *counters;
-      *counters = (val / d) * n;
-    }
-}
-
-/* Scale2 ior counters.  */
-
-static void
-__gcov_scale2_ior (gcov_type *counters ATTRIBUTE_UNUSED,
-                      unsigned n_counters ATTRIBUTE_UNUSED,
-                      int n ATTRIBUTE_UNUSED,
-                      int d ATTRIBUTE_UNUSED)
-{
-  /* do nothing.  */
-}
-
-/* Scale2 delta counters.  */
-
-static void
-__gcov_scale2_delta (gcov_type *counters, unsigned n_counters, int n, int d)
-{
-  unsigned i, n_measures;
-
-  gcc_assert (!(n_counters % 4));
-  n_measures = n_counters / 4;
-  for (i = 0; i < n_measures; i++, counters += 4)
-    {
-      counters[2] = (counters[2] / d) * n;
-      counters[3] = (counters[3] / d) * n;
-    }
-}
-
-/* Scale2 single counters.  */
-
-static void
-__gcov_scale2_single (gcov_type *counters, unsigned n_counters, int n, int d)
-{
-  unsigned i, n_measures;
-
-  gcc_assert (!(n_counters % 3));
-  n_measures = n_counters / 3;
-  for (i = 0; i < n_measures; i++, counters += 3)
-    {
-      counters[1] = (counters[1] / d) * n;
-      counters[2] = (counters[2] / d) * n;
-    }
-}
-
-/* Scale2 indirect-call profile counters. Multiplied the counters in COUNTERS
-   array by a factor of F.  */
-
-static void
-__gcov_scale2_icall_topn (gcov_type *counters, unsigned n_counters, int n, int d)
-{
-  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] = (value_array[j+1] / d) * n;
-    }
-}
-
-/* Scale2 direct-call profile counters. Multiplied the counters in COUNTERS
-   by a factor of F.  */
-
-static void
-__gcov_scale2_dc (gcov_type *counters, unsigned n_counters, int n, int d)
-{
-  unsigned i;
-
-  gcc_assert (!(n_counters % 2));
-  for (i = 0; i < n_counters; i += 2)
-    counters[i+1] = (counters[i+1] / d) * n;
-}
-
-/* Scale2 functions for counters.  */
-static gcov_scale2_fn ctr_scale2_functions[GCOV_COUNTERS] = {
-    __gcov_scale2_add,
-    __gcov_scale2_add,
-    __gcov_scale2_add,
-    __gcov_scale2_single,
-    __gcov_scale2_delta,
-    __gcov_scale2_single,
-    __gcov_scale2_add,
-    __gcov_scale2_ior,
-    __gcov_scale2_icall_topn,
-    __gcov_scale2_dc,
-};
-
-/* Driver for scale2 profile counters.  */
-
-int
-gcov_profile_scale2 (struct gcov_info *profile, int n, int d)
-{
-  struct gcov_info *gi_ptr;
-  unsigned f_ix;
-
-  if (verbose)
-    fprintf (stdout, "scale_factor is %d/%d\n", n, d);
-
-  gcc_assert (n >= 0 && d > 0);
-
-  /* Scale the counters.  */
-  for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
-    for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
-      {
-        unsigned t_ix;
-        const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
-        const struct gcov_ctr_info *ci_ptr;
-
-        if (!gfi_ptr || gfi_ptr->key != gi_ptr)
-          continue;
-
-        ci_ptr = gfi_ptr->ctrs;
-        for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
-          {
-            gcov_merge_fn merge = gi_ptr->merge[t_ix];
-
-            if (!merge)
-              continue;
-            (*ctr_scale2_functions[t_ix]) (ci_ptr->values, ci_ptr->num, n, d);
-            ci_ptr++;
-          }
-      }
-
-  return 0;
-}
-
