[Ada] Postcondition checks performed before finalization
[gcc.git] / gcc / profile.c
index c469df56dba70c754d4f2be80e2ee8ccbbd0400b..454095916294194052b98499ae6143e256613417 100644 (file)
@@ -1,5 +1,5 @@
 /* Calculate branch probabilities, and basic block execution counts.
-   Copyright (C) 1990-2013 Free Software Foundation, Inc.
+   Copyright (C) 1990-2020 Free Software Foundation, Inc.
    Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
    based on some ideas from Dain Samples of UC Berkeley.
    Further mangling by Bob Manson, Cygnus Support.
@@ -50,24 +50,28 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
 #include "rtl.h"
-#include "flags.h"
-#include "regs.h"
-#include "expr.h"
-#include "function.h"
-#include "basic-block.h"
-#include "diagnostic-core.h"
+#include "tree.h"
+#include "gimple.h"
+#include "cfghooks.h"
+#include "cgraph.h"
 #include "coverage.h"
+#include "diagnostic-core.h"
+#include "cfganal.h"
 #include "value-prof.h"
-#include "tree.h"
-#include "tree-flow.h"
-#include "cfgloop.h"
+#include "gimple-iterator.h"
+#include "tree-cfg.h"
 #include "dumpfile.h"
+#include "cfgloop.h"
 
 #include "profile.h"
 
-struct bb_info {
+/* Map from BBs/edges to gcov counters.  */
+vec<gcov_type> bb_gcov_counts;
+hash_map<edge,gcov_type> *edge_gcov_counts;
+
+struct bb_profile_info {
   unsigned int count_valid : 1;
 
   /* Number of successor and predecessor edges.  */
@@ -75,16 +79,12 @@ struct bb_info {
   gcov_type pred_count;
 };
 
-#define BB_INFO(b)  ((struct bb_info *) (b)->aux)
+#define BB_INFO(b)  ((struct bb_profile_info *) (b)->aux)
 
 
 /* Counter summary from the last set of coverage counts read.  */
 
-const struct gcov_ctr_summary *profile_info;
-
-/* Counter working set information computed from the current counter
-   summary. Not initialized unless profile_info summary is non-NULL.  */
-static gcov_working_set_t gcov_working_sets[NUM_GCOV_WORKING_SETS];
+gcov_summary *profile_info;
 
 /* Collect statistics on the performance of this pass for the entire source
    file.  */
@@ -114,14 +114,14 @@ instrument_edges (struct edge_list *el)
   int num_edges = NUM_EDGES (el);
   basic_block bb;
 
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     {
       edge e;
       edge_iterator ei;
 
       FOR_EACH_EDGE (e, ei, bb->succs)
        {
-         struct edge_info *inf = EDGE_INFO (e);
+         struct edge_profile_info *inf = EDGE_INFO (e);
 
          if (!inf->ignore && !inf->on_tree)
            {
@@ -160,31 +160,31 @@ instrument_values (histogram_values values)
       switch (hist->type)
        {
        case HIST_TYPE_INTERVAL:
-         gimple_gen_interval_profiler (hist, t, 0);
+         gimple_gen_interval_profiler (hist, t);
          break;
 
        case HIST_TYPE_POW2:
-         gimple_gen_pow2_profiler (hist, t, 0);
-         break;
-
-       case HIST_TYPE_SINGLE_VALUE:
-         gimple_gen_one_value_profiler (hist, t, 0);
+         gimple_gen_pow2_profiler (hist, t);
          break;
 
-       case HIST_TYPE_CONST_DELTA:
-         gimple_gen_const_delta_profiler (hist, t, 0);
+       case HIST_TYPE_TOPN_VALUES:
+         gimple_gen_topn_values_profiler (hist, t);
          break;
 
        case HIST_TYPE_INDIR_CALL:
-         gimple_gen_ic_profiler (hist, t, 0);
+         gimple_gen_ic_profiler (hist, t);
          break;
 
        case HIST_TYPE_AVERAGE:
-         gimple_gen_average_profiler (hist, t, 0);
+         gimple_gen_average_profiler (hist, t);
          break;
 
        case HIST_TYPE_IOR:
-         gimple_gen_ior_profiler (hist, t, 0);
+         gimple_gen_ior_profiler (hist, t);
+         break;
+
+       case HIST_TYPE_TIME_PROFILE:
+         gimple_gen_time_profiler (t);
          break;
 
        default:
@@ -194,60 +194,6 @@ instrument_values (histogram_values values)
 }
 \f
 
-/* Fill the working set information into the profile_info structure.  */
-
-void
-get_working_sets (void)
-{
-  unsigned ws_ix, pctinc, pct;
-  gcov_working_set_t *ws_info;
-
-  if (!profile_info)
-    return;
-
-  compute_working_sets (profile_info, gcov_working_sets);
-
-  if (dump_file)
-    {
-      fprintf (dump_file, "Counter working sets:\n");
-      /* Multiply the percentage by 100 to avoid float.  */
-      pctinc = 100 * 100 / NUM_GCOV_WORKING_SETS;
-      for (ws_ix = 0, pct = pctinc; ws_ix < NUM_GCOV_WORKING_SETS;
-           ws_ix++, pct += pctinc)
-        {
-          if (ws_ix == NUM_GCOV_WORKING_SETS - 1)
-            pct = 9990;
-          ws_info = &gcov_working_sets[ws_ix];
-          /* Print out the percentage using int arithmatic to avoid float.  */
-          fprintf (dump_file, "\t\t%u.%02u%%: num counts=%u, min counter="
-                   HOST_WIDEST_INT_PRINT_DEC "\n",
-                   pct / 100, pct - (pct / 100 * 100),
-                   ws_info->num_counters,
-                   (HOST_WIDEST_INT)ws_info->min_counter);
-        }
-    }
-}
-
-/* Given a the desired percentage of the full profile (sum_all from the
-   summary), multiplied by 10 to avoid float in PCT_TIMES_10, returns
-   the corresponding working set information. If an exact match for
-   the percentage isn't found, the closest value is used.  */
-
-gcov_working_set_t *
-find_working_set (unsigned pct_times_10)
-{
-  unsigned i;
-  if (!profile_info)
-    return NULL;
-  gcc_assert (pct_times_10 <= 1000);
-  if (pct_times_10 >= 999)
-    return &gcov_working_sets[NUM_GCOV_WORKING_SETS - 1];
-  i = pct_times_10 * NUM_GCOV_WORKING_SETS / 1000;
-  if (!i)
-    return &gcov_working_sets[0];
-  return &gcov_working_sets[i - 1];
-}
-
 /* Computes hybrid profile for all matching entries in da_file.  
    
    CFG_CHECKSUM is the precomputed checksum for the CFG.  */
@@ -260,7 +206,7 @@ get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum)
   gcov_type *counts;
 
   /* Count the edges to be (possibly) instrumented.  */
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     {
       edge e;
       edge_iterator ei;
@@ -270,21 +216,14 @@ get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum)
          num_edges++;
     }
 
-  counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, cfg_checksum,
-                               lineno_checksum, &profile_info);
+  counts = get_coverage_counts (GCOV_COUNTER_ARCS, cfg_checksum,
+                               lineno_checksum, num_edges);
   if (!counts)
     return NULL;
 
-  get_working_sets();
-
-  if (dump_file && profile_info)
-    fprintf(dump_file, "Merged %u profiles with maximal count %u.\n",
-           profile_info->runs, (unsigned) profile_info->sum_max);
-
   return counts;
 }
 
