diff gcc/profile-count.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/profile-count.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/profile-count.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* Profile counter container type.
-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+   Copyright (C) 2017-2020 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -33,34 +33,57 @@
 #include "wide-int.h"
 #include "sreal.h"
 
+/* Names from profile_quality enum values.  */
+
+const char *profile_quality_names[] =
+{
+  "uninitialized",
+  "guessed_local",
+  "guessed_global0",
+  "guessed_global0adjusted",
+  "guessed",
+  "afdo",
+  "adjusted",
+  "precise"
+};
+
 /* Get a string describing QUALITY.  */
 
 const char *
 profile_quality_as_string (enum profile_quality quality)
 {
-  switch (quality)
-    {
-    default:
-      gcc_unreachable ();
-    case profile_uninitialized:
-      return "uninitialized";
-    case profile_guessed_local:
-      return "guessed_local";
-    case profile_guessed_global0:
-      return "guessed_global0";
-    case profile_guessed_global0adjusted:
-      return "guessed_global0adjusted";
-    case profile_guessed:
-      return "guessed";
-    case profile_afdo:
-      return "afdo";
-    case profile_adjusted:
-      return "adjusted";
-    case profile_precise:
-      return "precise";
-    }
+  return profile_quality_names[quality];
 }
 
+/* Parse VALUE as profile quality and return true when a valid QUALITY.  */
+
+bool
+parse_profile_quality (const char *value, profile_quality *quality)
+{
+  for (unsigned i = 0; i < ARRAY_SIZE (profile_quality_names); i++)
+    if (strcmp (profile_quality_names[i], value) == 0)
+      {
+	*quality = (profile_quality)i;
+	return true;
+      }
+
+  return false;
+}
+
+/* Display names from profile_quality enum values.  */
+
+const char *profile_quality_display_names[] =
+{
+  NULL,
+  "estimated locally",
+  "estimated locally, globally 0",
+  "estimated locally, globally 0 adjusted",
+  "guessed",
+  "auto FDO",
+  "adjusted",
+  "precise"
+};
+
 /* Dump THIS to F.  */
 
 void
@@ -69,21 +92,8 @@
   if (!initialized_p ())
     fprintf (f, "uninitialized");
   else
-    {
-      fprintf (f, "%" PRId64, m_val);
-      if (m_quality == profile_guessed_local)
-	fprintf (f, " (estimated locally)");
-      else if (m_quality == profile_guessed_global0)
-	fprintf (f, " (estimated locally, globally 0)");
-      else if (m_quality == profile_guessed_global0adjusted)
-	fprintf (f, " (estimated locally, globally 0 adjusted)");
-      else if (m_quality == profile_adjusted)
-	fprintf (f, " (adjusted)");
-      else if (m_quality == profile_afdo)
-	fprintf (f, " (auto FDO)");
-      else if (m_quality == profile_guessed)
-	fprintf (f, " (guessed)");
-    }
+    fprintf (f, "%" PRId64 " (%s)", m_val,
+	     profile_quality_display_names[m_quality]);
 }
 
 /* Dump THIS to stderr.  */
@@ -95,7 +105,7 @@
   fprintf (stderr, "\n");
 }
 
-/* Return true if THIS differs from OTHER; tolerate small diferences.  */
+/* Return true if THIS differs from OTHER; tolerate small differences.  */
 
 bool
 profile_count::differs_from_p (profile_count other) const
@@ -115,7 +125,7 @@
 /* Stream THIS from IB.  */
 
 profile_count
-profile_count::stream_in (struct lto_input_block *ib)
+profile_count::stream_in (class lto_input_block *ib)
 {
   profile_count ret;
   ret.m_val = streamer_read_gcov_count (ib);
@@ -158,11 +168,11 @@
         fprintf (f, "always");
       else
         fprintf (f, "%3.1f%%", (double)m_val * 100 / max_probability);
-      if (m_quality == profile_adjusted)
+      if (m_quality == ADJUSTED)
 	fprintf (f, " (adjusted)");
-      else if (m_quality == profile_afdo)
+      else if (m_quality == AFDO)
 	fprintf (f, " (auto FDO)");
-      else if (m_quality == profile_guessed)
+      else if (m_quality == GUESSED)
 	fprintf (f, " (guessed)");
     }
 }
@@ -176,7 +186,7 @@
   fprintf (stderr, "\n");
 }
 
-/* Return true if THIS differs from OTHER; tolerate small diferences.  */
+/* Return true if THIS differs from OTHER; tolerate small differences.  */
 
 bool
 profile_probability::differs_from_p (profile_probability other) const
@@ -206,7 +216,7 @@
 /* Stream THIS from IB.  */
 
 profile_probability
