diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 269694c7962..22293e1c237 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -407,6 +407,7 @@ gcov_type expected_loop_iterations_unbounded (const class loop *, extern bool expected_loop_iterations_by_profile (const class loop *loop, sreal *ret, bool *reliable = NULL); +extern bool maybe_flat_loop_profile (const class loop *); extern unsigned expected_loop_iterations (class loop *); extern rtx doloop_condition_get (rtx_insn *); diff --git a/gcc/cfgloopanal.cc b/gcc/cfgloopanal.cc index c86a537f024..d8923b27e5d 100644 --- a/gcc/cfgloopanal.cc +++ b/gcc/cfgloopanal.cc @@ -303,6 +303,67 @@ expected_loop_iterations_by_profile (const class loop *loop, sreal *ret, return true; } +/* Return true if loop CFG profile may be unrealistically flat. + This is a common case, since average loops iterate only about 5 times. + In the case we do not have profile feedback or do not know real number of + iterations during profile estimation, we are likely going to predict it with + similar low iteration count. For static loop profiles we also artificially + cap profile of loops with known large iteration count so they do not appear + significantly more hot than other loops with unknown iteration counts. + + For loop optimization heuristics we ignore CFG profile and instead + use get_estimated_loop_iterations API which returns estimate + only when it is realistic. For unknown counts some optimizations, + like vectorizer or unroller make guess that iteration count will + be large. In this case we need to avoid scaling down the profile + after the loop transform. */ + +bool +maybe_flat_loop_profile (const class loop *loop) +{ + bool reliable; + sreal ret; + + if (!expected_loop_iterations_by_profile (loop, &ret, &reliable)) + return true; + + /* Reliable CFG estimates ought never be flat. Sanity check with + nb_iterations_estimate. If those differ, it is a but in profile + updating code */ + if (reliable) + { + int64_t intret = ret.to_nearest_int (); + if (loop->any_estimate + && (wi::ltu_p (intret * 2, loop->nb_iterations_estimate) + || wi::gtu_p (intret, loop->nb_iterations_estimate * 2))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + "Loop %i has inconsistent iterations estimates: " + "reliable CFG based iteration estimate is %f " + "while nb_iterations_estimate is %i\n", + loop->num, + ret.to_double (), + (int)loop->nb_iterations_estimate.to_shwi ()); + return true; + } + return false; + } + + /* Allow some margin of error and see if we are close to known bounds. + sreal (9,-3) is 9/8 */ + int64_t intret = (ret * sreal (9, -3)).to_nearest_int (); + if (loop->any_upper_bound && wi::geu_p (intret, loop->nb_iterations_upper_bound)) + return false; + if (loop->any_likely_upper_bound + && wi::geu_p (intret, loop->nb_iterations_likely_upper_bound)) + return false; + if (loop->any_estimate + && wi::geu_p (intret, loop->nb_iterations_estimate)) + return false; + return true; +} + /* Returns expected number of iterations of LOOP, according to measured or guessed profile. diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index a6c97a04662..c65af8cc800 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -8523,8 +8523,11 @@ print_loop_info (FILE *file, const class loop *loop, const char *prefix) bool reliable; sreal iterations; if (loop->num && expected_loop_iterations_by_profile (loop, &iterations, &reliable)) - fprintf (file, "\n%siterations by profile: %f %s", prefix, - iterations.to_double (), reliable ? "(reliable)" : "(unreliable)"); + { + fprintf (file, "\n%siterations by profile: %f (%s%s)", prefix, + iterations.to_double (), reliable ? "reliable" : "unreliable", + maybe_flat_loop_profile (loop) ? ", maybe flat" : ""); + } }