-
 static bool
 is_edge_inconsistent (vec<edge, va_gc> *edges)
 {
@@ -294,15 +233,15 @@ is_edge_inconsistent (vec<edge, va_gc> *edges)
     {
       if (!EDGE_INFO (e)->ignore)
         {
-          if (e->count < 0
+          if (edge_gcov_count (e) < 0
              && (!(e->flags & EDGE_FAKE)
                  || !block_ends_with_call_p (e->src)))
            {
              if (dump_file)
                {
                  fprintf (dump_file,
-                          "Edge %i->%i is inconsistent, count"HOST_WIDEST_INT_PRINT_DEC,
-                          e->src->index, e->dest->index, e->count);
+                          "Edge %i->%i is inconsistent, count%" PRId64,
+                          e->src->index, e->dest->index, edge_gcov_count (e));
                  dump_bb (dump_file, e->src, 0, TDF_DETAILS);
                  dump_bb (dump_file, e->dest, 0, TDF_DETAILS);
                }
@@ -320,12 +259,12 @@ correct_negative_edge_counts (void)
   edge e;
   edge_iterator ei;
 
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     {
       FOR_EACH_EDGE (e, ei, bb->succs)
         {
-           if (e->count < 0)
-             e->count = 0;
+           if (edge_gcov_count (e) < 0)
+             edge_gcov_count (e) = 0;
         }
     }
 }
@@ -337,7 +276,7 @@ is_inconsistent (void)
 {
   basic_block bb;
   bool inconsistent = false;
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
       inconsistent |= is_edge_inconsistent (bb->preds);
       if (!dump_file && inconsistent)
@@ -345,40 +284,41 @@ is_inconsistent (void)
       inconsistent |= is_edge_inconsistent (bb->succs);
       if (!dump_file && inconsistent)
        return true;
-      if (bb->count < 0)
+      if (bb_gcov_count (bb) < 0)
         {
          if (dump_file)
            {
              fprintf (dump_file, "BB %i count is negative "
-                      HOST_WIDEST_INT_PRINT_DEC,
+                      "%" PRId64,
                       bb->index,
-                      bb->count);
+                      bb_gcov_count (bb));
              dump_bb (dump_file, bb, 0, TDF_DETAILS);
            }
          inconsistent = true;
        }
-      if (bb->count != sum_edge_counts (bb->preds))
+      if (bb_gcov_count (bb) != sum_edge_counts (bb->preds))
         {
          if (dump_file)
            {
              fprintf (dump_file, "BB %i count does not match sum of incoming edges "
-                      HOST_WIDEST_INT_PRINT_DEC" should be " HOST_WIDEST_INT_PRINT_DEC,
+                      "%" PRId64" should be %" PRId64,
                       bb->index,
-                      bb->count,
+                      bb_gcov_count (bb),
                       sum_edge_counts (bb->preds));
              dump_bb (dump_file, bb, 0, TDF_DETAILS);
            }
          inconsistent = true;
        }
-      if (bb->count != sum_edge_counts (bb->succs) &&
-          ! (find_edge (bb, EXIT_BLOCK_PTR) != NULL && block_ends_with_call_p (bb)))
+      if (bb_gcov_count (bb) != sum_edge_counts (bb->succs) &&
+         ! (find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun)) != NULL
+            && block_ends_with_call_p (bb)))
        {
          if (dump_file)
            {
              fprintf (dump_file, "BB %i count does not match sum of outgoing edges "
-                      HOST_WIDEST_INT_PRINT_DEC" should be " HOST_WIDEST_INT_PRINT_DEC,
+                      "%" PRId64" should be %" PRId64,
                       bb->index,
-                      bb->count,
+                      bb_gcov_count (bb),
                       sum_edge_counts (bb->succs));
              dump_bb (dump_file, bb, 0, TDF_DETAILS);
            }
@@ -396,10 +336,10 @@ static void
 set_bb_counts (void)
 {
   basic_block bb;
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     {
-      bb->count = sum_edge_counts (bb->succs);
-      gcc_assert (bb->count >= 0);
+      bb_gcov_count (bb) = sum_edge_counts (bb->succs);
+      gcc_assert (bb_gcov_count (bb) >= 0);
     }
 }
 
@@ -415,7 +355,7 @@ read_profile_edge_counts (gcov_type *exec_counts)
   /* The first count in the .da file is the number of times that the function
      was entered.  This is the exec_count for block zero.  */
 
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     {
       edge e;
       edge_iterator ei;
@@ -425,25 +365,9 @@ read_profile_edge_counts (gcov_type *exec_counts)
          {
            num_edges++;
            if (exec_counts)
-             {
-               e->count = exec_counts[exec_counts_pos++];
-               if (e->count > profile_info->sum_max)
-                 {
-                   if (flag_profile_correction)
-                     {
-                       static bool informed = 0;
-                       if (!informed)
-                         inform (input_location,
-                                 "corrupted profile info: edge count exceeds maximal count");
-                       informed = 1;
-                     }
-                   else
-                     error ("corrupted profile info: edge from %i to %i exceeds maximal count",
-                            bb->index, e->dest->index);
-                 }
-             }
+             edge_gcov_count (e) = exec_counts[exec_counts_pos++];
            else
-             e->count = 0;
+             edge_gcov_count (e) = 0;
 
            EDGE_INFO (e)->count_valid = 1;
            BB_INFO (bb)->succ_count--;
@@ -452,8 +376,8 @@ read_profile_edge_counts (gcov_type *exec_counts)
              {
                fprintf (dump_file, "\nRead edge from %i to %i, count:",
                         bb->index, e->dest->index);
-               fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
-                        (HOST_WIDEST_INT) e->count);
+               fprintf (dump_file, "%" PRId64,
+                        (int64_t) edge_gcov_count (e));
              }
          }
     }
@@ -461,38 +385,6 @@ read_profile_edge_counts (gcov_type *exec_counts)
     return num_edges;
 }
 
