The following fixes an omission from when I introduced the mark_loop_for_removal abstraction. thread_through_all_blocks still uses the old way of killing a loop. The following patch fixes this by not killing it at all (it's just likely that the loop will break and a loop-fixup is scheduled anyway if we change the CFG and that fixup will deal with this just fine).
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard. 2014-11-26 Richard Biener <rguent...@suse.de> PR tree-optimization/64083 * tree-ssa-threadupdate.c (thread_through_all_blocks): Do not forcibly mark loop for removal the wrong way. * gcc.dg/torture/pr64083.c: New testcase. Index: gcc/tree-ssa-threadupdate.c =================================================================== --- gcc/tree-ssa-threadupdate.c (revision 218078) +++ gcc/tree-ssa-threadupdate.c (working copy) @@ -2428,16 +2428,8 @@ thread_through_all_blocks (bool may_peel /* Our path is still valid, thread it. */ if (e->aux) { - struct loop *loop = (*path)[0]->e->dest->loop_father; - if (thread_block ((*path)[0]->e->dest, false)) - { - /* This jump thread likely totally scrambled this loop. - So arrange for it to be fixed up. */ - loop->header = NULL; - loop->latch = NULL; - e->aux = NULL; - } + e->aux = NULL; else { delete_jump_thread_path (path); Index: gcc/testsuite/gcc.dg/torture/pr64083.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr64083.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr64083.c (working copy) @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +int a, b; +void +fn1 () +{ + int c = 0; + while (b) + { + switch (c) + case 1: + fn1 (); + if (a) + c = 1; + b = 0; + } +}