The following fixes issues that arise when a SSA propagator ends up deciding only a single outgoing edge is executable but the folder at substitute-and-fold time decides the other one is executable. This can of course only happen with undefined behavior (or with bugs...). In this case the propagator (copyprop) sees a condition if (0 > unsigned-var) and decides this always evaluates to false. But fold, given more context and being inherently more powerful than a simple copyprop sees that unsigned-var is actually 0 % 0 and 0 > 0 % 0 evaluates to true (because we have that match.pd pattern saying that X % Y is smaller than Y which is a valid answer considering that % 0 invokes undefined behavior).
Rather than trying to fix this by conditionalizing that pattern against a zero modulo I decided that of course what the propagator things of edge executability has to agree with what fold produces, thus we just force the propagators idea. Otherwise you run into this testcases issue where the lattice contains a value that is computed in the path that fold now decides to delete. Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2015-07-22 Richard Biener <rguent...@suse.de> PR tree-optimization/66945 * tree-ssa-propagate.c (substitute_and_fold_dom_walker ::before_dom_children): Force the propagators idea of non-executable edges to materialize, not what the folder chooses. * gcc.dg/torture/pr66945.c: New testcase. Index: gcc/tree-ssa-propagate.c =================================================================== --- gcc/tree-ssa-propagate.c (revision 226042) +++ gcc/tree-ssa-propagate.c (working copy) @@ -1236,13 +1236,33 @@ substitute_and_fold_dom_walker::before_d /* If we made a replacement, fold the statement. */ if (did_replace) - fold_stmt (&i, follow_single_use_edges); + { + fold_stmt (&i, follow_single_use_edges); + stmt = gsi_stmt (i); + } + + /* If this is a control statement the propagator left edges + unexecuted on force the condition in a way consistent with + that. See PR66945 for cases where the propagator can end + up with a different idea of a taken edge than folding + (once undefined behavior is involved). */ + if (gimple_code (stmt) == GIMPLE_COND) + { + if ((EDGE_SUCC (bb, 0)->flags & EDGE_EXECUTABLE) + ^ (EDGE_SUCC (bb, 1)->flags & EDGE_EXECUTABLE)) + { + if (((EDGE_SUCC (bb, 0)->flags & EDGE_TRUE_VALUE) != 0) + == ((EDGE_SUCC (bb, 0)->flags & EDGE_EXECUTABLE) != 0)) + gimple_cond_make_true (as_a <gcond *> (stmt)); + else + gimple_cond_make_false (as_a <gcond *> (stmt)); + did_replace = true; + } + } /* Now cleanup. */ if (did_replace) { - stmt = gsi_stmt (i); - /* If we cleaned up EH information from the statement, remove EH edges. */ if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)) Index: gcc/testsuite/gcc.dg/torture/pr66945.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr66945.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr66945.c (working copy) @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +unsigned b; +void f() +{ + for(;;) + if(!b?:(b=0)) + ; + else if(b%0<b?:b) /* { dg-warning "division by zero" } */ + for(;;) + ; +}