-#define OVERLAP_BASE 10000
-
-/* Compare the static estimated profile to the actual profile, and
-   return the "degree of overlap" measure between them.
-
-   Degree of overlap is a number between 0 and OVERLAP_BASE. It is
-   the sum of each basic block's minimum relative weights between
-   two profiles. And overlap of OVERLAP_BASE means two profiles are
-   identical.  */
-
-static int
-compute_frequency_overlap (void)
-{
-  gcov_type count_total = 0, freq_total = 0;
-  int overlap = 0;
-  basic_block bb;
-
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
-    {
-      count_total += bb->count;
-      freq_total += bb->frequency;
-    }
-
-  if (count_total == 0 || freq_total == 0)
-    return 0;
-
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
-    overlap += MIN (bb->count * OVERLAP_BASE / count_total,
-                   bb->frequency * OVERLAP_BASE / freq_total);
-
-  return overlap;
-}
 
 /* Compute the branch probabilities for the various branches.
    Annotate them accordingly.  
@@ -514,22 +406,18 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
 
   /* Very simple sanity checks so we catch bugs in our profiling code.  */
   if (!profile_info)
-    return;
-  if (profile_info->run_max * profile_info->runs < profile_info->sum_max)
     {
-      error ("corrupted profile info: run_max * runs < sum_max");
-      exec_counts = NULL;
+      if (dump_file)
+       fprintf (dump_file, "Profile info is missing; giving up\n");
+      return;
     }
 
-  if (profile_info->sum_all < profile_info->sum_max)
-    {
-      error ("corrupted profile info: sum_all is smaller than sum_max");
-      exec_counts = NULL;
-    }
+  bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun), true);
+  edge_gcov_counts = new hash_map<edge,gcov_type>;
 
   /* Attach extra info block to each bb.  */
-  alloc_aux_for_blocks (sizeof (struct bb_info));
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  alloc_aux_for_blocks (sizeof (struct bb_profile_info));
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     {
       edge e;
       edge_iterator ei;
@@ -543,8 +431,8 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
     }
 
   /* Avoid predicting entry on exit nodes.  */
-  BB_INFO (EXIT_BLOCK_PTR)->succ_count = 2;
-  BB_INFO (ENTRY_BLOCK_PTR)->pred_count = 2;
+  BB_INFO (EXIT_BLOCK_PTR_FOR_FN (cfun))->succ_count = 2;
+  BB_INFO (ENTRY_BLOCK_PTR_FOR_FN (cfun))->pred_count = 2;
 
   num_edges = read_profile_edge_counts (exec_counts);
 
@@ -574,9 +462,9 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
     {
       passes++;
       changes = 0;
-      FOR_BB_BETWEEN (bb, EXIT_BLOCK_PTR, NULL, prev_bb)
+      FOR_BB_BETWEEN (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), NULL, prev_bb)
        {
-         struct bb_info *bi = BB_INFO (bb);
+         struct bb_profile_info *bi = BB_INFO (bb);
          if (! bi->count_valid)
            {
              if (bi->succ_count == 0)
@@ -586,8 +474,8 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
                  gcov_type total = 0;
 
                  FOR_EACH_EDGE (e, ei, bb->succs)
-                   total += e->count;
-                 bb->count = total;
+                   total += edge_gcov_count (e);
+                 bb_gcov_count (bb) = total;
                  bi->count_valid = 1;
                  changes = 1;
                }
@@ -598,8 +486,8 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
                  gcov_type total = 0;
 
                  FOR_EACH_EDGE (e, ei, bb->preds)
-                   total += e->count;
-                 bb->count = total;
+                   total += edge_gcov_count (e);
+                 bb_gcov_count (bb) = total;
                  bi->count_valid = 1;
                  changes = 1;
                }
@@ -615,7 +503,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
                  /* One of the counts will be invalid, but it is zero,
                     so adding it in also doesn't hurt.  */
                  FOR_EACH_EDGE (e, ei, bb->succs)
-                   total += e->count;
+                   total += edge_gcov_count (e);
 
                  /* Search for the invalid edge, and set its count.  */
                  FOR_EACH_EDGE (e, ei, bb->succs)
@@ -623,11 +511,11 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
                      break;
 
                  /* Calculate count for remaining edge by conservation.  */
-                 total = bb->count - total;
+                 total = bb_gcov_count (bb) - total;
 
                  gcc_assert (e);
                  EDGE_INFO (e)->count_valid = 1;
-                 e->count = total;
+                 edge_gcov_count (e) = total;
                  bi->succ_count--;
 
                  BB_INFO (e->dest)->pred_count--;
@@ -642,7 +530,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
                  /* One of the counts will be invalid, but it is zero,
                     so adding it in also doesn't hurt.  */
                  FOR_EACH_EDGE (e, ei, bb->preds)
-                   total += e->count;
+                   total += edge_gcov_count (e);
 
                  /* Search for the invalid edge, and set its count.  */
                  FOR_EACH_EDGE (e, ei, bb->preds)
@@ -650,11 +538,11 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
                      break;
 
                  /* Calculate count for remaining edge by conservation.  */
-                 total = bb->count - total + e->count;
+                 total = bb_gcov_count (bb) - total + edge_gcov_count (e);
 
                  gcc_assert (e);
                  EDGE_INFO (e)->count_valid = 1;
-                 e->count = total;
+                 edge_gcov_count (e) = total;
                  bi->pred_count--;
 
                  BB_INFO (e->src)->succ_count--;
@@ -663,14 +551,6 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
            }
        }
     }
-  if (dump_file)
-    {
-      int overlap = compute_frequency_overlap ();
-      gimple_dump_cfg (dump_file, dump_flags);
-      fprintf (dump_file, "Static profile overlap: %d.%d%%\n",
-              overlap / (OVERLAP_BASE / 100),
-              overlap % (OVERLAP_BASE / 100));
-    }
 
   total_num_passes += passes;
   if (dump_file)
@@ -678,7 +558,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
 
   /* If the graph has been correctly solved, every block will have a
      succ and pred count of zero.  */
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
       gcc_assert (!BB_INFO (bb)->succ_count && !BB_INFO (bb)->pred_count);
     }
@@ -692,10 +572,12 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
        {
          /* Inconsistency detected. Make it flow-consistent. */
          static int informed = 0;
-         if (informed == 0)
+         if (dump_enabled_p () && informed == 0)
            {
              informed = 1;
-             inform (input_location, "correcting inconsistent profile data");
+             dump_printf_loc (MSG_NOTE,
+                             dump_user_location_t::from_location_t (input_location),
+                              "correcting inconsistent profile data\n");
            }
          correct_negative_edge_counts ();
          /* Set bb counts to the sum of the outgoing edge counts */
@@ -715,16 +597,16 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
     hist_br_prob[i] = 0;
   num_branches = 0;
 
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     {
       edge e;
       edge_iterator ei;
 
-      if (bb->count < 0)
+      if (bb_gcov_count (bb) < 0)
        {
          error ("corrupted profile info: number of iterations for basic block %d thought to be %i",
-                bb->index, (int)bb->count);
-         bb->count = 0;
+                bb->index, (int)bb_gcov_count (bb));
+         bb_gcov_count (bb) = 0;
        }
       FOR_EACH_EDGE (e, ei, bb->succs)
        {
@@ -733,26 +615,40 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
             edge from the entry, since extra edge from the exit is
             already present.  We get negative frequency from the entry
             point.  */
-         if ((e->count < 0
-              && e->dest == EXIT_BLOCK_PTR)
-             || (e->count > bb->count
-                 && e->dest != EXIT_BLOCK_PTR))
+         if ((edge_gcov_count (e) < 0
+              && e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+             || (edge_gcov_count (e) > bb_gcov_count (bb)
+                 && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)))
            {
              if (block_ends_with_call_p (bb))
-               e->count = e->count < 0 ? 0 : bb->count;
+               edge_gcov_count (e) = edge_gcov_count (e) < 0
+                                     ? 0 : bb_gcov_count (bb);
            }
-         if (e->count < 0 || e->count > bb->count)
+         if (edge_gcov_count (e) < 0
+             || edge_gcov_count (e) > bb_gcov_count (bb))
            {
              error ("corrupted profile info: number of executions for edge %d-%d thought to be %i",
                     e->src->index, e->dest->index,
-                    (int)e->count);
-             e->count = bb->count / 2;
+                    (int)edge_gcov_count (e));
+             edge_gcov_count (e) = bb_gcov_count (bb) / 2;
            }
        }
