The testcase shows that when cleaning up the CFG we can end up with broken LC SSA (for virtual operands with the testcase). The case here involves deleting a loop after which it is not enough to scan the blocks with changed loop depth for SSA uses that need to be rewritten. So make fix_loop_sturcture return the sum of the number of new loops and the number of deleted loops.
Bootstrap and regtest pending on x86_64-unknown-linux-gnu. PR tree-optimization/106182 * loop-init.cc (fix_loop_structure): Return the number of newly discovered plus the number of deleted loops. * tree-cfgcleanup.cc (repair_loop_structures): Adjust variable name. * gcc.dg/torture/pr106182.c: New testcase. --- gcc/loop-init.cc | 10 +++++----- gcc/testsuite/gcc.dg/torture/pr106182.c | 18 ++++++++++++++++++ gcc/tree-cfgcleanup.cc | 6 +++--- 3 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr106182.c diff --git a/gcc/loop-init.cc b/gcc/loop-init.cc index 648aa290916..b9e07973dd6 100644 --- a/gcc/loop-init.cc +++ b/gcc/loop-init.cc @@ -194,7 +194,7 @@ loop_fini_done: If CHANGED_BBS is not NULL, basic blocks whose loop depth has changed are marked in it. - Returns the number of new discovered loops. */ + Returns the number of new discovered plus the number of removed loops. */ unsigned fix_loop_structure (bitmap changed_bbs) @@ -277,7 +277,7 @@ fix_loop_structure (bitmap changed_bbs) } /* Finally free deleted loops. */ - bool any_deleted = false; + unsigned n_deleted = 0; class loop *loop; FOR_EACH_VEC_ELT (*get_loops (cfun), i, loop) if (loop && loop->header == NULL) @@ -311,12 +311,12 @@ fix_loop_structure (bitmap changed_bbs) } (*get_loops (cfun))[i] = NULL; flow_loop_free (loop); - any_deleted = true; + n_deleted++; } /* If we deleted loops then the cached scalar evolutions refering to those loops become invalid. */ - if (any_deleted && scev_initialized_p ()) + if (n_deleted > 0 && scev_initialized_p ()) scev_reset_htab (); loops_state_clear (LOOPS_NEED_FIXUP); @@ -328,7 +328,7 @@ fix_loop_structure (bitmap changed_bbs) timevar_pop (TV_LOOP_INIT); - return number_of_loops (cfun) - old_nloops; + return number_of_loops (cfun) - old_nloops + n_deleted; } /* The RTL loop superpass. The actual passes are subpasses. See passes.cc for diff --git a/gcc/testsuite/gcc.dg/torture/pr106182.c b/gcc/testsuite/gcc.dg/torture/pr106182.c new file mode 100644 index 00000000000..6b5c2493fd6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr106182.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-funswitch-loops" } */ + +short var_32; +int test_var_0; +unsigned char test_var_6; +char test_var_13; +void test(int var_2) +{ + for (;;) + for (short i_7; i_7 < test_var_13; i_7 += 1) + for (; test_var_0;) { + for (; var_2;) + var_32 = 0; + for (char i_19; i_19 < test_var_6 + 135; i_19 += 200) + ; + } +} diff --git a/gcc/tree-cfgcleanup.cc b/gcc/tree-cfgcleanup.cc index a6d0bf2c40a..3b24e021b6b 100644 --- a/gcc/tree-cfgcleanup.cc +++ b/gcc/tree-cfgcleanup.cc @@ -1170,13 +1170,13 @@ static void repair_loop_structures (void) { bitmap changed_bbs; - unsigned n_new_loops; + unsigned n_new_or_deleted_loops; calculate_dominance_info (CDI_DOMINATORS); timevar_push (TV_REPAIR_LOOPS); changed_bbs = BITMAP_ALLOC (NULL); - n_new_loops = fix_loop_structure (changed_bbs); + n_new_or_deleted_loops = fix_loop_structure (changed_bbs); /* This usually does nothing. But sometimes parts of cfg that originally were inside a loop get out of it due to edge removal (since they @@ -1184,7 +1184,7 @@ repair_loop_structures (void) irreducible loop can become reducible - in this case force a full rewrite into loop-closed SSA form. */ if (loops_state_satisfies_p (LOOP_CLOSED_SSA)) - rewrite_into_loop_closed_ssa (n_new_loops ? NULL : changed_bbs, + rewrite_into_loop_closed_ssa (n_new_or_deleted_loops ? NULL : changed_bbs, TODO_update_ssa); BITMAP_FREE (changed_bbs); -- 2.35.3