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; +}