-      if (bb->count)
+      if (bb_gcov_count (bb))
        {
+         bool set_to_guessed = false;
          FOR_EACH_EDGE (e, ei, bb->succs)
-           e->probability = GCOV_COMPUTE_SCALE (e->count, bb->count);
+           {
+             bool prev_never = e->probability == profile_probability::never ();
+             e->probability = profile_probability::probability_in_gcov_type
+                 (edge_gcov_count (e), bb_gcov_count (bb));
+             if (e->probability == profile_probability::never ()
+                 && !prev_never
+                 && flag_profile_partial_training)
+               set_to_guessed = true;
+           }
+         if (set_to_guessed)
+           FOR_EACH_EDGE (e, ei, bb->succs)
+             e->probability = e->probability.guessed ();
          if (bb->index >= NUM_FIXED_BLOCKS
              && block_ends_with_condjump_p (bb)
              && EDGE_COUNT (bb->succs) >= 2)
@@ -767,7 +663,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
                if (!(e->flags & (EDGE_FAKE | EDGE_FALLTHRU)))
                  break;
 
-             prob = e->probability;
+             prob = e->probability.to_reg_br_prob_base ();
              index = prob * 20 / REG_BR_PROB_BASE;
 
              if (index == 20)
@@ -782,7 +678,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
         give all abnormals frequency of 0, otherwise distribute the
         frequency over abnormals (this is the case of noreturn
         calls).  */
-      else if (profile_status == PROFILE_ABSENT)
+      else if (profile_status_for_fn (cfun) == PROFILE_ABSENT)
        {
          int total = 0;
 
@@ -793,15 +689,17 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
            {
              FOR_EACH_EDGE (e, ei, bb->succs)
                if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
-                 e->probability = REG_BR_PROB_BASE / total;
+                 e->probability
+                   = profile_probability::guessed_always ().apply_scale (1, total);
                else
-                 e->probability = 0;
+                 e->probability = profile_probability::never ();
            }
          else
            {
              total += EDGE_COUNT (bb->succs);
              FOR_EACH_EDGE (e, ei, bb->succs)
-               e->probability = REG_BR_PROB_BASE / total;
+               e->probability
+                = profile_probability::guessed_always ().apply_scale (1, total);
            }
          if (bb->index >= NUM_FIXED_BLOCKS
              && block_ends_with_condjump_p (bb)
@@ -809,12 +707,41 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
            num_branches++;
        }
     }
-  counts_to_freqs ();
-  profile_status = PROFILE_READ;
-  compute_function_frequency ();
+
+  if (exec_counts
+      && (bb_gcov_count (ENTRY_BLOCK_PTR_FOR_FN (cfun))
+         || !flag_profile_partial_training))
+    profile_status_for_fn (cfun) = PROFILE_READ;
+
+  /* If we have real data, use them!  */
+  if (bb_gcov_count (ENTRY_BLOCK_PTR_FOR_FN (cfun))
+      || !flag_guess_branch_prob)
+    FOR_ALL_BB_FN (bb, cfun)
+      if (bb_gcov_count (bb) || !flag_profile_partial_training)
+        bb->count = profile_count::from_gcov_type (bb_gcov_count (bb));
+      else
+       bb->count = profile_count::guessed_zero ();
+  /* If function was not trained, preserve local estimates including statically
+     determined zero counts.  */
+  else if (profile_status_for_fn (cfun) == PROFILE_READ
+          && !flag_profile_partial_training)
+    FOR_ALL_BB_FN (bb, cfun)
+      if (!(bb->count == profile_count::zero ()))
+        bb->count = bb->count.global0 ();
+
+  bb_gcov_counts.release ();
+  delete edge_gcov_counts;
+  edge_gcov_counts = NULL;
+
+  update_max_bb_count ();
 
   if (dump_file)
     {
+      fprintf (dump_file, " Profile feedback for function");
+      fprintf (dump_file, ((profile_status_for_fn (cfun) == PROFILE_READ)
+                          ? " is available \n"
+                          : " is not available \n"));
+
       fprintf (dump_file, "%d branches\n", num_branches);
       if (num_branches)
        for (i = 0; i < 10; i++)
@@ -833,6 +760,38 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
   free_aux_for_blocks ();
 }
 
+/* Sort the histogram value and count for TOPN and INDIR_CALL type.  */
+
+static void
+sort_hist_values (histogram_value hist)
+{
+  gcc_assert (hist->type == HIST_TYPE_TOPN_VALUES
+             || hist->type == HIST_TYPE_INDIR_CALL);
+
+  int counters = hist->hvalue.counters[1];
+  for (int i = 0; i < counters - 1; i++)
+  /* Hist value is organized as:
+     [total_executions, N, value1, counter1, ..., valueN, counterN]
+     Use decrease bubble sort to rearrange it.  The sort starts from <value1,
+     counter1> and compares counter first.  If counter is same, compares the
+     value, exchange it if small to keep stable.  */
+
+    {
+      bool swapped = false;
+      for (int j = 0; j < counters - 1 - i; j++)
+       {
+         gcov_type *p = &hist->hvalue.counters[2 * j + 2];
+         if (p[1] < p[3] || (p[1] == p[3] && p[0] < p[2]))
+           {
+             std::swap (p[0], p[2]);
+             std::swap (p[1], p[3]);
+             swapped = true;
+           }
+       }
+      if (!swapped)
+       break;
+    }
+}
 /* Load value histograms values whose description is stored in VALUES array
    from .gcda file.  
 
@@ -847,6 +806,7 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum,
   gcov_type *histogram_counts[GCOV_N_VALUE_COUNTERS];
   gcov_type *act_count[GCOV_N_VALUE_COUNTERS];
   gcov_type *aact_count;
+  struct cgraph_node *node;
 
   for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
     n_histogram_counters[t] = 0;
@@ -866,10 +826,10 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum,
          continue;
        }
 
-      histogram_counts[t] =
-       get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
-                            n_histogram_counters[t], cfg_checksum,
-                            lineno_checksum, NULL);
+      histogram_counts[t] = get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
+                                                cfg_checksum,
+                                                lineno_checksum,
+                                                n_histogram_counters[t]);
       if (histogram_counts[t])
        any = 1;
       act_count[t] = histogram_counts[t];
@@ -880,38 +840,158 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum,
   for (i = 0; i < values.length (); i++)
     {
       histogram_value hist = values[i];
-      gimple stmt = hist->hvalue.stmt;
+      gimple *stmt = hist->hvalue.stmt;
 
       t = (int) hist->type;
+      bool topn_p = (hist->type == HIST_TYPE_TOPN_VALUES
+                    || hist->type == HIST_TYPE_INDIR_CALL);
+
+      /* TOP N counter uses variable number of counters.  */
+      if (topn_p)
+       {
+         unsigned total_size;
+         if (act_count[t])
+           total_size = 2 + 2 * act_count[t][1];
+         else
+           total_size = 2;
+         gimple_add_histogram_value (cfun, stmt, hist);
+         hist->n_counters = total_size;
+         hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
+         for (j = 0; j < hist->n_counters; j++)
+           if (act_count[t])
+             hist->hvalue.counters[j] = act_count[t][j];
+           else
+             hist->hvalue.counters[j] = 0;
+         act_count[t] += hist->n_counters;
+         sort_hist_values (hist);
+       }
+      else
+       {
+         aact_count = act_count[t];
+
+         if (act_count[t])
+           act_count[t] += hist->n_counters;
+
+         gimple_add_histogram_value (cfun, stmt, hist);
+         hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
+         for (j = 0; j < hist->n_counters; j++)
+           if (aact_count)
+             hist->hvalue.counters[j] = aact_count[j];
+           else
+             hist->hvalue.counters[j] = 0;
+       }
+
+      /* Time profiler counter is not related to any statement,
+         so that we have to read the counter and set the value to
+         the corresponding call graph node.  */
+      if (hist->type == HIST_TYPE_TIME_PROFILE)
+        {
+         node = cgraph_node::get (hist->fun->decl);
+         if (hist->hvalue.counters[0] >= 0
+             && hist->hvalue.counters[0] < INT_MAX / 2)
+           node->tp_first_run = hist->hvalue.counters[0];
+         else
+           {
+             if (flag_profile_correction)
+               error ("corrupted profile info: invalid time profile");
+             node->tp_first_run = 0;
+           }
 
-      aact_count = act_count[t];
-      if (act_count[t])
-        act_count[t] += hist->n_counters;
-
-      gimple_add_histogram_value (cfun, stmt, hist);
-      hist->hvalue.counters =  XNEWVEC (gcov_type, hist->n_counters);
-      for (j = 0; j < hist->n_counters; j++)
-        if (aact_count)
-         hist->hvalue.counters[j] = aact_count[j];
-       else
-         hist->hvalue.counters[j] = 0;
+          if (dump_file)
+            fprintf (dump_file, "Read tp_first_run: %d\n", node->tp_first_run);
+        }
     }
 
   for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
     free (histogram_counts[t]);
 }
 
