This patch widens the scope of the PR54838 fix (and reverts one of my earlier kludges). Like on the GIMPLE level threading an edge through a loop header is seldomly a good idea as it may create multiple-entry loops (not handled at all), create irreducible regions (not handled at all).
In theory threading the latch is possible (see the hoops tree-ssa-threadupdate.c jumps through). But instead of replicating all this on RTL the easiest thing is to simply not thread through loop headers when loops are to be preserved. It again unleashes the full powers before earlier patches when loops are not preserved (there is at least one rtl-cprop pass after rtl loop opts). Bootstrap and regtest pending on x86_64-unknown-linux-gnu. I've committed the testcase already as I wasn't able to reproduce the issue (had a local patch to fix it ...). Thanks, Richard. 2012-12-21 Richard Biener <rguent...@suse.de> PR rtl-optimization/52996 * cprop.c (bypass_block): When loops are to be preserved do not bypass loop headers. Revert earlier kludge to remove loops when doing that. Index: gcc/cprop.c =================================================================== *** gcc/cprop.c (revision 194658) --- gcc/cprop.c (working copy) *************** bypass_block (basic_block bb, rtx setcc, *** 1496,1502 **** rtx insn, note; edge e, edest; int change; ! int may_be_loop_header; unsigned removed_p; unsigned i; edge_iterator ei; --- 1496,1502 ---- rtx insn, note; edge e, edest; int change; ! int may_be_loop_header = false; unsigned removed_p; unsigned i; edge_iterator ei; *************** bypass_block (basic_block bb, rtx setcc, *** 1510,1536 **** if (note) find_used_regs (&XEXP (note, 0), NULL); - /* Determine whether there are more latch edges. Threading through - a loop header with more than one latch is delicate, see e.g. - tree-ssa-threadupdate.c:thread_through_loop_header. */ if (current_loops) { ! may_be_loop_header = bb == bb->loop_father->header; ! if (may_be_loop_header ! && bb->loop_father->latch == NULL) return 0; } else { - unsigned n_back_edges = 0; FOR_EACH_EDGE (e, ei, bb->preds) if (e->flags & EDGE_DFS_BACK) ! n_back_edges++; ! ! may_be_loop_header = n_back_edges > 0; ! ! if (n_back_edges > 1) ! return 0; } change = 0; --- 1510,1531 ---- if (note) find_used_regs (&XEXP (note, 0), NULL); if (current_loops) { ! /* If we are to preserve loop structure then do not bypass ! a loop header. This will either rotate the loop, create ! multiple entry loops or even irreducible regions. */ ! if (bb == bb->loop_father->header) return 0; } else { FOR_EACH_EDGE (e, ei, bb->preds) if (e->flags & EDGE_DFS_BACK) ! { ! may_be_loop_header = true; ! break; ! } } change = 0; *************** bypass_block (basic_block bb, rtx setcc, *** 1619,1635 **** && dest != old_dest && dest != EXIT_BLOCK_PTR) { - if (current_loops != NULL - && e->src->loop_father->latch == e->src) - { - /* ??? Now we are creating (or may create) a loop - with multiple entries. Simply mark it for - removal. Alternatively we could not do this - threading. */ - e->src->loop_father->header = NULL; - e->src->loop_father->latch = NULL; - } - redirect_edge_and_branch_force (e, dest); /* Copy the register setter to the redirected edge. --- 1614,1619 ----