https://gcc.gnu.org/g:17f7b6250628c31182fd4f71c9ecdeca9568ffd1
commit r16-930-g17f7b6250628c31182fd4f71c9ecdeca9568ffd1 Author: Jan Hubicka <hubi...@ucw.cz> Date: Wed May 28 14:26:11 2025 +0200 Handle auto-fdo 0 more carefully This patch fixes few other places where auto-fdo 0 should be be treated as actual 0 (i.e. probably never executed). Overall I think we should end up combining static profile with auto-fdo profile where auto-fdo has 0 counts, but that is something that should be benchmarked and first it is neccessary to get something benchmarkeable out of auto-FDO. gcc/ChangeLog: * cgraph.cc (cgraph_edge::maybe_hot_p): For auto-fdo turn 0 to non-zero. * ipa-cp.cc (cs_interesting_for_ipcp_p): Do not trust auto-fdo 0. * profile-count.cc (profile_count::adjust_for_ipa_scaling): Likewise. (profile_count::from_gcov_type): Fix formating. Diff: --- gcc/cgraph.cc | 9 ++++++++- gcc/ipa-cp.cc | 8 ++++++-- gcc/profile-count.cc | 30 +++++++++++++++++------------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc index ac0f2519361b..3f95ca1fa85c 100644 --- a/gcc/cgraph.cc +++ b/gcc/cgraph.cc @@ -3019,7 +3019,14 @@ cgraph_edge::maybe_hot_p (sreal scale) /* Use IPA count and if it s not available appy local heuristics. */ if (c.initialized_p ()) - return maybe_hot_count_p (NULL, c * scale); + { + /* A special case; AFDO zero means that function may quite possibly + be executed few times per execution. If scale is large, we still + want to consider the call hot. */ + if (c.quality () == AFDO) + c = c.force_nonzero (); + return maybe_hot_count_p (NULL, c * scale); + } if (!count.initialized_p ()) return true; cgraph_node *where = caller->inlined_to ? caller->inlined_to : caller; diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index f06ac46dfffb..73cf9040fad7 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -544,8 +544,12 @@ cs_interesting_for_ipcp_p (cgraph_edge *e) if (e->count.ipa ().nonzero_p ()) return true; /* If local (possibly guseed or adjusted 0 profile) claims edge is - not executed, do not propagate. */ - if (e->count.initialized_p () && !e->count.nonzero_p ()) + not executed, do not propagate. + Do not trust AFDO since branch needs to be executed multiple + time to count while we want to propagate even call called + once during the train run if callee is important. */ + if (e->count.initialized_p () && !e->count.nonzero_p () + && e->count.quality () != AFDO) return false; /* If we have zero IPA profile, still consider edge for cloning in case we do partial training. */ diff --git a/gcc/profile-count.cc b/gcc/profile-count.cc index 374f06f4c083..2d9c778b3758 100644 --- a/gcc/profile-count.cc +++ b/gcc/profile-count.cc @@ -364,8 +364,12 @@ profile_count::adjust_for_ipa_scaling (profile_count *num, /* Scaling to zero is always zero. */ if (*num == zero ()) return; - /* If den is non-zero we are safe. */ - if (den->force_nonzero () == *den) + /* If den is non-zero we are safe. + However take care of zeros in AFDO profiles since + they simply means that no useful samples were collected. + Called function still may contain important loop. */ + if (den->force_nonzero () == *den + && num->quality () != AFDO) return; /* Force both to non-zero so we do not push profiles to 0 when both num == 0 and den == 0. */ @@ -417,17 +421,17 @@ profile_count::combine_with_ipa_count_within (profile_count ipa, profile_count profile_count::from_gcov_type (gcov_type v, profile_quality quality) - { - 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 = quality; - return ret; - } +{ + 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 = quality; + return ret; +} /* COUNT1 times event happens with *THIS probability, COUNT2 times OTHER happens with COUNT2 probability. Return probability that either *THIS or