RTL optimizers perform CFG adjustments themselves rather than relying on cleanup_cfg (as the gimple level does). This makes it necessary to handle things all-over-the-place. This case is if-conversion performing forwarder block removal (well, it calls it "speculation"), removing empty loop latches. That's unwanted, thus the following patch makes sure we do not do this.
I'm sure more RTL optimiziation fallout will pop up - and I wonder if we should simply avoid modifying the CFG all over the place and instead do that in cleanup_cfg. Thus, in the if-conversion case, simply do the speculation and leave the empty forwarder blocks to be cleaned up by cleanup_cfg (or for CSE to leave unconditional jumps conditional, as if (0/1), for example). Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2012-04-10 Richard Guenther <rguent...@suse.de> PR rtl-optimization/52881 * ifcvt.c (find_if_case_2): Avoid speculating loop latches. * gcc.dg/torture/pr52881.c: New testcase. * gcc.dg/torture/pr52913.c: Likewise. Index: gcc/ifcvt.c =================================================================== *** gcc/ifcvt.c (revision 186274) --- gcc/ifcvt.c (working copy) *************** find_if_case_2 (basic_block test_bb, edg *** 3927,3932 **** --- 3927,3937 ---- edge else_succ; int then_prob, else_prob; + /* We do not want to speculate (empty) loop latches. */ + if (current_loops + && else_bb->loop_father->latch == else_bb) + return FALSE; + /* If we are partitioning hot/cold basic blocks, we don't want to mess up unconditional or indirect jumps that cross between hot and cold sections. Index: gcc/testsuite/gcc.dg/torture/pr52881.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr52881.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr52881.c (revision 0) *************** *** 0 **** --- 1,35 ---- + /* { dg-do compile } */ + + int a, b, c, d, e, f, h, i, j, k, l, m, n, o; + static int g; + int + fn1 () { + for (;; ++f) + if (e) + break; + return 0; + } + unsigned char fn2 (); + void + fn3 () { + lbl_220: + if (j) { + lbl_221: + l = (g || b) <= fn1 (); + for (;;) { + g = 0; + fn2 (); + if (k) + goto lbl_220; + break; + } + if (l) + goto lbl_221; + } + } + unsigned char + fn2 () { + o = d ? 0 : c; + h = m | a % o != n; + return i; + } Index: gcc/testsuite/gcc.dg/torture/pr52913.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr52913.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr52913.c (revision 0) @@ -0,0 +1,18 @@ +/* { dg-do compile } */ + +int a, b, c, d, e; +void +fn1 () +{ +lbl_101: + e = 0; +lbl_274: + for (c = 0; c < 1; c = a) + if (d) + if (b) + goto lbl_101; + else + break; + d = 1; + goto lbl_274; +}