-profile_probability::stream_in (struct lto_input_block *ib)
+profile_probability::stream_in (class lto_input_block *ib)
 {
   profile_probability ret;
   ret.m_val = streamer_read_uhwi (ib);
@@ -258,7 +268,7 @@
 {
   if (!initialized_p ())
     return BB_FREQ_MAX;
-  if (*this == profile_count::zero ())
+  if (*this == zero ())
     return 0;
   gcc_assert (REG_BR_PROB_BASE == BB_FREQ_MAX
 	      && fun->cfg->count_max.initialized_p ());
@@ -277,10 +287,11 @@
 {
   if (!initialized_p () || !entry_bb_count.initialized_p ())
     return CGRAPH_FREQ_BASE;
-  if (*this == profile_count::zero ())
+  if (*this == zero ())
     return 0;
   gcc_checking_assert (entry_bb_count.initialized_p ());
   uint64_t scale;
+  gcc_checking_assert (compatible_p (entry_bb_count));
   if (!safe_scale_64bit (!entry_bb_count.m_val ? m_val + 1 : m_val,
 			 CGRAPH_FREQ_BASE, MAX (1, entry_bb_count.m_val), &scale))
     return CGRAPH_FREQ_MAX;
@@ -300,8 +311,25 @@
     }
   if (known)
     *known = true;
-  if (*this == profile_count::zero ())
+  /* Watch for cases where one count is IPA and other is not.  */
+  if (in.ipa ().initialized_p ())
+    {
+      gcc_checking_assert (ipa ().initialized_p ());
+      /* If current count is inter-procedurally 0 and IN is inter-procedurally
+	 non-zero, return 0.  */
+      if (in.ipa ().nonzero_p ()
+	  && !ipa().nonzero_p ())
+	return 0;
+    }
+  else 
+    /* We can handle correctly 0 IPA count within locally estimated
+       profile, but otherwise we are lost and this should not happen.   */
+    gcc_checking_assert (!ipa ().initialized_p () || !ipa ().nonzero_p ());
+  if (*this == zero ())
     return 0;
+  if (m_val == in.m_val)
+    return 1;
+  gcc_checking_assert (compatible_p (in));
 
   if (!in.m_val)
     {
@@ -327,7 +355,7 @@
   if (*num == *den)
     return;
   /* Scaling to zero is always zero.  */
-  if (*num == profile_count::zero ())
+  if (*num == zero ())
     return;
   /* If den is non-zero we are safe.  */
   if (den->force_nonzero () == *den)
@@ -343,24 +371,45 @@
    if it is nonzero, not changing anything if IPA is uninitialized
    and if IPA is zero, turning THIS into corresponding local profile with
    global0.  */
+
 profile_count
 profile_count::combine_with_ipa_count (profile_count ipa)
 {
+  if (!initialized_p ())
+    return *this;
   ipa = ipa.ipa ();
   if (ipa.nonzero_p ())
     return ipa;
-  if (!ipa.initialized_p () || *this == profile_count::zero ())
+  if (!ipa.initialized_p () || *this == zero ())
     return *this;
-  if (ipa == profile_count::zero ())
+  if (ipa == zero ())
     return this->global0 ();
   return this->global0adjusted ();
 }
 
+/* Sae as profile_count::combine_with_ipa_count but within function with count
+   IPA2.  */
+profile_count
+profile_count::combine_with_ipa_count_within (profile_count ipa,
+					      profile_count ipa2)
+{
+  profile_count ret;
+  if (!initialized_p ())
+    return *this;
+  if (ipa2.ipa () == ipa2 && ipa.initialized_p ())
+    ret = ipa;
+  else
+    ret = combine_with_ipa_count (ipa);
+  gcc_checking_assert (ret.compatible_p (ipa2));
+  return ret;
+}
+
 /* The profiling runtime uses gcov_type, which is usually 64bit integer.
    Conversions back and forth are used to read the coverage and get it
    into internal representation.  */
+
 profile_count
-profile_count::from_gcov_type (gcov_type v)
+profile_count::from_gcov_type (gcov_type v, profile_quality quality)
   {
     profile_count ret;
     gcc_checking_assert (v >= 0);
@@ -369,13 +418,12 @@
 	       "Capping gcov count %" PRId64 " to max_count %" PRId64 "\n",
 	       (int64_t) v, (int64_t) max_count);
     ret.m_val = MIN (v, (gcov_type)max_count);
-    ret.m_quality = profile_precise;
+    ret.m_quality = quality;
     return ret;
   }
 
-
 /* COUNT1 times event happens with *THIS probability, COUNT2 times OTHER
-   happens with COUNT2 probablity. Return probablity that either *THIS or
+   happens with COUNT2 probability.  Return probability that either *THIS or
    OTHER happens.  */
 
 profile_probability
@@ -385,7 +433,7 @@
 {
   /* If probabilities are same, we are done.
      If counts are nonzero we can distribute accordingly. In remaining
-     cases just avreage the values and hope for the best.  */
+     cases just average the values and hope for the best.  */
   if (*this == other || count1 == count2
       || (count2 == profile_count::zero ()
 	  && !(count1 == profile_count::zero ())))
@@ -396,6 +444,14 @@
     return *this * count1.probability_in (count1 + count2)
 	   + other * count2.probability_in (count1 + count2);
   else
-    return *this * profile_probability::even ()
-	   + other * profile_probability::even ();
+    return *this * even () + other * even ();
 }
+
+/* Return probability as sreal in range [0, 1].  */
+
+sreal
+profile_probability::to_sreal () const
+{
+  gcc_checking_assert (initialized_p ());
+  return ((sreal)m_val) >> (n_bits - 2);
+}