Mercurial > hg > CbC > CbC_gcc
diff gcc/profile-count.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/profile-count.c Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/profile-count.c Thu Oct 25 07:37:49 2018 +0900 @@ -1,5 +1,5 @@ /* Profile counter container type. - Copyright (C) 2017 Free Software Foundation, Inc. + Copyright (C) 2017-2018 Free Software Foundation, Inc. Contributed by Jan Hubicka This file is part of GCC. @@ -25,12 +25,41 @@ #include "options.h" #include "tree.h" #include "basic-block.h" +#include "function.h" #include "cfg.h" -#include "function.h" #include "gimple.h" #include "data-streamer.h" #include "cgraph.h" #include "wide-int.h" +#include "sreal.h" + +/* 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"; + } +} /* Dump THIS to F. */ @@ -42,7 +71,13 @@ else { fprintf (f, "%" PRId64, m_val); - if (m_quality == profile_adjusted) + 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)"); @@ -65,6 +100,7 @@ bool profile_count::differs_from_p (profile_count other) const { + gcc_checking_assert (compatible_p (other)); if (!initialized_p () || !other.initialized_p ()) return false; if ((uint64_t)m_val - (uint64_t)other.m_val < 100 @@ -202,7 +238,7 @@ slow_safe_scale_64bit (uint64_t a, uint64_t b, uint64_t c, uint64_t *res) { FIXED_WIDE_INT (128) tmp = a; - bool overflow; + wi::overflow_type overflow; tmp = wi::udiv_floor (wi::umul (tmp, b, &overflow) + (c / 2), c); gcc_checking_assert (!overflow); if (wi::fits_uhwi_p (tmp)) @@ -213,3 +249,153 @@ *res = (uint64_t) -1; return false; } + +/* Return count as frequency within FUN scaled in range 0 to REG_FREQ_MAX + Used for legacy code and should not be used anymore. */ + +int +profile_count::to_frequency (struct function *fun) const +{ + if (!initialized_p ()) + return BB_FREQ_MAX; + if (*this == profile_count::zero ()) + return 0; + gcc_assert (REG_BR_PROB_BASE == BB_FREQ_MAX + && fun->cfg->count_max.initialized_p ()); + profile_probability prob = probability_in (fun->cfg->count_max); + if (!prob.initialized_p ()) + return REG_BR_PROB_BASE; + return prob.to_reg_br_prob_base (); +} + +/* Return count as frequency within FUN scaled in range 0 to CGRAPH_FREQ_MAX + where CGRAPH_FREQ_BASE means that count equals to entry block count. + Used for legacy code and should not be used anymore. */ + +int +profile_count::to_cgraph_frequency (profile_count entry_bb_count) const +{ + if (!initialized_p () || !entry_bb_count.initialized_p ()) + return CGRAPH_FREQ_BASE; + if (*this == profile_count::zero ()) + return 0; + gcc_checking_assert (entry_bb_count.initialized_p ()); + uint64_t scale; + 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; + return MIN (scale, CGRAPH_FREQ_MAX); +} + +/* Return THIS/IN as sreal value. */ + +sreal +profile_count::to_sreal_scale (profile_count in, bool *known) const +{ + if (!initialized_p () || !in.initialized_p ()) + { + if (known) + *known = false; + return 1; + } + if (known) + *known = true; + if (*this == profile_count::zero ()) + return 0; + + if (!in.m_val) + { + if (!m_val) + return 1; + return m_val * 4; + } + return (sreal)m_val / (sreal)in.m_val; +} + +/* We want to scale profile across function boundary from NUM to DEN. + Take care of the side case when DEN is zeros. We still want to behave + sanely here which means + - scale to profile_count::zero () if NUM is profile_count::zero + - do not affect anything if NUM == DEN + - preserve counter value but adjust quality in other cases. */ + +void +profile_count::adjust_for_ipa_scaling (profile_count *num, + profile_count *den) +{ + /* Scaling is no-op if NUM and DEN are the same. */ + if (*num == *den) + return; + /* Scaling to zero is always zero. */ + if (*num == profile_count::zero ()) + return; + /* If den is non-zero we are safe. */ + if (den->force_nonzero () == *den) + return; + /* Force both to non-zero so we do not push profiles to 0 when + both num == 0 and den == 0. */ + *den = den->force_nonzero (); + *num = num->force_nonzero (); +} + +/* THIS is a count of bb which is known to be executed IPA times. + Combine this information into bb counter. This means returning IPA + 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) +{ + ipa = ipa.ipa (); + if (ipa.nonzero_p ()) + return ipa; + if (!ipa.initialized_p () || *this == profile_count::zero ()) + return *this; + if (ipa == profile_count::zero ()) + return this->global0 (); + return this->global0adjusted (); +} + +/* 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 ret; + gcc_checking_assert (v >= 0); + if (dump_file && v >= (gcov_type)max_count) + fprintf (dump_file, + "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; + return ret; + } + + +/* COUNT1 times event happens with *THIS probability, COUNT2 times OTHER + happens with COUNT2 probablity. Return probablity that either *THIS or + OTHER happens. */ + +profile_probability +profile_probability::combine_with_count (profile_count count1, + profile_probability other, + profile_count count2) const +{ + /* 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. */ + if (*this == other || count1 == count2 + || (count2 == profile_count::zero () + && !(count1 == profile_count::zero ()))) + return *this; + if (count1 == profile_count::zero () && !(count2 == profile_count::zero ())) + return other; + else if (count1.nonzero_p () || count2.nonzero_p ()) + return *this * count1.probability_in (count1 + count2) + + other * count2.probability_in (count1 + count2); + else + return *this * profile_probability::even () + + other * profile_probability::even (); +}