From 1265afa91d51606605f85e732344e86e4e4dae9b Mon Sep 17 00:00:00 2001
From: Richard Biener <rguenther@suse.de>
Date: Mon, 20 Jan 2025 11:50:53 +0100
Subject: [PATCH] tree-optimization/118552 - failed LC SSA update after
 unrolling

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.

	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 17bcf9f4acc4..573146b2e284 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 000000000000..03ee0d0ca3f2
--- /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;
+}
-- 
GitLab