tree-ssa-loop-niter.c (double_int_cmp, [...]): New functions.
authorJan Hubicka <jh@suse.cz>
Fri, 2 Nov 2012 19:35:44 +0000 (20:35 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Fri, 2 Nov 2012 19:35:44 +0000 (19:35 +0000)
* tree-ssa-loop-niter.c (double_int_cmp, bound_index,
discover_iteration_bound_by_body_walk): New functions.
(discover_iteration_bound_by_body_walk): Use it.

* gcc.dg/tree-ssa/loop-38.c: New testcase.

From-SVN: r193104

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/loop-38.c [new file with mode: 0644]
gcc/tree-ssa-loop-niter.c

index 29c8147ac77c2203c67256a6ebda97f9501729b5..284dd8a152036b52ec3e0608254b3f5a14ae6c4c 100644 (file)
@@ -1,3 +1,9 @@
+2012-11-02  Jan Hubicka  <jh@suse.cz>
+
+       * tree-ssa-loop-niter.c (double_int_cmp, bound_index,
+       discover_iteration_bound_by_body_walk): New functions.
+       (discover_iteration_bound_by_body_walk): Use it.
+
 2012-11-02  Jan Hubicka  <jh@suse.cz>
 
        * predict.c (predict_loops): Predict also exits not dominating
index 2a2f86d43b4772054ab8b7f7179d40989574ec50..7bf85b0c714c3fd595d0c78fbb10561e208ad787 100644 (file)
        * gcc.target/powerpc/pr46728-8.c: Likewise.
        * gcc/testsuite/gcc.dg/pr46728-6.c: Likewise.
 
+2012-11-02  Jan Hubicka  <jh@suse.cz>
+
+       * gcc.dg/tree-ssa/loop-38.c: New testcase.
+
 2012-11-02  Jan Hubicka  <jh@suse.cz>
 
        * gcc.dg/tree-ssa/cunroll-10.c: New testcase.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-38.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-38.c
new file mode 100644 (file)
index 0000000..d5568d6
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cunrolli-details" } */
+int a[10];
+int b[11];
+t(int n)
+{
+   int i;
+   int sum = 0;
+   for (i=0;i<n;i++)
+     if (q())
+       sum+=a[i];
+     else
+       sum+=b[i];
+  return sum;
+}
+/* { dg-final { scan-tree-dump "Found better loop bound 10" "cunrolli" } } */
+/* { dg-final { scan-tree-dump "Loop 1 iterates at most 10 times" "cunrolli" } } */
+/* { dg-final { cleanup-tree-dump "cunrolli" } } */
index b77bcbbe5bade64ea315c2fa20ad3008689829cd..b769f849d0e9da8696553fc22176e7b29bea7e8d 100644 (file)
@@ -2961,6 +2961,224 @@ gcov_type_to_double_int (gcov_type val)
   return ret;
 }
 
