]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR middle-end/54937
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Oct 2012 10:00:19 +0000 (10:00 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Oct 2012 10:00:19 +0000 (10:00 +0000)
* tree-ssa-loop-niter.c (record_estimate): Do not try to lower
the bound of non-is_exit statements.
(maybe_lower_iteration_bound): Do it here.
(estimate_numbers_of_iterations_loop): Call it.
* gcc.c-torture/execute/pr54937.c: New testcase.
* gcc.dg/tree-ssa/cunroll-2.c: Update.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192710 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr54937.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/cunroll-2.c
gcc/tree-ssa-loop-niter.c

index d9c294eb2ab451aa897480e2d67b951ffea1e0c5..815c5824ac49723584386db8c5791e76ac54f909 100644 (file)
@@ -1,3 +1,11 @@
+2012-10-23  Jan Hubicka  <jh@suse.cz>
+
+       PR middle-end/54937
+       * tree-ssa-loop-niter.c (record_estimate): Do not try to lower
+       the bound of non-is_exit statements.
+       (maybe_lower_iteration_bound): Do it here.
+       (estimate_numbers_of_iterations_loop): Call it.
+
 2012-10-23  Jan Hubicka  <jh@suse.cz>
 
        PR middle-end/54967
index 7daf70e366d55969cb13689409ad39e9fd88fc24..7a6d25847b638cb35bbfde5bc9a90eae61af6259 100644 (file)
@@ -1,3 +1,9 @@
+2012-10-23  Jan Hubicka  <jh@suse.cz>
+
+       PR middle-end/54937
+       * gcc.c-torture/execute/pr54937.c: New testcase.
+       * gcc.dg/tree-ssa/cunroll-2.c: Update.
+
 2012-10-23  Jan Hubicka  <jh@suse.cz>
 
        PR middle-end/54967
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr54937.c b/gcc/testsuite/gcc.c-torture/execute/pr54937.c
new file mode 100644 (file)
index 0000000..13dae60
--- /dev/null
@@ -0,0 +1,22 @@
+
+void exit (int);
+void abort (void);
+int a[1];
+void (*terminate_me)(int);
+
+__attribute__((noinline,noclone))
+t(int c)
+{ int i;
+  for (i=0;i<c;i++)
+    {
+      if (i)
+       terminate_me(0);
+      a[i]=0;
+    }
+}
+main()
+{
+  terminate_me = exit;
+  t(100);
+  abort();
+}
index cd54c6695b257b306c0247c701069bbbf5c9d922..8a54a801c6edb3dc7ab5255d533a2f70ea03afd4 100644 (file)
@@ -12,5 +12,5 @@ test(int c)
     }
 }
 /* We are not able to get rid of the final conditional because the loop has two exits.  */
-/* { dg-final { scan-tree-dump "Unrolled loop 1 completely .duplicated 2 times.." "cunroll"} } */
+/* { dg-final { scan-tree-dump "Unrolled loop 1 completely .duplicated 1 times.." "cunroll"} } */
 /* { dg-final { cleanup-tree-dump "cunroll" } } */
index 3c39413ee1bd6f3055125afe7ec330d12185ca71..054aff30954606bf06048458e664273915e76ccd 100644 (file)
@@ -2535,7 +2535,6 @@ record_estimate (struct loop *loop, tree bound, double_int i_bound,
                 gimple at_stmt, bool is_exit, bool realistic, bool upper)
 {
   double_int delta;
-  edge exit;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -2570,14 +2569,10 @@ record_estimate (struct loop *loop, tree bound, double_int i_bound,
     }
 
   /* Update the number of iteration estimates according to the bound.
-     If at_stmt is an exit or dominates the single exit from the loop,
-     then the loop latch is executed at most BOUND times, otherwise
-     it can be executed BOUND + 1 times.  */
-  exit = single_exit (loop);
-  if (is_exit
-      || (exit != NULL
-         && dominated_by_p (CDI_DOMINATORS,
-                            exit->src, gimple_bb (at_stmt))))
+     If at_stmt is an exit then the loop latch is executed at most BOUND times,
+     otherwise it can be executed BOUND + 1 times.  We will lower the estimate
+     later if such statement must be executed on last iteration  */
+  if (is_exit)
     delta = double_int_zero;
   else
     delta = double_int_one;
@@ -2953,6 +2948,110 @@ gcov_type_to_double_int (gcov_type val)
   return ret;
 }
 
