Commit 65739a68 by Jan Hubicka Committed by Jan Hubicka

re PR tree-optimization/82965 (gcc.dg/vect/pr79347.c starts failing after r254379)

	PR tree-optimization/82965
	PR tree-optimization/83991
	* cfgloopanal.c (expected_loop_iterations_unbounded): Add
	by_profile_only parameter.
	* cfgloopmanip.c (scale_loop_profile): Further scale loop's profile
        information if the loop was predicted to iterate too many times.
	* cfgloop.h (expected_loop_iterations_unbounded): Update prototype

Co-Authored-By: Bin Cheng <bin.cheng@arm.com>

From-SVN: r259368
parent 2fdb5a23
2018-04-13 Jan Hubicka <hubicka@ucw.cz> 2018-04-13 Jan Hubicka <hubicka@ucw.cz>
Bin Cheng <bin.cheng@arm.com>
PR tree-optimization/82965
PR tree-optimization/83991
* cfgloopanal.c (expected_loop_iterations_unbounded): Add
by_profile_only parameter.
* cfgloopmanip.c (scale_loop_profile): Further scale loop's profile
information if the loop was predicted to iterate too many times.
* cfgloop.h (expected_loop_iterations_unbounded): Update prototype
2018-04-13 Jan Hubicka <hubicka@ucw.cz>
PR lto/71991 PR lto/71991
* config/i386/i386.c (ix86_can_inline_p): Allow safe transitions for * config/i386/i386.c (ix86_can_inline_p): Allow safe transitions for
......
...@@ -388,7 +388,7 @@ extern void verify_loop_structure (void); ...@@ -388,7 +388,7 @@ extern void verify_loop_structure (void);
/* Loop analysis. */ /* Loop analysis. */
extern bool just_once_each_iteration_p (const struct loop *, const_basic_block); extern bool just_once_each_iteration_p (const struct loop *, const_basic_block);
gcov_type expected_loop_iterations_unbounded (const struct loop *, gcov_type expected_loop_iterations_unbounded (const struct loop *,
bool *read_profile_p = NULL); bool *read_profile_p = NULL, bool by_profile_only = false);
extern unsigned expected_loop_iterations (struct loop *); extern unsigned expected_loop_iterations (struct loop *);
extern rtx doloop_condition_get (rtx_insn *); extern rtx doloop_condition_get (rtx_insn *);
......
...@@ -230,12 +230,17 @@ average_num_loop_insns (const struct loop *loop) ...@@ -230,12 +230,17 @@ average_num_loop_insns (const struct loop *loop)
} }
/* Returns expected number of iterations of LOOP, according to /* Returns expected number of iterations of LOOP, according to
measured or guessed profile. No bounding is done on the measured or guessed profile.
value. */
This functions attempts to return "sane" value even if profile
information is not good enough to derive osmething.
If BY_PROFILE_ONLY is set, this logic is bypassed and function
return -1 in those scenarios. */
gcov_type gcov_type
expected_loop_iterations_unbounded (const struct loop *loop, expected_loop_iterations_unbounded (const struct loop *loop,
bool *read_profile_p) bool *read_profile_p,
bool by_profile_only)
{ {
edge e; edge e;
edge_iterator ei; edge_iterator ei;
...@@ -246,7 +251,11 @@ expected_loop_iterations_unbounded (const struct loop *loop, ...@@ -246,7 +251,11 @@ expected_loop_iterations_unbounded (const struct loop *loop,
/* If we have no profile at all, use AVG_LOOP_NITER. */ /* If we have no profile at all, use AVG_LOOP_NITER. */
if (profile_status_for_fn (cfun) == PROFILE_ABSENT) if (profile_status_for_fn (cfun) == PROFILE_ABSENT)
{
if (by_profile_only)
return -1;
expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER); expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
}
else if (loop->latch && (loop->latch->count.initialized_p () else if (loop->latch && (loop->latch->count.initialized_p ()
|| loop->header->count.initialized_p ())) || loop->header->count.initialized_p ()))
{ {
...@@ -260,9 +269,17 @@ expected_loop_iterations_unbounded (const struct loop *loop, ...@@ -260,9 +269,17 @@ expected_loop_iterations_unbounded (const struct loop *loop,
count_in += e->count (); count_in += e->count ();
if (!count_latch.initialized_p ()) if (!count_latch.initialized_p ())
{
if (by_profile_only)
return -1;
expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER); expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
}
else if (!count_in.nonzero_p ()) else if (!count_in.nonzero_p ())
{
if (by_profile_only)
return -1;
expected = count_latch.to_gcov_type () * 2; expected = count_latch.to_gcov_type () * 2;
}
else else
{ {
expected = (count_latch.to_gcov_type () + count_in.to_gcov_type () expected = (count_latch.to_gcov_type () + count_in.to_gcov_type ()
...@@ -273,11 +290,18 @@ expected_loop_iterations_unbounded (const struct loop *loop, ...@@ -273,11 +290,18 @@ expected_loop_iterations_unbounded (const struct loop *loop,
} }
} }
else else
{
if (by_profile_only)
return -1;
expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER); expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
}
if (!by_profile_only)
{
HOST_WIDE_INT max = get_max_loop_iterations_int (loop); HOST_WIDE_INT max = get_max_loop_iterations_int (loop);
if (max != -1 && max < expected) if (max != -1 && max < expected)
return max; return max;
}
return expected; return expected;
} }
......
...@@ -502,14 +502,17 @@ scale_loop_frequencies (struct loop *loop, profile_probability p) ...@@ -502,14 +502,17 @@ scale_loop_frequencies (struct loop *loop, profile_probability p)
/* Scale profile in LOOP by P. /* Scale profile in LOOP by P.
If ITERATION_BOUND is non-zero, scale even further if loop is predicted If ITERATION_BOUND is non-zero, scale even further if loop is predicted
to iterate too many times. */ to iterate too many times.
Before caling this function, preheader block profile should be already
scaled to final count. This is necessary because loop iterations are
determined by comparing header edge count to latch ege count and thus
they need to be scaled synchronously. */
void void
scale_loop_profile (struct loop *loop, profile_probability p, scale_loop_profile (struct loop *loop, profile_probability p,
gcov_type iteration_bound) gcov_type iteration_bound)
{ {
gcov_type iterations = expected_loop_iterations_unbounded (loop); edge e, preheader_e;
edge e;
edge_iterator ei; edge_iterator ei;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
...@@ -517,27 +520,44 @@ scale_loop_profile (struct loop *loop, profile_probability p, ...@@ -517,27 +520,44 @@ scale_loop_profile (struct loop *loop, profile_probability p,
fprintf (dump_file, ";; Scaling loop %i with scale ", fprintf (dump_file, ";; Scaling loop %i with scale ",
loop->num); loop->num);
p.dump (dump_file); p.dump (dump_file);
fprintf (dump_file, " bounding iterations to %i from guessed %i\n", fprintf (dump_file, " bounding iterations to %i\n",
(int)iteration_bound, (int)iterations); (int)iteration_bound);
}
/* Scale the probabilities. */
scale_loop_frequencies (loop, p);
if (iteration_bound == 0)
return;
gcov_type iterations = expected_loop_iterations_unbounded (loop, NULL, true);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, ";; guessed iterations after scaling %i\n",
(int)iterations);
} }
/* See if loop is predicted to iterate too many times. */ /* See if loop is predicted to iterate too many times. */
if (iteration_bound && iterations > 0 if (iterations <= iteration_bound)
&& p.apply (iterations) > iteration_bound) return;
preheader_e = loop_preheader_edge (loop);
/* We could handle also loops without preheaders, but bounding is
currently used only by optimizers that have preheaders constructed. */
gcc_checking_assert (preheader_e);
profile_count count_in = preheader_e->count ();
if (count_in > profile_count::zero ()
&& loop->header->count.initialized_p ())
{ {
/* Fixing loop profile for different trip count is not trivial; the exit profile_count count_delta = profile_count::zero ();
probabilities has to be updated to match and frequencies propagated down
to the loop body.
We fully update only the simple case of loop with single exit that is
either from the latch or BB just before latch and leads from BB with
simple conditional jump. This is OK for use in vectorizer. */
e = single_exit (loop); e = single_exit (loop);
if (e) if (e)
{ {
edge other_e; edge other_e;
profile_count count_delta;
FOR_EACH_EDGE (other_e, ei, e->src->succs) FOR_EACH_EDGE (other_e, ei, e->src->succs)
if (!(other_e->flags & (EDGE_ABNORMAL | EDGE_FAKE)) if (!(other_e->flags & (EDGE_ABNORMAL | EDGE_FAKE))
&& e != other_e) && e != other_e)
...@@ -548,50 +568,52 @@ scale_loop_profile (struct loop *loop, profile_probability p, ...@@ -548,50 +568,52 @@ scale_loop_profile (struct loop *loop, profile_probability p,
e->probability = profile_probability::always () e->probability = profile_probability::always ()
.apply_scale (1, iteration_bound); .apply_scale (1, iteration_bound);
other_e->probability = e->probability.invert (); other_e->probability = e->probability.invert ();
count_delta -= e->count ();
/* If latch exists, change its count, since we changed /* In code below we only handle the following two updates. */
probability of exit. Theoretically we should update everything from if (other_e->dest != loop->header
source of exit edge to latch, but for vectorizer this is enough. */ && other_e->dest != loop->latch
if (loop->latch && (dump_file && (dump_flags & TDF_DETAILS)))
&& loop->latch != e->src)
{ {
loop->latch->count += count_delta; fprintf (dump_file, ";; giving up on update of paths from "
"exit condition to latch\n");
} }
} }
else
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ";; Loop has multiple exit edges; "
"giving up on exit condition update\n");
/* Roughly speaking we want to reduce the loop body profile by the /* Roughly speaking we want to reduce the loop body profile by the
difference of loop iterations. We however can do better if difference of loop iterations. We however can do better if
we look at the actual profile, if it is available. */ we look at the actual profile, if it is available. */
p = p.apply_scale (iteration_bound, iterations); p = profile_probability::always ();
if (loop->header->count.initialized_p ()) count_in = count_in.apply_scale (iteration_bound, 1);
{ p = count_in.probability_in (loop->header->count);
profile_count count_in = profile_count::zero ();
FOR_EACH_EDGE (e, ei, loop->header->preds)
if (e->src != loop->latch)
count_in += e->count ();
if (count_in > profile_count::zero () )
{
p = count_in.probability_in (loop->header->count.apply_scale
(iteration_bound, 1));
}
}
if (!(p > profile_probability::never ())) if (!(p > profile_probability::never ()))
p = profile_probability::very_unlikely (); p = profile_probability::very_unlikely ();
}
if (p >= profile_probability::always () if (p == profile_probability::always ()
|| !p.initialized_p ()) || !p.initialized_p ())
return; return;
/* Scale the actual probabilities. */ /* If latch exists, change its count, since we changed
probability of exit. Theoretically we should update everything from
source of exit edge to latch, but for vectorizer this is enough. */
if (loop->latch && loop->latch != e->src)
loop->latch->count += count_delta;
/* Scale the probabilities. */
scale_loop_frequencies (loop, p); scale_loop_frequencies (loop, p);
/* Change latch's count back. */
if (loop->latch && loop->latch != e->src)
loop->latch->count -= count_delta;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ";; guessed iterations are now %i\n", fprintf (dump_file, ";; guessed iterations are now %i\n",
(int)expected_loop_iterations_unbounded (loop)); (int)expected_loop_iterations_unbounded (loop, NULL, true));
}
} }
/* Recompute dominance information for basic blocks outside LOOP. */ /* Recompute dominance information for basic blocks outside LOOP. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment