aboutsummaryrefslogtreecommitdiff
path: root/gcc/predict.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/predict.c')
-rw-r--r--gcc/predict.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/gcc/predict.c b/gcc/predict.c
index 31c5565..396e150 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -3249,3 +3249,99 @@ report_predictor_hitrates (void)
loop_optimizer_finalize ();
}
+/* Force edge E to be cold.
+ If IMPOSSIBLE is true, for edge to have count and probability 0 otherwise
+ keep low probability to represent possible error in a guess. This is used
+ i.e. in case we predict loop to likely iterate given number of times but
+ we are not 100% sure.
+
+ This function locally updates profile without attempt to keep global
+ consistency which can not be reached in full generality without full profile
+ rebuild from probabilities alone. Doing so is not necessarily a good idea
+ because frequencies and counts may be more realistic then probabilities.
+
+ In some cases (such as for elimination of early exits during full loop
+ unrolling) the caller can ensure that profile will get consistent
+ afterwards. */
+
+void
+force_edge_cold (edge e, bool impossible)
+{
+ gcov_type count_sum = 0;
+ int prob_sum = 0;
+ edge_iterator ei;
+ edge e2;
+ gcov_type old_count = e->count;
+ int old_probability = e->probability;
+ gcov_type gcov_scale = REG_BR_PROB_BASE;
+ int prob_scale = REG_BR_PROB_BASE;
+
+ /* If edge is already improbably or cold, just return. */
+ if (e->probability <= impossible ? PROB_VERY_UNLIKELY : 0
+ && (!impossible || !e->count))
+ return;
+ FOR_EACH_EDGE (e2, ei, e->src->succs)
+ if (e2 != e)
+ {
+ count_sum += e2->count;
+ prob_sum += e2->probability;
+ }
+
+ /* If there are other edges out of e->src, redistribute probabilitity
+ there. */
+ if (prob_sum)
+ {
+ e->probability
+ = MIN (e->probability, impossible ? 0 : PROB_VERY_UNLIKELY);
+ if (old_probability)
+ e->count = RDIV (e->count * e->probability, old_probability);
+ else
+ e->count = MIN (e->count, impossible ? 0 : 1);
+
+ if (count_sum)
+ gcov_scale = RDIV ((count_sum + old_count - e->count) * REG_BR_PROB_BASE,
+ count_sum);
+ prob_scale = RDIV ((REG_BR_PROB_BASE - e->probability) * REG_BR_PROB_BASE,
+ prob_sum);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Making edge %i->%i %s by redistributing "
+ "probability to other edges.\n",
+ e->src->index, e->dest->index,
+ impossible ? "imposisble" : "cold");
+ FOR_EACH_EDGE (e2, ei, e->src->succs)
+ if (e2 != e)
+ {
+ e2->count = RDIV (e2->count * gcov_scale, REG_BR_PROB_BASE);
+ e2->probability = RDIV (e2->probability * prob_scale,
+ REG_BR_PROB_BASE);
+ }
+ }
+ /* If all edges out of e->src are unlikely, the basic block itself
+ is unlikely. */
+ else
+ {
+ e->probability = REG_BR_PROB_BASE;
+
+ /* If we did not adjusting, the source basic block has no likely edeges
+ leaving other direction. In that case force that bb cold, too.
+ This in general is difficult task to do, but handle special case when
+ BB has only one predecestor. This is common case when we are updating
+ after loop transforms. */
+ if (!prob_sum && !count_sum && single_pred_p (e->src)
+ && e->src->frequency > (impossible ? 0 : 1))
+ {
+ int old_frequency = e->src->frequency;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Making bb %i %s.\n", e->src->index,
+ impossible ? "imposisble" : "cold");
+ e->src->frequency = MIN (e->src->frequency, impossible ? 0 : 1);
+ e->src->count = e->count = RDIV (e->src->count * e->src->frequency,
+ old_frequency);
+ force_edge_cold (single_pred_edge (e->src), impossible);
+ }
+ else if (dump_file && (dump_flags & TDF_DETAILS)
+ && maybe_hot_bb_p (cfun, e->src))
+ fprintf (dump_file, "Giving up on making bb %i %s.\n", e->src->index,
+ impossible ? "imposisble" : "cold");
+ }
+}