+/* 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.  */
+
+static void
+maybe_lower_iteration_bound (struct loop *loop)
+{
+  pointer_set_t *not_executed_last_iteration = pointer_set_create ();
+  struct nb_iter_bound *elt;
+  bool found_exit = false;
+  VEC (basic_block, heap) *queue = NULL;
+  bitmap visited;
+
+  /* Collect all statements with interesting (i.e. lower than
+     nb_iterations_upper_bound) bound on them. 
+
+     TODO: Due to the way record_estimate choose estimates to store, the bounds
+     will be always nb_iterations_upper_bound-1.  We can change this to record
+     also statements not dominating the loop latch and update the walk bellow
+     to the shortest path algorthm.  */
+  for (elt = loop->bounds; elt; elt = elt->next)
+    {
+      if (!elt->is_exit
+         && elt->bound.ult (loop->nb_iterations_upper_bound))
+       {
+         if (!not_executed_last_iteration)
+           not_executed_last_iteration = pointer_set_create ();
+         pointer_set_insert (not_executed_last_iteration, elt->stmt);
+       }
+    }
+  if (!not_executed_last_iteration)
+    return;
+
+  /* Start DFS walk in the loop header and see if we can reach the
+     loop latch or any of the exits (including statements with side
+     effects that may terminate the loop otherwise) without visiting
+     any of the statements known to have undefined effect on the last
+     iteration.  */
+  VEC_safe_push (basic_block, heap, queue, loop->header);
+  visited = BITMAP_ALLOC (NULL);
+  bitmap_set_bit (visited, loop->header->index);
+  found_exit = false;
+
+  do
+    {
+      basic_block bb = VEC_pop (basic_block, queue);
+      gimple_stmt_iterator gsi;
+      bool stmt_found = false;
+
+      /* Loop for possible exits and statements bounding the execution.  */
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple stmt = gsi_stmt (gsi);
+         if (pointer_set_contains (not_executed_last_iteration, stmt))
+           {
+             stmt_found = true;
+             break;
+           }
+         if (gimple_has_side_effects (stmt))
+           {
+             found_exit = true;
+             break;
+           }
+       }
+      if (found_exit)
+       break;
+
+      /* If no bounding statement is found, continue the walk.  */
+      if (!stmt_found)
+       {
+          edge e;
+          edge_iterator ei;
+
+          FOR_EACH_EDGE (e, ei, bb->succs)
+           {
+             if (loop_exit_edge_p (loop, e)
+                 || e == loop_latch_edge (loop))
+               {
+                 found_exit = true;
+                 break;
+               }
+             if (bitmap_set_bit (visited, e->dest->index))
+               VEC_safe_push (basic_block, heap, queue, e->dest);
+           }
+       }
+    }
+  while (VEC_length (basic_block, queue) && !found_exit);
+
+  /* If every path through the loop reach bounding statement before exit,
+     then we know the last iteration of the loop will have undefined effect
+     and we can decrease number of iterations.  */
+    
+  if (!found_exit)
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, "Reducing loop iteration estimate by 1; "
+                "undefined statement must be executed at the last iteration.\n");
+      record_niter_bound (loop, loop->nb_iterations_upper_bound - double_int_one,
+                         false, true);
+    }
+  BITMAP_FREE (visited);
+  VEC_free (basic_block, heap, queue);
+}
+
 /* Records estimates on numbers of iterations of LOOP.  If USE_UNDEFINED_P
    is true also use estimates derived from undefined behavior.  */
 
@@ -2996,6 +3095,8 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
 
   infer_loop_bounds_from_undefined (loop);
 
+  maybe_lower_iteration_bound (loop);
+
   /* If we have a measured profile, use it to estimate the number of
      iterations.  */
   if (loop->header->count != 0)