The following fixes a missed CFG cleanup opportunity (requiring its iteration) that ultimatively causes us to create a dead if-converted loop variant (discovered as dead by CFG cleanup run by ifcvt).
The issue is that when removing unreachable code CFG cleanup does not schedule predecessors of path exits for revisiting but only the path exit itself - this leads to a missed BB merging opportunity. Fixed by slightly re-organizing the BB merging code. Bootstrapped / tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2016-08-09 Richard Biener <rguent...@suse.de> PR tree-optimization/71802 * tree-cfgcleanup.c (cleanup_tree_cfg_bb): Make sure to catch all merge opportunities with the predecessor. * gcc.dg/torture/pr71802.c: New testcase. Index: gcc/tree-cfgcleanup.c =================================================================== *** gcc/tree-cfgcleanup.c (revision 239164) --- gcc/tree-cfgcleanup.c (working copy) *************** cleanup_tree_cfg_bb (basic_block bb) *** 641,664 **** && remove_forwarder_block (bb)) return true; /* Merging the blocks may create new opportunities for folding conditional branches (due to the elimination of single-valued PHI nodes). */ ! if (single_succ_p (bb) ! && can_merge_blocks_p (bb, single_succ (bb))) { ! /* If there is a merge opportunity with the predecessor ! do nothing now but wait until we process the predecessor. ! This happens when we visit BBs in a non-optimal order and ! avoids quadratic behavior with adjusting stmts BB pointer. */ ! if (single_pred_p (bb) ! && can_merge_blocks_p (single_pred (bb), bb)) ! ; ! else ! { ! merge_blocks (bb, single_succ (bb)); ! return true; ! } } return false; --- 641,665 ---- && remove_forwarder_block (bb)) return true; + /* If there is a merge opportunity with the predecessor + do nothing now but wait until we process the predecessor. + This happens when we visit BBs in a non-optimal order and + avoids quadratic behavior with adjusting stmts BB pointer. */ + if (single_pred_p (bb) + && can_merge_blocks_p (single_pred (bb), bb)) + /* But make sure we _do_ visit it. When we remove unreachable paths + ending in a backedge we fail to mark the destinations predecessors + as changed. */ + bitmap_set_bit (cfgcleanup_altered_bbs, single_pred (bb)->index); + /* Merging the blocks may create new opportunities for folding conditional branches (due to the elimination of single-valued PHI nodes). */ ! else if (single_succ_p (bb) ! && can_merge_blocks_p (bb, single_succ (bb))) { ! merge_blocks (bb, single_succ (bb)); ! return true; } return false; Index: gcc/testsuite/gcc.dg/torture/pr71802.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr71802.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr71802.c (working copy) *************** *** 0 **** --- 1,37 ---- + /* { dg-do compile } */ + + int b, c; + long d, f; + void fn1() + { + char g; + long long h = 0; + int *i; + if (0) { + L2: + b && (b = f); + d = 3; + for (; d;) { + char *j = &g; + c = *j = 0; + L3: + *j %= b; + for (; g <= 4;) + ; + } + goto L2; + } + for (; *i; *i = 1) { + if ((h -= 4) == (h != (b ?: d))) { + g = 3; + goto L3; + } + i = (int *)&h; + *i = f; + i = (int *)&f; + if ((h && 6) - (h = 0)) + goto L2; + } + for (; d;) + goto L3; + }