re PR tree-optimization/56817 (ICE in hide_evolution_in_other_loops_than_loop)
authorRichard Biener <rguenther@suse.de>
Wed, 3 Apr 2013 13:41:13 +0000 (13:41 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Wed, 3 Apr 2013 13:41:13 +0000 (13:41 +0000)
2013-04-03  Richard Biener  <rguenther@suse.de>

PR tree-optimization/56817
* tree-ssa-loop-ivcanon.c (tree_unroll_loops_completely):
Split out ...
(tree_unroll_loops_completely_1): ... new function to manually
walk the loop tree, properly defering outer loops of unrolled
loops to later iterations.

* g++.dg/torture/pr56817.C: New testcase.

From-SVN: r197411

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr56817.C [new file with mode: 0644]
gcc/tree-ssa-loop-ivcanon.c

index 69afaf3b25ff489365e4d0c32a057ff749497ec0..f6b00ca6700bf29e492ea1c37072a554d4246e35 100644 (file)
@@ -1,3 +1,12 @@
+2013-04-03  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/56817
+       * tree-ssa-loop-ivcanon.c (tree_unroll_loops_completely):
+       Split out ...
+       (tree_unroll_loops_completely_1): ... new function to manually
+       walk the loop tree, properly defering outer loops of unrolled
+       loops to later iterations.
+
 2013-04-03  Marc Glisse  <marc.glisse@inria.fr>
 
        * tree-vect-stmts.c (vectorizable_store): Accept BIT_FIELD_REF.
index e9482cbc480a8a173d21a9d69e26ffee704507d4..d871b6e5960d814a90dd366e9e0e4f98aa8c7b79 100644 (file)
@@ -1,3 +1,8 @@
+2013-04-03  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/56817
+       * g++.dg/torture/pr56817.C: New testcase.
+
 2013-04-03  Marc Glisse  <marc.glisse@inria.fr>
 
        * gcc.dg/vect/bb-slp-31.c: New file.
diff --git a/gcc/testsuite/g++.dg/torture/pr56817.C b/gcc/testsuite/g++.dg/torture/pr56817.C
new file mode 100644 (file)
index 0000000..35fc6f7
--- /dev/null
@@ -0,0 +1,38 @@
+// { dg-do compile }
+// { dg-options "--param max-unroll-times=32" }
+
+struct A {};
+A **q;
+struct B
+{
+  A **j;
+  B () { j = q; }
+  A *& operator[] (unsigned long x) { return j[x]; }
+};
+struct C
+{
+  C (int r) : v (), s (r) {}
+  A *& operator () (int i, int j) { return v[i * s + j]; }
+  B v;
+  int s;
+};
+struct D
+{
+  D ()
+    {
+      unsigned h = 2;
+      for (int i = 0; i < 1; ++i, h *= 2)
+       {
+         C w (h);
+         for (unsigned j = 0; j < h; ++j)
+           for (unsigned k = 0; k < h; ++k)
+             w (j, k) = new A;
+       }
+    }
+};
+void
+foo ()
+{
+  for (int i = 0; i < 3; i++)
+    A (), A (), D ();
+}
index 4570807842d70d907ed60a466a7dd4597c0bd188..c57e4f6a30d3ce727c15ee040debb8639d07635e 100644 (file)
@@ -1097,6 +1097,63 @@ propagate_constants_for_unrolling (basic_block bb)
     }
 }
 
+/* Process loops from innermost to outer, stopping at the innermost
+   loop we unrolled.  */
+
+static bool
+tree_unroll_loops_completely_1 (bool may_increase_size, bool unroll_outer,
+                               vec<loop_p, va_stack>& father_stack,
+                               struct loop *loop)
+{
+  struct loop *loop_father;
+  bool changed = false;
+  struct loop *inner;
+  enum unroll_level ul;
+
+  /* Process inner loops first.  */
+  for (inner = loop->inner; inner != NULL; inner = inner->next)
+    changed |= tree_unroll_loops_completely_1 (may_increase_size,
+                                              unroll_outer, father_stack,
+                                              inner);
+  /* If we changed an inner loop we cannot process outer loops in this
+     iteration because SSA form is not up-to-date.  Continue with
+     siblings of outer loops instead.  */
+  if (changed)
+    return true;
+
+  /* Try to unroll this loop.  */
+  loop_father = loop_outer (loop);
+  if (!loop_father)
+    return false;
+
+  if (may_increase_size && optimize_loop_nest_for_speed_p (loop)
+      /* Unroll outermost loops only if asked to do so or they do
+        not cause code growth.  */
+      && (unroll_outer || loop_outer (loop_father)))
+    ul = UL_ALL;
+  else
+    ul = UL_NO_GROWTH;
+
+  if (canonicalize_loop_induction_variables
+        (loop, false, ul, !flag_tree_loop_ivcanon))
+    {
+      /* If we'll continue unrolling, we need to propagate constants
+        within the new basic blocks to fold away induction variable
+        computations; otherwise, the size might blow up before the
+        iteration is complete and the IR eventually cleaned up.  */
+      if (loop_outer (loop_father) && !loop_father->aux)
+       {
+         father_stack.safe_push (loop_father);
+         loop_father->aux = loop_father;
+       }
+
+      return true;
+    }
+
+  return false;
+}
+
 /* Unroll LOOPS completely if they iterate just few times.  Unless
    MAY_INCREASE_SIZE is true, perform the unrolling only if the
    size of the code does not increase.  */
@@ -1105,10 +1162,7 @@ unsigned int
 tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
 {
   vec<loop_p, va_stack> father_stack;
-  loop_iterator li;
-  struct loop *loop;
   bool changed;
-  enum unroll_level ul;
   int iteration = 0;
   bool irred_invalidated = false;
 
@@ -1124,34 +1178,9 @@ tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
       free_numbers_of_iterations_estimates ();
       estimate_numbers_of_iterations ();
 
-      FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
-       {
-         struct loop *loop_father = loop_outer (loop);
-
-         if (may_increase_size && optimize_loop_nest_for_speed_p (loop)
-             /* Unroll outermost loops only if asked to do so or they do
-                not cause code growth.  */
-             && (unroll_outer || loop_outer (loop_father)))
-           ul = UL_ALL;
-         else
-           ul = UL_NO_GROWTH;
-
-         if (canonicalize_loop_induction_variables
-                (loop, false, ul, !flag_tree_loop_ivcanon))
-           {
-             changed = true;
-             /* If we'll continue unrolling, we need to propagate constants
-                within the new basic blocks to fold away induction variable
-                computations; otherwise, the size might blow up before the
-                iteration is complete and the IR eventually cleaned up.  */
-             if (loop_outer (loop_father) && !loop_father->aux)
-               {
-                 father_stack.safe_push (loop_father);
-                 loop_father->aux = loop_father;
-               }
-           }
-       }
-
+      changed = tree_unroll_loops_completely_1 (may_increase_size,
+                                               unroll_outer, father_stack,
+                                               current_loops->tree_root);
       if (changed)
        {
          struct loop **iter;