When unrolling changes nesting relationship of loops we fail to
mark blocks as in need to change for LC SSA update.  Specifically
the LC SSA PHI on a former inner loop exit might be misplaced
if that loop becomes a sibling of its outer loop.

Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.

        PR tree-optimization/118552
        * cfgloopmanip.cc (fix_loop_placement): Properly mark
        exit source blocks as to be scanned for LC SSA update when
        the loops nesting relationship changed.
        (fix_loop_placements): Adjust.
        (fix_bb_placements): Likewise.

        * gcc.dg/torture/pr118552.c: New testcase.
---
 gcc/cfgloopmanip.cc                     | 13 +++++++---
 gcc/testsuite/gcc.dg/torture/pr118552.c | 34 +++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr118552.c

diff --git a/gcc/cfgloopmanip.cc b/gcc/cfgloopmanip.cc
index 17bcf9f4acc..573146b2e28 100644
--- a/gcc/cfgloopmanip.cc
+++ b/gcc/cfgloopmanip.cc
@@ -123,7 +123,8 @@ fix_bb_placement (basic_block bb)
    invalidate the information about irreducible regions.  */
 
 static bool
-fix_loop_placement (class loop *loop, bool *irred_invalidated)
+fix_loop_placement (class loop *loop, bool *irred_invalidated,
+                   bitmap loop_closed_ssa_invalidated)
 {
   unsigned i;
   edge e;
@@ -153,6 +154,10 @@ fix_loop_placement (class loop *loop, bool 
*irred_invalidated)
          if (e->flags & EDGE_IRREDUCIBLE_LOOP)
            *irred_invalidated = true;
          rescan_loop_exit (e, false, false);
+         /* Any LC SSA PHIs on e->dest might now be on the wrong edge
+            if their defs were in a former outer loop.  */
+         if (loop_closed_ssa_invalidated)
+           bitmap_set_bit (loop_closed_ssa_invalidated, e->src->index);
        }
 
       ret = true;
@@ -224,7 +229,8 @@ fix_bb_placements (basic_block from,
       if (from->loop_father->header == from)
        {
          /* Subloop header, maybe move the loop upward.  */
-         if (!fix_loop_placement (from->loop_father, irred_invalidated))
+         if (!fix_loop_placement (from->loop_father, irred_invalidated,
+                                  loop_closed_ssa_invalidated))
            continue;
          target_loop = loop_outer (from->loop_father);
          if (loop_closed_ssa_invalidated)
@@ -1057,7 +1063,8 @@ fix_loop_placements (class loop *loop, bool 
*irred_invalidated,
   while (loop_outer (loop))
     {
       outer = loop_outer (loop);
-      if (!fix_loop_placement (loop, irred_invalidated))
+      if (!fix_loop_placement (loop, irred_invalidated,
+                              loop_closed_ssa_invalidated))
        break;
 
       /* Changing the placement of a loop in the loop tree may alter the
diff --git a/gcc/testsuite/gcc.dg/torture/pr118552.c 
b/gcc/testsuite/gcc.dg/torture/pr118552.c
new file mode 100644
index 00000000000..03ee0d0ca3f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr118552.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fno-tree-ch -fno-tree-ccp -fno-tree-fre" } */
+
+volatile int a;
+int b, c, d, e;
+int main() {
+  int f = 1, g = 1;
+h:
+  if (!d)
+    ;
+  else {
+    int i = 1;
+  j:
+    e = 0;
+    for (; e < 3; e++) {
+      if (e)
+        for (; g < 2; g++) {
+          if (c)
+            return 0;
+          if (f)
+            goto j;
+        }
+      a;
+      if (i)
+        continue;
+      f = i = 0;
+    }
+  }
+  f = 2;
+  b++;
+  if (c)
+    goto h;
+  return 0;
+}
-- 
2.43.0

Reply via email to