tree-optimization/124810 - ICE with loop fixup

Message ID 20260408114925.21A734A0B3@imap1.dmz-prg2.suse.org
State New
Headers
Series tree-optimization/124810 - ICE with loop fixup |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply

Commit Message

Richard Biener April 8, 2026, 11:49 a.m. UTC
  The following fixes fix_loop_placements to properly consider
re-parenting only outer loops of a nest.

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

	PR tree-optimization/124810
	* cfgloopmanip.cc (fix_loop_placements): Do not stop
	iterating when an inner loop didn't get re-parented.
	Compute the outermost loop we have to consider re-parenting.

	* gcc.dg/torture/pr124810.c: New testcase.
---
 gcc/cfgloopmanip.cc                     | 37 +++++++++++++++++--------
 gcc/testsuite/gcc.dg/torture/pr124810.c | 23 +++++++++++++++
 2 files changed, 48 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr124810.c
  

Patch

diff --git a/gcc/cfgloopmanip.cc b/gcc/cfgloopmanip.cc
index d8acbad6e55..72f7c1896ba 100644
--- a/gcc/cfgloopmanip.cc
+++ b/gcc/cfgloopmanip.cc
@@ -1061,23 +1061,36 @@  static void
 fix_loop_placements (class loop *loop, bool *irred_invalidated,
 		     bitmap loop_closed_ssa_invalidated)
 {
-  class loop *outer;
+  if (!loop_outer (loop))
+    return;
+
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
+  unsigned i;
+  edge e;
 
+  /* We might need to only re-parent an outer loop, but as the constraint
+     is that we removed an exit from LOOP, we have a limit for what level
+     of outer loop we eventually have to re-parent to.  */
+  class loop *outermost = loop;
+  FOR_EACH_VEC_ELT (exits, i, e)
+    outermost = find_common_loop (outermost, e->dest->loop_father);
+
+  class loop *outer;
   while (loop_outer (loop))
     {
       outer = loop_outer (loop);
-      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
-	 validity of condition 2) of the description of fix_bb_placement
-	 for its preheader, because the successor is the header and belongs
-	 to the loop.  So call fix_bb_placements to fix up the placement
-	 of the preheader and (possibly) of its predecessors.  */
-      fix_bb_placements (loop_preheader_edge (loop)->src,
-			 irred_invalidated, loop_closed_ssa_invalidated);
+      if (fix_loop_placement (loop, irred_invalidated,
+			      loop_closed_ssa_invalidated))
+	/* Changing the placement of a loop in the loop tree may alter the
+	   validity of condition 2) of the description of fix_bb_placement
+	   for its preheader, because the successor is the header and belongs
+	   to the loop.  So call fix_bb_placements to fix up the placement
+	   of the preheader and (possibly) of its predecessors.  */
+	fix_bb_placements (loop_preheader_edge (loop)->src,
+			   irred_invalidated, loop_closed_ssa_invalidated);
       loop = outer;
+      if (outer == outermost)
+	break;
     }
 }
 
diff --git a/gcc/testsuite/gcc.dg/torture/pr124810.c b/gcc/testsuite/gcc.dg/torture/pr124810.c
new file mode 100644
index 00000000000..bd2b03592d2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr124810.c
@@ -0,0 +1,23 @@ 
+/* { dg-additional-options "-fno-tree-ch -fno-tree-dce -fno-tree-dominator-opts -fno-tree-vrp -fno-tree-dse" } */
+
+int a, b[9], c, d;
+static void e() {
+  int f[9];
+  unsigned char g;
+h:
+i:
+  if (a)
+    goto h;
+  g = 0;
+  for (; g < 9; g++) {
+    b[g] = f[8] ? 0 : g;
+    if (g)
+      goto i;
+    d ? c && d < 0 : c;
+  }
+}
+int main() {
+  while (c)
+    e();
+  return 0;
+}