+/* Location triplet which records a location.  */
+struct location_triplet
+{
+  const char *filename;
+  int lineno;
+  int bb_index;
+};
+
+/* Traits class for streamed_locations hash set below.  */
+
+struct location_triplet_hash : typed_noop_remove <location_triplet>
+{
+  typedef location_triplet value_type;
+  typedef location_triplet compare_type;
+
+  static hashval_t
+  hash (const location_triplet &ref)
+  {
+    inchash::hash hstate (0);
+    if (ref.filename)
+      hstate.add_int (strlen (ref.filename));
+    hstate.add_int (ref.lineno);
+    hstate.add_int (ref.bb_index);
+    return hstate.end ();
+  }
+
+  static bool
+  equal (const location_triplet &ref1, const location_triplet &ref2)
+  {
+    return ref1.lineno == ref2.lineno
+      && ref1.bb_index == ref2.bb_index
+      && ref1.filename != NULL
+      && ref2.filename != NULL
+      && strcmp (ref1.filename, ref2.filename) == 0;
+  }
+
+  static void
+  mark_deleted (location_triplet &ref)
+  {
+    ref.lineno = -1;
+  }
+
+  static const bool empty_zero_p = false;
+
+  static void
+  mark_empty (location_triplet &ref)
+  {
+    ref.lineno = -2;
+  }
+
+  static bool
+  is_deleted (const location_triplet &ref)
+  {
+    return ref.lineno == -1;
+  }
+
+  static bool
+  is_empty (const location_triplet &ref)
+  {
+    return ref.lineno == -2;
+  }
+};
+
+
+
+
 /* When passed NULL as file_name, initialize.
    When passed something else, output the necessary commands to change
    line to LINE and offset to FILE_NAME.  */
 static void