+/* Compare double ints, callback for qsort.  */
+
+int
+double_int_cmp (const void *p1, const void *p2)
+{
+  const double_int *d1 = (const double_int *)p1;
+  const double_int *d2 = (const double_int *)p2;
+  if (*d1 == *d2)
+    return 0;
+  if (d1->ult (*d2))
+    return -1;
+  return 1;
+}
+
+/* Return index of BOUND in BOUNDS array sorted in increasing order.
+   Lookup by binary search.  */
+
+int
+bound_index (VEC (double_int, heap) *bounds, double_int bound)
+{
+  unsigned int end = VEC_length (double_int, bounds);
+  unsigned int begin = 0;
+
+  /* Find a matching index by means of a binary search.  */
+  while (begin != end)
+    {
+      unsigned int middle = (begin + end) / 2;
+      double_int index = VEC_index (double_int, bounds, middle);
+
+      if (index == bound)
+       return middle;
+      else if (index.ult (bound))
+       begin = middle + 1;
+      else
+       end = middle;
+    }
+  gcc_unreachable ();
+}
+
+/* Used to hold vector of queues of basic blocks bellow.  */
+typedef VEC (basic_block, heap) *bb_queue;
+DEF_VEC_P(bb_queue);
+DEF_VEC_ALLOC_P(bb_queue,heap);
+
+/* We recorded loop bounds only for statements dominating loop latch (and thus
+   executed each loop iteration).  If there are any bounds on statements not
+   dominating the loop latch we can improve the estimate by walking the loop
+   body and seeing if every path from loop header to loop latch contains
+   some bounded statement.  */
+
+static void
+discover_iteration_bound_by_body_walk (struct loop *loop)
+{
+  pointer_map_t *bb_bounds;
+  struct nb_iter_bound *elt;
+  VEC (double_int, heap) *bounds = NULL;
+  VEC (bb_queue, heap) *queues = NULL;
+  bb_queue queue = NULL;
+  ptrdiff_t queue_index;
+  ptrdiff_t latch_index = 0;
+  pointer_map_t *block_priority;
+
+  /* Discover what bounds may interest us.  */
+  for (elt = loop->bounds; elt; elt = elt->next)
+    {
+      double_int bound = elt->bound;
+
+      /* Exit terminates loop at given iteration, while non-exits produce undefined
+        effect on the next iteration.  */
+      if (!elt->is_exit)
+       bound += double_int_one;
+
+      if (!loop->any_upper_bound
+         || bound.ult (loop->nb_iterations_upper_bound))
+        VEC_safe_push (double_int, heap, bounds, bound);
+    }
+
+  /* Exit early if there is nothing to do.  */
+  if (!bounds)
+    return;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, " Trying to walk loop body to reduce the bound.\n");
+
+  /* Sort the bounds in decreasing order.  */
+  qsort (VEC_address (double_int, bounds), VEC_length (double_int, bounds),
+        sizeof (double_int), double_int_cmp);
+
+  /* For every basic block record the lowest bound that is guaranteed to
+     terminate the loop.  */
+
+  bb_bounds = pointer_map_create ();
+  for (elt = loop->bounds; elt; elt = elt->next)
+    {
+      double_int bound = elt->bound;
+      if (!elt->is_exit)
+       bound += double_int_one;
+
+      if (!loop->any_upper_bound
+         || bound.ult (loop->nb_iterations_upper_bound))
+       {
+         ptrdiff_t index = bound_index (bounds, bound);
+         void **entry = pointer_map_contains (bb_bounds,
+                                              gimple_bb (elt->stmt));
+         if (!entry)
+           *pointer_map_insert (bb_bounds,
+                                gimple_bb (elt->stmt)) = (void *)index;
+         else if ((ptrdiff_t)*entry > index)
+           *entry = (void *)index;
+       }
+    }
+
+  block_priority = pointer_map_create ();
+
+  /* Perform shortest path discovery loop->header ... loop->latch.
+
+     The "distance" is given by the smallest loop bound of basic block
+     present in the path and we look for path with largest smallest bound
+     on it.
+
+     To avoid the need for fibonaci heap on double ints we simply compress
+     double ints into indexes to BOUNDS array and then represent the queue
+     as arrays of queues for every index.
+     Index of VEC_length (BOUNDS) means that the execution of given BB has
+     no bounds determined.
+
+     VISITED is a pointer map translating basic block into smallest index
+     it was inserted into the priority queue with.  */
+  latch_index = -1;
+
+  /* Start walk in loop header with index set to infinite bound.  */
+  queue_index = VEC_length (double_int, bounds);
+  VEC_safe_grow_cleared (bb_queue, heap, queues, queue_index + 1);
+  VEC_safe_push (basic_block, heap, queue, loop->header);
+  VEC_replace (bb_queue, queues, queue_index, queue);
+  *pointer_map_insert (block_priority, loop->header) = (void *)queue_index;
+
+  for (; queue_index >= 0; queue_index--)
+    {
+      if (latch_index < queue_index)
+       {
+         while (VEC_length (basic_block,
+                            VEC_index (bb_queue, queues, queue_index)))
+           {
+             basic_block bb;
+             ptrdiff_t bound_index = queue_index;
+             void **entry;
+              edge e;
+              edge_iterator ei;
+
+             queue = VEC_index (bb_queue, queues, queue_index);
+             bb = VEC_pop (basic_block, queue);
+
+             /* OK, we later inserted the BB with lower priority, skip it.  */
+             if ((ptrdiff_t)*pointer_map_contains (block_priority, bb) > queue_index)
+               continue;
+
+             /* See if we can improve the bound.  */
+             entry = pointer_map_contains (bb_bounds, bb);
+             if (entry && (ptrdiff_t)*entry < bound_index)
+               bound_index = (ptrdiff_t)*entry;
+
+             /* Insert succesors into the queue, watch for latch edge
+                and record greatest index we saw.  */
+             FOR_EACH_EDGE (e, ei, bb->succs)
+               {
+                 bool insert = false;
+                 void **entry;
+
+                 if (loop_exit_edge_p (loop, e))
+                   continue;
+
+                 if (e == loop_latch_edge (loop)
+                     && latch_index < bound_index)
+                   latch_index = bound_index;
+                 else if (!(entry = pointer_map_contains (block_priority, e->dest)))
+                   {
+                     insert = true;
+                     *pointer_map_insert (block_priority, e->dest) = (void *)bound_index;
+                   }
+                 else if ((ptrdiff_t)*entry < bound_index)
+                   {
+                     insert = true;
+                     *entry = (void *)bound_index;
+                   }
+                   
+                 if (insert)
+                   {
+                     bb_queue queue2 = VEC_index (bb_queue, queues, bound_index);
+                     VEC_safe_push (basic_block, heap, queue2, e->dest);
+                     VEC_replace (bb_queue, queues, bound_index, queue2);
+                   }
+               }
+           }
+       }
+      else
+       VEC_free (basic_block, heap, VEC_index (bb_queue, queues, queue_index));
+    }
+
+  gcc_assert (latch_index >= 0);
+  if (latch_index < VEC_length (double_int, bounds))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Found better loop bound ");
+         dump_double_int (dump_file,
+                          VEC_index (double_int, bounds, latch_index), true);
+         fprintf (dump_file, "\n");
+       }
+      record_niter_bound (loop, VEC_index (double_int, bounds, latch_index),
+                         false, true);
+    }
+
+  VEC_free (bb_queue, heap, queues);
+  pointer_map_destroy (bb_bounds);
+  pointer_map_destroy (block_priority);
+}
+
 /* See if every path cross the loop goes through a statement that is known
    to not execute at the last iteration. In that case we can decrese iteration
    count by 1.  */
@@ -3108,6 +3326,8 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
 
   infer_loop_bounds_from_undefined (loop);
 
+  discover_iteration_bound_by_body_walk (loop);
+
   maybe_lower_iteration_bound (loop);
 
   /* If we have a measured profile, use it to estimate the number of