The following fixes a long-standing bug in tree if-conversion. The transform phase relies on being able to extract edge predicates by simply using the predicate under which its source block is executed. That obviously isn't the correct one if the source block ends in a condition itself. Thus the following patch verifies that each predecessor edge of blocks we will if-convert is non-critical.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2013-06-24 Richard Biener <rguent...@suse.de> PR tree-optimization/57521 * tree-if-conv.c (if_convertible_bb_p): Verify that all edges are non-critical. (pass_if_conversion): Add TODO_verify_ssa. * gcc.dg/torture/pr57521.c: New testcase. Index: gcc/tree-if-conv.c =================================================================== *** gcc/tree-if-conv.c (revision 200367) --- gcc/tree-if-conv.c (working copy) *************** if_convertible_bb_p (struct loop *loop, *** 873,878 **** --- 873,886 ---- && !bb_postdominates_preds (bb)) return false; + /* All incoming edges have to be non-critical as otherwise edge + predicates are not equal to basic-block predicates of the edge + source. */ + if (EDGE_COUNT (bb->preds) > 1) + FOR_EACH_EDGE (e, ei, bb->preds) + if (EDGE_COUNT (e->src->succs) > 1) + return false; + return true; } *************** struct gimple_opt_pass pass_if_conversio *** 1870,1875 **** 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_verify_stmts | TODO_verify_flow ! /* todo_flags_finish */ } }; --- 1878,1883 ---- 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_verify_stmts | TODO_verify_flow ! | TODO_verify_ssa /* todo_flags_finish */ } }; Index: gcc/testsuite/gcc.dg/torture/pr57521.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr57521.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr57521.c (working copy) *************** *** 0 **** --- 1,51 ---- + /* { dg-do run } */ + /* { dg-options "-ftree-loop-if-convert" } */ + + void abort (void); + + int a, b, c, d, o = 1, p; + short e; + + int + fn1 (int * p1) + { + int f, g, h, j = 0, k = 0, l = 0; + unsigned int i; + int *m[1] = { &l }; + for (; b >= 0; b--) + { + if (*p1) + if (j >= 0) + { + int n = 1; + e = 1; + h = a ? a : 1 % n; + g = h > 0 ? 0 : h + 1; + k = c + g; + } + else + continue; + else + { + + f = d > 0 ? 0 : d + 1; + i = f; + j = 1 + i; + } + l++; + } + return k; + } + + int + main () + { + for (;; p++) + { + fn1 (&o); + break; + } + if (e != 1) + abort (); + return 0; + }