-output_location (char const *file_name, int line,
+output_location (hash_set<location_triplet_hash> *streamed_locations,
+                char const *file_name, int line,
                 gcov_position_t *offset, basic_block bb)
 {
   static char const *prev_file_name;
   static int prev_line;
   bool name_differs, line_differs;
 
+  location_triplet triplet;
+  triplet.filename = file_name;
+  triplet.lineno = line;
+  triplet.bb_index = bb ? bb->index : 0;
+
+  if (streamed_locations->add (triplet))
+    return;
+
   if (!file_name)
     {
       prev_file_name = NULL;
@@ -922,31 +1002,68 @@ output_location (char const *file_name, int line,
   name_differs = !prev_file_name || filename_cmp (file_name, prev_file_name);
   line_differs = prev_line != line;
 
-  if (name_differs || line_differs)
+  if (!*offset)
     {
-      if (!*offset)
-       {
-         *offset = gcov_write_tag (GCOV_TAG_LINES);
-         gcov_write_unsigned (bb->index);
-         name_differs = line_differs=true;
-       }
+      *offset = gcov_write_tag (GCOV_TAG_LINES);
+      gcov_write_unsigned (bb->index);
+      name_differs = line_differs = true;
+    }
 
-      /* If this is a new source file, then output the
-        file's name to the .bb file.  */
-      if (name_differs)
-       {
-         prev_file_name = file_name;
-         gcov_write_unsigned (0);
-         gcov_write_string (prev_file_name);
-       }
-      if (line_differs)
-       {
-         gcov_write_unsigned (line);
-         prev_line = line;
-       }
-     }
+  /* If this is a new source file, then output the
+     file's name to the .bb file.  */
+  if (name_differs)
+    {
+      prev_file_name = file_name;
+      gcov_write_unsigned (0);
+      gcov_write_filename (prev_file_name);
+    }
+  if (line_differs)
+    {
+      gcov_write_unsigned (line);
+      prev_line = line;
+    }
+}
+
+/* Helper for qsort so edges get sorted from highest frequency to smallest.
+   This controls the weight for minimal spanning tree algorithm  */
+static int
+compare_freqs (const void *p1, const void *p2)
+{
+  const_edge e1 = *(const const_edge *)p1;
+  const_edge e2 = *(const const_edge *)p2;
+
+  /* Critical edges needs to be split which introduce extra control flow.
+     Make them more heavy.  */
+  int m1 = EDGE_CRITICAL_P (e1) ? 2 : 1;
+  int m2 = EDGE_CRITICAL_P (e2) ? 2 : 1;
+
+  if (EDGE_FREQUENCY (e1) * m1 + m1 != EDGE_FREQUENCY (e2) * m2 + m2)
+    return EDGE_FREQUENCY (e2) * m2 + m2 - EDGE_FREQUENCY (e1) * m1 - m1;
+  /* Stabilize sort.  */
+  if (e1->src->index != e2->src->index)
+    return e2->src->index - e1->src->index;
+  return e2->dest->index - e1->dest->index;
 }
 
+/* Only read execution count for thunks.  */
+
+void
+read_thunk_profile (struct cgraph_node *node)
+{
+  tree old = current_function_decl;
+  current_function_decl = node->decl;
+  gcov_type *counts = get_coverage_counts (GCOV_COUNTER_ARCS, 0, 0, 1);
+  if (counts)
+    {
+      node->callees->count = node->count
+        = profile_count::from_gcov_type (counts[0]);
+      free (counts);
+    }
+  current_function_decl = old;
+  return;
+}
+
+
 /* Instrument and/or analyze program behavior based on program the CFG.
 
    This function creates a representation of the control flow graph (of
@@ -967,14 +1084,14 @@ output_location (char const *file_name, int line,
    Main entry point of this file.  */
 
 void
-branch_prob (void)
+branch_prob (bool thunk)
 {
   basic_block bb;
   unsigned i;
   unsigned num_edges, ignored_edges;
   unsigned num_instrumented;
   struct edge_list *el;
-  histogram_values values = histogram_values();
+  histogram_values values = histogram_values ();
   unsigned cfg_checksum, lineno_checksum;
 
   total_num_times_called++;
@@ -982,134 +1099,131 @@ branch_prob (void)
   flow_call_edges_add (NULL);
   add_noreturn_fake_exit_edges ();
 
-  /* We can't handle cyclic regions constructed using abnormal edges.
-     To avoid these we replace every source of abnormal edge by a fake
-     edge from entry node and every destination by fake edge to exit.
-     This keeps graph acyclic and our calculation exact for all normal
-     edges except for exit and entrance ones.
-
-     We also add fake exit edges for each call and asm statement in the
-     basic, since it may not return.  */
+  hash_set <location_triplet_hash> streamed_locations;
 
-  FOR_EACH_BB (bb)
+  if (!thunk)
     {
-      int need_exit_edge = 0, need_entry_edge = 0;
-      int have_exit_edge = 0, have_entry_edge = 0;
-      edge e;
-      edge_iterator ei;
+      /* We can't handle cyclic regions constructed using abnormal edges.
+        To avoid these we replace every source of abnormal edge by a fake
+        edge from entry node and every destination by fake edge to exit.
+        This keeps graph acyclic and our calculation exact for all normal
+        edges except for exit and entrance ones.
 
-      /* Functions returning multiple times are not handled by extra edges.
-         Instead we simply allow negative counts on edges from exit to the
-         block past call and corresponding probabilities.  We can't go
-         with the extra edges because that would result in flowgraph that
-        needs to have fake edges outside the spanning tree.  */
+        We also add fake exit edges for each call and asm statement in the
+        basic, since it may not return.  */
 
-      FOR_EACH_EDGE (e, ei, bb->succs)
+      FOR_EACH_BB_FN (bb, cfun)
        {
-         gimple_stmt_iterator gsi;
-         gimple last = NULL;
-
-         /* It may happen that there are compiler generated statements
-            without a locus at all.  Go through the basic block from the
-            last to the first statement looking for a locus.  */
-         for (gsi = gsi_last_nondebug_bb (bb);
-              !gsi_end_p (gsi);
-              gsi_prev_nondebug (&gsi))
-           {
-             last = gsi_stmt (gsi);
-             if (gimple_has_location (last))
-               break;
-           }
+         int need_exit_edge = 0, need_entry_edge = 0;
+         int have_exit_edge = 0, have_entry_edge = 0;
+         edge e;
+         edge_iterator ei;
 
-         /* Edge with goto locus might get wrong coverage info unless
-            it is the only edge out of BB.
-            Don't do that when the locuses match, so
-            if (blah) goto something;
-            is not computed twice.  */
-         if (last
-             && gimple_has_location (last)
-             && LOCATION_LOCUS (e->goto_locus) != UNKNOWN_LOCATION
-             && !single_succ_p (bb)
-             && (LOCATION_FILE (e->goto_locus)
-                 != LOCATION_FILE (gimple_location (last))
-                 || (LOCATION_LINE (e->goto_locus)
-                     != LOCATION_LINE (gimple_location (last)))))
-           {
-             basic_block new_bb = split_edge (e);
-             edge ne = single_succ_edge (new_bb);
-             ne->goto_locus = e->goto_locus;
-           }
-         if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
-              && e->dest != EXIT_BLOCK_PTR)
-           need_exit_edge = 1;
-         if (e->dest == EXIT_BLOCK_PTR)
-           have_exit_edge = 1;
-       }
-      FOR_EACH_EDGE (e, ei, bb->preds)
-       {
-         if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
-              && e->src != ENTRY_BLOCK_PTR)
-           need_entry_edge = 1;
-         if (e->src == ENTRY_BLOCK_PTR)
-           have_entry_edge = 1;
-       }
+         /* Functions returning multiple times are not handled by extra edges.
+            Instead we simply allow negative counts on edges from exit to the
+            block past call and corresponding probabilities.  We can't go
+            with the extra edges because that would result in flowgraph that
+            needs to have fake edges outside the spanning tree.  */
 
-      if (need_exit_edge && !have_exit_edge)
-       {
-         if (dump_file)
-           fprintf (dump_file, "Adding fake exit edge to bb %i\n",
-                    bb->index);
-         make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
-       }
-      if (need_entry_edge && !have_entry_edge)
-       {
-         if (dump_file)
-           fprintf (dump_file, "Adding fake entry edge to bb %i\n",
-                    bb->index);
-         make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
-         /* Avoid bbs that have both fake entry edge and also some
-            exit edge.  One of those edges wouldn't be added to the
-            spanning tree, but we can't instrument any of them.  */
-         if (have_exit_edge || need_exit_edge)
+         FOR_EACH_EDGE (e, ei, bb->succs)
            {
              gimple_stmt_iterator gsi;
-             gimple first;
-             tree fndecl;
+             gimple *last = NULL;
+
+             /* It may happen that there are compiler generated statements
+                without a locus at all.  Go through the basic block from the
+                last to the first statement looking for a locus.  */
+             for (gsi = gsi_last_nondebug_bb (bb);
+                  !gsi_end_p (gsi);
+                  gsi_prev_nondebug (&gsi))
+               {
+                 last = gsi_stmt (gsi);
+                 if (!RESERVED_LOCATION_P (gimple_location (last)))
+                   break;
+               }
 
-             gsi = gsi_after_labels (bb);
-             gcc_checking_assert (!gsi_end_p (gsi));
-             first = gsi_stmt (gsi);
-             if (is_gimple_debug (first))
+             /* Edge with goto locus might get wrong coverage info unless
+                it is the only edge out of BB.
+                Don't do that when the locuses match, so
+                if (blah) goto something;
+                is not computed twice.  */
+             if (last
+                 && gimple_has_location (last)
+                 && !RESERVED_LOCATION_P (e->goto_locus)
+                 && !single_succ_p (bb)
+                 && (LOCATION_FILE (e->goto_locus)
+                     != LOCATION_FILE (gimple_location (last))
+                     || (LOCATION_LINE (e->goto_locus)
+                         != LOCATION_LINE (gimple_location (last)))))
                {
-                 gsi_next_nondebug (&gsi);
-                 gcc_checking_assert (!gsi_end_p (gsi));
-                 first = gsi_stmt (gsi);
+                 basic_block new_bb = split_edge (e);
+                 edge ne = single_succ_edge (new_bb);
+                 ne->goto_locus = e->goto_locus;
                }
-             /* Don't split the bbs containing __builtin_setjmp_receiver
-                or __builtin_setjmp_dispatcher calls.  These are very
-                special and don't expect anything to be inserted before
-                them.  */
-             if (is_gimple_call (first)
-                 && (((fndecl = gimple_call_fndecl (first)) != NULL
-                      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-                      && (DECL_FUNCTION_CODE (fndecl)
-                          == BUILT_IN_SETJMP_RECEIVER
-                          || (DECL_FUNCTION_CODE (fndecl)
-                              == BUILT_IN_SETJMP_DISPATCHER)))
-                     || gimple_call_flags (first) & ECF_RETURNS_TWICE))
-               continue;
+             if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
+                  && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
+               need_exit_edge = 1;
+             if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+               have_exit_edge = 1;
+           }
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           {
+             if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
+                  && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+               need_entry_edge = 1;
+             if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun))
+               have_entry_edge = 1;
+           }
 
+         if (need_exit_edge && !have_exit_edge)
+           {
              if (dump_file)
-               fprintf (dump_file, "Splitting bb %i after labels\n",
+               fprintf (dump_file, "Adding fake exit edge to bb %i\n",
                         bb->index);
-             split_block_after_labels (bb);
+             make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
+           }
+         if (need_entry_edge && !have_entry_edge)
+           {
+             if (dump_file)
+               fprintf (dump_file, "Adding fake entry edge to bb %i\n",
+                        bb->index);
+             make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FAKE);
+             /* Avoid bbs that have both fake entry edge and also some
+                exit edge.  One of those edges wouldn't be added to the
+                spanning tree, but we can't instrument any of them.  */
+             if (have_exit_edge || need_exit_edge)
+               {
+                 gimple_stmt_iterator gsi;
+                 gimple *first;
+
+                 gsi = gsi_start_nondebug_after_labels_bb (bb);
+                 gcc_checking_assert (!gsi_end_p (gsi));
+                 first = gsi_stmt (gsi);
+                 /* Don't split the bbs containing __builtin_setjmp_receiver
+                    or ABNORMAL_DISPATCHER calls.  These are very
+                    special and don't expect anything to be inserted before
+                    them.  */
+                 if (is_gimple_call (first)
+                     && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
+                         || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
+                         || (gimple_call_internal_p (first)
+                             && (gimple_call_internal_fn (first)
+                                 == IFN_ABNORMAL_DISPATCHER))))
+                   continue;
+
+                 if (dump_file)
+                   fprintf (dump_file, "Splitting bb %i after labels\n",
+                            bb->index);
+                 split_block_after_labels (bb);
+               }
            }
        }
     }
 
   el = create_edge_list ();
   num_edges = NUM_EDGES (el);
