The following patch fixes (?) PR55833 by recomputing irreducible loops after every unswitch-transformation. With this testcase, when we perform loop unswitching on the RTL level, we end up in situation where we have a loop into which we get through loop exit of another loop which is a part of an irreducible region. Between those two loops is something like preheader, which isn't marked as irreducible, nor its edges. verify_loop_structure then ICEs because of that. Another hunk of this patch is just cheaper checking, written by Richi.
Regtested/bootstrapped on x86_64-linux. Zdenek, any thoughts on this? 2013-01-10 Richard Biener <rguent...@suse.de> Marek Polacek <pola...@redhat.com> PR rtl-optimization/55833 * loop-unswitch.c (unswitch_loops): Move loop verification... (unswitch_single_loop): ...here. Call mark_irreducible_loops. * gcc.dg/pr55833.c: New test. --- gcc/loop-unswitch.c.mp 2013-01-10 16:50:28.899559875 +0100 +++ gcc/loop-unswitch.c 2013-01-10 16:50:34.203575403 +0100 @@ -145,12 +145,7 @@ unswitch_loops (void) /* Go through inner loops (only original ones). */ FOR_EACH_LOOP (li, loop, LI_ONLY_INNERMOST) - { - unswitch_single_loop (loop, NULL_RTX, 0); -#ifdef ENABLE_CHECKING - verify_loop_structure (); -#endif - } + unswitch_single_loop (loop, NULL_RTX, 0); iv_analysis_done (); } @@ -370,6 +365,13 @@ unswitch_single_loop (struct loop *loop, nloop = unswitch_loop (loop, bbs[i], copy_rtx_if_shared (cond), cinsn); gcc_assert (nloop); + /* We changed the CFG. Recompute irreducible BBs and edges. */ + mark_irreducible_loops (); + +#ifdef ENABLE_CHECKING + verify_loop_structure (); +#endif + /* Invoke itself on modified loops. */ unswitch_single_loop (nloop, rconds, num + 1); unswitch_single_loop (loop, conds, num + 1); --- gcc/testsuite/gcc.dg/pr55833.c.mp 2013-01-10 17:23:26.016102692 +0100 +++ gcc/testsuite/gcc.dg/pr55833.c 2013-01-10 17:23:15.898073384 +0100 @@ -0,0 +1,28 @@ +/* PR rtl-optimization/55833 */ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +int a, b, c; + +void foo() +{ + unsigned d, l, *p, k = 1; + + if(bar()) + { +label: + if((a = a <= 0)) + { + if(c) + d = b; + + if (b || d ? l : k ? : 0) + a = d = 0; + + goto label; + } + } + + while(*p++) + goto label; +} Marek