re PR tree-optimization/82965 (gcc.dg/vect/pr79347.c starts failing after r254379)
authorJan Hubicka <hubicka@ucw.cz>
Fri, 13 Apr 2018 08:59:05 +0000 (10:59 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Fri, 13 Apr 2018 08:59:05 +0000 (08:59 +0000)
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

gcc/ChangeLog
gcc/cfgloop.h
gcc/cfgloopanal.c
gcc/cfgloopmanip.c

index bc3a749d7b753c7d0b411e187c4a72bbbccf19ab..d28ab178bb5ac418e37271748548ccc222851b55 100644 (file)
@@ -1,3 +1,14 @@
+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
index ccd2f89b7873281c94e65bf6895c79f01b3d8e44..af9bfabe094c31bfc7393c31a3f1698ae783c38d 100644 (file)
@@ -388,7 +388,7 @@ extern void verify_loop_structure (void);
 /* Loop analysis.  */
 extern bool just_once_each_iteration_p (const struct loop *, const_basic_block);
 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 rtx doloop_condition_get (rtx_insn *);
 
index 9151a33d6f738876584963a2a238d9686d5657df..3af0b2dbe72194abdefd2856822fab6f4d83e4d1 100644 (file)
@@ -230,12 +230,17 @@ average_num_loop_insns (const struct loop *loop)
 }
 
 /* Returns expected number of iterations of LOOP, according to
-   measured or guessed profile.  No bounding is done on the
-   value.  */
+   measured or guessed profile.
+
+   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
 expected_loop_iterations_unbounded (const struct loop *loop,
-                                   bool *read_profile_p)
+                                   bool *read_profile_p,
+                                   bool by_profile_only)
 {
   edge e;
   edge_iterator ei;
@@ -246,7 +251,11 @@ expected_loop_iterations_unbounded (const struct loop *loop,
 
   /* If we have no profile at all, use AVG_LOOP_NITER.  */
   if (profile_status_for_fn (cfun) == PROFILE_ABSENT)
-    expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
+    {
+      if (by_profile_only)
+       return -1;
+      expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
+    }
   else if (loop->latch && (loop->latch->count.initialized_p ()
                           || loop->header->count.initialized_p ()))
     {
@@ -260,9 +269,17 @@ expected_loop_iterations_unbounded (const struct loop *loop,
          count_in += e->count ();
 
       if (!count_latch.initialized_p ())
-       expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
+       {
+          if (by_profile_only)
+           return -1;
+         expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
+       }
       else if (!count_in.nonzero_p ())
-       expected = count_latch.to_gcov_type () * 2;
+       {
+          if (by_profile_only)
+           return -1;
+         expected = count_latch.to_gcov_type () * 2;
+       }
       else
        {
          expected = (count_latch.to_gcov_type () + count_in.to_gcov_type ()
@@ -273,11 +290,18 @@ expected_loop_iterations_unbounded (const struct loop *loop,
        }
     }
   else
-    expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
+    {
+      if (by_profile_only)
+       return -1;
+      expected = PARAM_VALUE (PARAM_AVG_LOOP_NITER);
+    }
 
-  HOST_WIDE_INT max = get_max_loop_iterations_int (loop);
-  if (max != -1 && max < expected)
-    return max;
+  if (!by_profile_only)
+    {
+      HOST_WIDE_INT max = get_max_loop_iterations_int (loop);
+      if (max != -1 && max < expected)
+        return max;
+    }
  
   return expected;
 }
index 27484850fd53e9a35fb6d9413337ac2eac1f8918..74c39dbe8faa812fb3db8072d65c7bb7cdf0f751 100644 (file)
@@ -502,14 +502,17 @@ scale_loop_frequencies (struct loop *loop, profile_probability p)
 
 /* Scale profile in LOOP by P.
    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
 scale_loop_profile (struct loop *loop, profile_probability p,
                    gcov_type iteration_bound)
 {
-  gcov_type iterations = expected_loop_iterations_unbounded (loop);
-  edge e;
+  edge e, preheader_e;
   edge_iterator ei;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -517,28 +520,45 @@ scale_loop_profile (struct loop *loop, profile_probability p,
       fprintf (dump_file, ";; Scaling loop %i with scale ",
               loop->num);
       p.dump (dump_file);
-      fprintf (dump_file, " bounding iterations to %i from guessed %i\n",
-              (int)iteration_bound, (int)iterations);
+      fprintf (dump_file, " bounding iterations to %i\n",
+              (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.  */
-  if (iteration_bound && iterations > 0
-      && p.apply (iterations) > iteration_bound)
+  if (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
-        probabilities has to be updated to match and frequencies propagated down
-        to the loop body.
+      profile_count count_delta = profile_count::zero ();
 
-        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);
       if (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))
                && e != other_e)
              break;
@@ -546,52 +566,54 @@ scale_loop_profile (struct loop *loop, profile_probability p,
          /* Probability of exit must be 1/iterations.  */
          count_delta = e->count ();
          e->probability = profile_probability::always ()
-                               .apply_scale (1, iteration_bound);
+                                   .apply_scale (1, iteration_bound);
          other_e->probability = e->probability.invert ();
-         count_delta -= e->count ();
 
-         /* 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)
+         /* In code below we only handle the following two updates.  */
+         if (other_e->dest != loop->header
+             && other_e->dest != loop->latch
+             && (dump_file && (dump_flags & TDF_DETAILS)))
            {
-             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
         difference of loop iterations.  We however can do better if
         we look at the actual profile, if it is available.  */
-      p = p.apply_scale (iteration_bound, iterations);
-
-      if (loop->header->count.initialized_p ())
-       {
-         profile_count count_in = profile_count::zero ();
-
-         FOR_EACH_EDGE (e, ei, loop->header->preds)
-           if (e->src != loop->latch)
-             count_in += e->count ();
+      p = profile_probability::always ();
 
-         if (count_in > profile_count::zero () )
-           {
-             p = count_in.probability_in (loop->header->count.apply_scale
-                                                (iteration_bound, 1));
-           }
-       }
+      count_in = count_in.apply_scale (iteration_bound, 1);
+      p = count_in.probability_in (loop->header->count);
       if (!(p > profile_probability::never ()))
        p = profile_probability::very_unlikely ();
-    }
 
-  if (p >= profile_probability::always ()
-      || !p.initialized_p ())
-    return;
+      if (p == profile_probability::always ()
+         || !p.initialized_p ())
+       return;
 
-  /* Scale the actual probabilities.  */
-  scale_loop_frequencies (loop, p);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, ";; guessed iterations are now %i\n",
-            (int)expected_loop_iterations_unbounded (loop));
+      /* 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);
+
+      /* Change latch's count back.  */
+      if (loop->latch && loop->latch != e->src)
+       loop->latch->count -= count_delta;
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, ";; guessed iterations are now %i\n",
+                (int)expected_loop_iterations_unbounded (loop, NULL, true));
+    }
 }
 
 /* Recompute dominance information for basic blocks outside LOOP.  */