]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/profile.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / profile.c
index 9aff9ef2b211dcda90aa1744e95d7881b8d1aac3..c33c833167f660fe15f70da323d1c7b49c91e3a2 100644 (file)
@@ -1,5 +1,5 @@
 /* Calculate branch probabilities, and basic block execution counts.
-   Copyright (C) 1990-2019 Free Software Foundation, Inc.
+   Copyright (C) 1990-2021 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.
@@ -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);
+         gimple_gen_pow2_profiler (hist, t);
          break;
 
-       case HIST_TYPE_SINGLE_VALUE:
-         gimple_gen_one_value_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, 0);
+         gimple_gen_time_profiler (t);
          break;
 
        default:
@@ -412,7 +412,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
       return;
     }
 
-  bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun));
+  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.  */
@@ -635,9 +635,20 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
        }
       if (bb_gcov_count (bb))
        {
+         bool set_to_guessed = false;
          FOR_EACH_EDGE (e, ei, bb->succs)
-           e->probability = profile_probability::probability_in_gcov_type
-               (edge_gcov_count (e), bb_gcov_count (bb));
+           {
+             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)
@@ -697,17 +708,23 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
        }
     }
 
-  if (exec_counts)
+  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)
-      bb->count = profile_count::from_gcov_type (bb_gcov_count (bb));
+      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)
+  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 ();
@@ -743,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.  
 
@@ -794,19 +843,43 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum,
       gimple *stmt = hist->hvalue.stmt;
 
       t = (int) hist->type;
+      bool topn_p = (hist->type == HIST_TYPE_TOPN_VALUES
+                    || hist->type == HIST_TYPE_INDIR_CALL);
 
-      aact_count = act_count[t];
+      /* 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;
+         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;
+         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
@@ -814,10 +887,26 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum,
       if (hist->type == HIST_TYPE_TIME_PROFILE)
         {
          node = cgraph_node::get (hist->fun->decl);
-         node->tp_first_run = hist->hvalue.counters[0];
+         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;
+           }
+
+         /* Drop profile for -fprofile-reproducible=multithreaded.  */
+         bool drop
+           = (flag_profile_reproducible == PROFILE_REPRODUCIBILITY_MULTITHREADED);
+         if (drop)
+           node->tp_first_run = 0;
 
-          if (dump_file)
-            fprintf (dump_file, "Read tp_first_run: %d\n", node->tp_first_run);
+         if (dump_file)
+           fprintf (dump_file, "Read tp_first_run: %d%s\n", node->tp_first_run,
+                    drop ? "; ignored because profile reproducibility is "
+                    "multi-threaded" : "");
         }
     }
 
@@ -867,6 +956,8 @@ struct location_triplet_hash : typed_noop_remove <location_triplet>
     ref.lineno = -1;
   }
 
+  static const bool empty_zero_p = false;
+
   static void
   mark_empty (location_triplet &ref)
   {
@@ -1211,6 +1302,11 @@ branch_prob (bool thunk)
   if (dump_file)
     fprintf (dump_file, "%d instrumentation edges\n", num_instrumented);
 
+  /* Dump function body before it's instrumented.
+     It helps to debug gcov tool.  */
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    dump_function_to_file (cfun->decl, dump_file, dump_flags);
+
   /* Compute two different checksums. Note that we want to compute
      the checksum in only once place, since it depends on the shape
      of the control flow which can change during 
@@ -1292,7 +1388,7 @@ branch_prob (bool thunk)
              seen_locations.add (loc);
              expanded_location curr_location = expand_location (loc);
              output_location (&streamed_locations, curr_location.file,
-                              curr_location.line, &offset, bb);
+                              MAX (1, curr_location.line), &offset, bb);
            }
 
          for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -1303,7 +1399,7 @@ branch_prob (bool thunk)
                {
                  seen_locations.add (loc);
                  output_location (&streamed_locations, gimple_filename (stmt),
-                                  gimple_lineno (stmt), &offset, bb);
+                                  MAX (1, gimple_lineno (stmt)), &offset, bb);
                }
            }
 
@@ -1318,7 +1414,7 @@ branch_prob (bool thunk)
            {
              expanded_location curr_location = expand_location (loc);
              output_location (&streamed_locations, curr_location.file,
-                              curr_location.line, &offset, bb);
+                              MAX (1, curr_location.line), &offset, bb);
            }
 
          if (offset)
@@ -1370,14 +1466,13 @@ branch_prob (bool thunk)
   if (flag_branch_probabilities
       && (profile_status_for_fn (cfun) == PROFILE_READ))
     {
-      struct 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)
+      for (auto loop : loops_list (cfun, 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);