https://gcc.gnu.org/g:e1efdc361c4fd123d34b7bbd5f9583137a62a905

commit r16-8527-ge1efdc361c4fd123d34b7bbd5f9583137a62a905
Author: Richard Biener <[email protected]>
Date:   Wed Apr 8 09:27:41 2026 +0200

    tree-optimization/124810 - ICE with loop fixup
    
    The following fixes fix_loop_placements to properly consider
    re-parenting only outer loops of a nest.
    
            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.

Diff:
---
 gcc/cfgloopmanip.cc                     | 37 ++++++++++++++++++++++-----------
 gcc/testsuite/gcc.dg/torture/pr124810.c | 23 ++++++++++++++++++++
 2 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/gcc/cfgloopmanip.cc b/gcc/cfgloopmanip.cc
index d8acbad6e55f..72f7c1896ba9 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 000000000000..bd2b03592d2f
--- /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;
+}

Reply via email to