-  alloc_aux_for_edges (sizeof (struct edge_info));
+  qsort (el->index_to_edge, num_edges, sizeof (edge), compare_freqs);
+  alloc_aux_for_edges (sizeof (struct edge_profile_info));
 
   /* The basic blocks are expected to be numbered sequentially.  */
   compact_blocks ();
@@ -1118,11 +1232,11 @@ branch_prob (void)
   for (i = 0 ; i < num_edges ; i++)
     {
       edge e = INDEX_EDGE (el, i);
-      e->count = 0;
 
       /* Mark edges we've replaced by fake edges above as ignored.  */
       if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
-         && e->src != ENTRY_BLOCK_PTR && e->dest != EXIT_BLOCK_PTR)
+         && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
+         && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
        {
          EDGE_INFO (e)->ignore = 1;
          ignored_edges++;
@@ -1133,14 +1247,25 @@ branch_prob (void)
      on the spanning tree.  We insert as many abnormal and critical edges
      as possible to minimize number of edge splits necessary.  */
 
-  find_spanning_tree (el);
+  if (!thunk)
+    find_spanning_tree (el);
+  else
+    {
+      edge e;
+      edge_iterator ei;
+      /* Keep only edge from entry block to be instrumented.  */
+      FOR_EACH_BB_FN (bb, cfun)
+       FOR_EACH_EDGE (e, ei, bb->succs)
+         EDGE_INFO (e)->ignore = true;
+    }
+
 
   /* Fake edges that are not on the tree will not be instrumented, so
      mark them ignored.  */
   for (num_instrumented = i = 0; i < num_edges; i++)
     {
       edge e = INDEX_EDGE (el, i);
-      struct edge_info *inf = EDGE_INFO (e);
+      struct edge_profile_info *inf = EDGE_INFO (e);
 
       if (inf->ignore || inf->on_tree)
        /*NOP*/;
@@ -1153,9 +1278,9 @@ branch_prob (void)
        num_instrumented++;
     }
 
-  total_num_blocks += n_basic_blocks;
+  total_num_blocks += n_basic_blocks_for_fn (cfun);
   if (dump_file)
-    fprintf (dump_file, "%d basic blocks\n", n_basic_blocks);
+    fprintf (dump_file, "%d basic blocks\n", n_basic_blocks_for_fn (cfun));
 
   total_num_edges += num_edges;
   if (dump_file)
@@ -1173,8 +1298,17 @@ branch_prob (void)
      the checksum in only once place, since it depends on the shape
      of the control flow which can change during 
      various transformations.  */
-  cfg_checksum = coverage_compute_cfg_checksum ();
-  lineno_checksum = coverage_compute_lineno_checksum ();
+  if (thunk)
+    {
+      /* At stream in time we do not have CFG, so we cannot do checksums.  */
+      cfg_checksum = 0;
+      lineno_checksum = 0;
+    }
+  else
+    {
+      cfg_checksum = coverage_compute_cfg_checksum (cfun);
+      lineno_checksum = coverage_compute_lineno_checksum ();
+    }
 
   /* Write the data from which gcov can reconstruct the basic block
      graph and function line numbers (the gcno file).  */
@@ -1184,12 +1318,12 @@ branch_prob (void)
 
       /* Basic block flags */
       offset = gcov_write_tag (GCOV_TAG_BLOCKS);
-      for (i = 0; i != (unsigned) (n_basic_blocks); i++)
-       gcov_write_unsigned (0);
+      gcov_write_unsigned (n_basic_blocks_for_fn (cfun));
       gcov_write_length (offset);
 
       /* Arcs */
-      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
+      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun),
+                     EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb)
        {
          edge e;
          edge_iterator ei;
@@ -1199,7 +1333,7 @@ branch_prob (void)
 
          FOR_EACH_EDGE (e, ei, bb->succs)
            {
-             struct edge_info *i = EDGE_INFO (e);
+             struct edge_profile_info *i = EDGE_INFO (e);
              if (!i->ignore)
                {
                  unsigned flag_bits = 0;
@@ -1226,38 +1360,48 @@ branch_prob (void)
 
       /* Line numbers.  */
       /* Initialize the output.  */
-      output_location (NULL, 0, NULL, NULL);
+      output_location (&streamed_locations, NULL, 0, NULL, NULL);
+
+      hash_set<int_hash <location_t, 0, 2> > seen_locations;
 
-      FOR_EACH_BB (bb)
+      FOR_EACH_BB_FN (bb, cfun)
        {
          gimple_stmt_iterator gsi;
          gcov_position_t offset = 0;
 
-         if (bb == ENTRY_BLOCK_PTR->next_bb)
+         if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb)
            {
-             expanded_location curr_location =
-               expand_location (DECL_SOURCE_LOCATION (current_function_decl));
-             output_location (curr_location.file, curr_location.line,
-                              &offset, bb);
+             location_t loc = DECL_SOURCE_LOCATION (current_function_decl);
+             seen_locations.add (loc);
+             expanded_location curr_location = expand_location (loc);
+             output_location (&streamed_locations, curr_location.file,
+                              MAX (1, curr_location.line), &offset, bb);
            }
 
          for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
            {
-             gimple stmt = gsi_stmt (gsi);
-             if (gimple_has_location (stmt))
-               output_location (gimple_filename (stmt), gimple_lineno (stmt),
-                                &offset, bb);
+             gimple *stmt = gsi_stmt (gsi);
+             location_t loc = gimple_location (stmt);
+             if (!RESERVED_LOCATION_P (loc))
+               {
+                 seen_locations.add (loc);
+                 output_location (&streamed_locations, gimple_filename (stmt),
+                                  MAX (1, gimple_lineno (stmt)), &offset, bb);
+               }
            }
 
-         /* Notice GOTO expressions eliminated while constructing the CFG.  */
+         /* Notice GOTO expressions eliminated while constructing the CFG.
+            It's hard to distinguish such expression, but goto_locus should
+            not be any of already seen location.  */
+         location_t loc;
          if (single_succ_p (bb)
-             && LOCATION_LOCUS (single_succ_edge (bb)->goto_locus)
-                != UNKNOWN_LOCATION)
+             && (loc = single_succ_edge (bb)->goto_locus)
+             && !RESERVED_LOCATION_P (loc)
+             && !seen_locations.contains (loc))
            {
-             expanded_location curr_location
-               = expand_location (single_succ_edge (bb)->goto_locus);
-             output_location (curr_location.file, curr_location.line,
-                              &offset, bb);
+             expanded_location curr_location = expand_location (loc);
+             output_location (&streamed_locations, curr_location.file,
+                              MAX (1, curr_location.line), &offset, bb);
            }
 
          if (offset)
@@ -1288,7 +1432,7 @@ branch_prob (void)
     {
       unsigned n_instrumented;
 
-      gimple_init_edge_profiler ();
+      gimple_init_gcov_profiler ();
 
       n_instrumented = instrument_edges (el);
 
@@ -1306,6 +1450,25 @@ branch_prob (void)
   values.release ();
   free_edge_list (el);
   coverage_end_function (lineno_checksum, cfg_checksum);
+  if (flag_branch_probabilities
+      && (profile_status_for_fn (cfun) == PROFILE_READ))
+    {
+      class loop *loop;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       report_predictor_hitrates ();
+
+      /* At this moment we have precise loop iteration count estimates.
+        Record them to loop structure before the profile gets out of date. */
+      FOR_EACH_LOOP (loop, 0)
+       if (loop->header->count > 0 && loop->header->count.reliable_p ())
+         {
+           gcov_type nit = expected_loop_iterations_unbounded (loop);
+           widest_int bound = gcov_type_to_wide_int (nit);
+           loop->any_estimate = false;
+           record_niter_bound (loop, bound, true, false);
+         }
+      compute_function_frequency ();
+    }
 }
 \f
 /* Union find algorithm implementation for the basic blocks using
@@ -1357,20 +1520,20 @@ find_spanning_tree (struct edge_list *el)
   basic_block bb;
 
   /* We use aux field for standard union-find algorithm.  */
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     bb->aux = bb;
 
   /* Add fake edge exit to entry we can't instrument.  */
-  union_groups (EXIT_BLOCK_PTR, ENTRY_BLOCK_PTR);
+  union_groups (EXIT_BLOCK_PTR_FOR_FN (cfun), ENTRY_BLOCK_PTR_FOR_FN (cfun));
 
   /* First add all abnormal edges to the tree unless they form a cycle. Also
-     add all edges to EXIT_BLOCK_PTR to avoid inserting profiling code behind
+     add all edges to the exit block to avoid inserting profiling code behind
      setting return value from function.  */
   for (i = 0; i < num_edges; i++)
     {
       edge e = INDEX_EDGE (el, i);
       if (((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
-          || e->dest == EXIT_BLOCK_PTR)
+          || e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
          && !EDGE_INFO (e)->ignore
          && (find_group (e->src) != find_group (e->dest)))
        {
@@ -1382,22 +1545,8 @@ find_spanning_tree (struct edge_list *el)
        }
     }
 
-  /* Now insert all critical edges to the tree unless they form a cycle.  */
-  for (i = 0; i < num_edges; i++)
-    {
-      edge e = INDEX_EDGE (el, i);
-      if (EDGE_CRITICAL_P (e) && !EDGE_INFO (e)->ignore
-         && find_group (e->src) != find_group (e->dest))
-       {
-         if (dump_file)
-           fprintf (dump_file, "Critical edge %d to %d put to tree\n",
-                    e->src->index, e->dest->index);
-         EDGE_INFO (e)->on_tree = 1;
-         union_groups (e->src, e->dest);
-       }
-    }
-
-  /* And now the rest.  */
+  /* And now the rest.  Edge list is sorted according to frequencies and
+     thus we will produce minimal spanning tree.  */
   for (i = 0; i < num_edges; i++)
     {
       edge e = INDEX_EDGE (el, i);