This fixes PR56264 - the machinery to communicate changed-blocks from fix_loop_structure to cfgcleanups call to rewrite_into_loop_closed_ssa doesn't work (at least) in the face of newly discovered loops as that exposes new definition sites and not only new use sites (as the code assumes).
Fixed by completely re-scanning the whole function if we discover new loops (in this case unswitching makes one subloop no longer irreducible). Bootstrapped and tested on x86_64-unknown-linux-gnu, need to retest because I combined it with removing the find_uses_to_rename ??? and that exposes PR56286. Richard. 2013-02-11 Richard Biener <rguent...@suse.de> PR tree-optimization/56264 * cfgloop.h (fix_loop_structure): Adjust prototype. * loop-init.c (fix_loop_structure): Return the number of newly discovered loops. * tree-cfgcleanup.c (repair_loop_structures): When new loops are discovered, do a full loop-closed SSA rewrite. * gcc.dg/torture/pr56264.c: New testcase. Index: gcc/cfgloop.h =================================================================== *** gcc/cfgloop.h (revision 195938) --- gcc/cfgloop.h (working copy) *************** extern void flow_loop_dump (const struct *** 216,222 **** struct loop *alloc_loop (void); extern void flow_loop_free (struct loop *); int flow_loop_nodes_find (basic_block, struct loop *); ! void fix_loop_structure (bitmap changed_bbs); bool mark_irreducible_loops (void); void release_recorded_exits (void); void record_loop_exits (void); --- 216,222 ---- struct loop *alloc_loop (void); extern void flow_loop_free (struct loop *); int flow_loop_nodes_find (basic_block, struct loop *); ! unsigned fix_loop_structure (bitmap changed_bbs); bool mark_irreducible_loops (void); void release_recorded_exits (void); void record_loop_exits (void); Index: gcc/loop-init.c =================================================================== *** gcc/loop-init.c (revision 195938) --- gcc/loop-init.c (working copy) *************** loop_fini_done: *** 171,186 **** the latch, and loops did not get new subloops (new loops might possibly get created, but we are not interested in them). Fix up the mess. ! If CHANGED_BBS is not NULL, basic blocks whose loop has changed are ! marked in it. */ ! void fix_loop_structure (bitmap changed_bbs) { basic_block bb; int record_exits = 0; loop_iterator li; struct loop *loop; timevar_push (TV_LOOP_INIT); --- 171,189 ---- the latch, and loops did not get new subloops (new loops might possibly get created, but we are not interested in them). Fix up the mess. ! If CHANGED_BBS is not NULL, basic blocks whose loop depth has changed are ! marked in it. ! Returns the number of new discovered loops. */ ! ! unsigned fix_loop_structure (bitmap changed_bbs) { basic_block bb; int record_exits = 0; loop_iterator li; struct loop *loop; + unsigned old_nloops; timevar_push (TV_LOOP_INIT); *************** fix_loop_structure (bitmap changed_bbs) *** 228,233 **** --- 231,240 ---- delete_loop (loop); } + /* Remember the number of loops so we can return how many new loops + flow_loops_find discovered. */ + old_nloops = number_of_loops (); + /* Re-compute loop structure in-place. */ flow_loops_find (current_loops); *************** fix_loop_structure (bitmap changed_bbs) *** 253,258 **** --- 260,267 ---- #endif timevar_pop (TV_LOOP_INIT); + + return number_of_loops () - old_nloops; } /* Gate for the RTL loop superpass. The actual passes are subpasses. Index: gcc/tree-cfgcleanup.c =================================================================== *** gcc/tree-cfgcleanup.c (revision 195938) --- gcc/tree-cfgcleanup.c (working copy) *************** static void *** 707,724 **** repair_loop_structures (void) { bitmap changed_bbs; calculate_dominance_info (CDI_DOMINATORS); timevar_push (TV_REPAIR_LOOPS); changed_bbs = BITMAP_ALLOC (NULL); ! 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 ! become unreachable by back edges from latch). */ if (loops_state_satisfies_p (LOOP_CLOSED_SSA)) ! rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa); BITMAP_FREE (changed_bbs); --- 707,728 ---- repair_loop_structures (void) { bitmap changed_bbs; + unsigned n_new_loops; calculate_dominance_info (CDI_DOMINATORS); timevar_push (TV_REPAIR_LOOPS); changed_bbs = BITMAP_ALLOC (NULL); ! n_new_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 ! become unreachable by back edges from latch). Also a former ! 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, ! TODO_update_ssa); BITMAP_FREE (changed_bbs); Index: gcc/testsuite/gcc.dg/torture/pr56264.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr56264.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr56264.c (working copy) *************** *** 0 **** --- 1,20 ---- + /* { dg-do compile } */ + /* { dg-options "-funswitch-loops" } */ + + int a, b, c; + + void f(void) + { + if(b) + { + for(a = 0; a < 1; a++) + lbl: + c = c && b ? : 0; + + c = 0; + goto lbl; + } + + if(a) + goto lbl; + }