The following fixes CH - FRE - LIM not doing store-motion across a loop nest for redundant header checks. FRE is supposed to do such redundant comparison "threading" but didn't do it because of latch edges confusing the single_pred_p check.
The following fixes it by disregarding edges that come from blocks we dominate. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2015-11-23 Richard Biener <rguent...@suse.de> PR tree-optimization/68465 * tree-ssa-sccvn.c (sccvn_dom_walker::before_dom_children): Also record equalities from multiple predecessor blocks if only one non-backedge exists. * gcc.dg/tree-ssa/ssa-fre-52.c: New testcase. Index: gcc/tree-ssa-sccvn.c =================================================================== *** gcc/tree-ssa-sccvn.c (revision 230737) --- gcc/tree-ssa-sccvn.c (working copy) *************** sccvn_dom_walker::before_dom_children (b *** 4357,4376 **** /* If we have a single predecessor record the equivalence from a possible condition on the predecessor edge. */ ! if (single_pred_p (bb)) { - edge e = single_pred_edge (bb); /* Check if there are multiple executable successor edges in the source block. Otherwise there is no additional info to be recorded. */ edge e2; ! FOR_EACH_EDGE (e2, ei, e->src->succs) ! if (e2 != e && e2->flags & EDGE_EXECUTABLE) break; if (e2 && (e2->flags & EDGE_EXECUTABLE)) { ! gimple *stmt = last_stmt (e->src); if (stmt && gimple_code (stmt) == GIMPLE_COND) { --- 4402,4435 ---- /* If we have a single predecessor record the equivalence from a possible condition on the predecessor edge. */ ! edge pred_e = NULL; ! FOR_EACH_EDGE (e, ei, bb->preds) ! { ! /* Ignore simple backedges from this to allow recording conditions ! in loop headers. */ ! if (dominated_by_p (CDI_DOMINATORS, e->src, e->dest)) ! continue; ! if (! pred_e) ! pred_e = e; ! else ! { ! pred_e = NULL; ! break; ! } ! } ! if (pred_e) { /* Check if there are multiple executable successor edges in the source block. Otherwise there is no additional info to be recorded. */ edge e2; ! FOR_EACH_EDGE (e2, ei, pred_e->src->succs) ! if (e2 != pred_e && e2->flags & EDGE_EXECUTABLE) break; if (e2 && (e2->flags & EDGE_EXECUTABLE)) { ! gimple *stmt = last_stmt (pred_e->src); if (stmt && gimple_code (stmt) == GIMPLE_COND) { *************** sccvn_dom_walker::before_dom_children (b *** 4378,4388 **** tree lhs = gimple_cond_lhs (stmt); tree rhs = gimple_cond_rhs (stmt); record_conds (bb, code, lhs, rhs, ! (e->flags & EDGE_TRUE_VALUE) != 0); code = invert_tree_comparison (code, HONOR_NANS (lhs)); if (code != ERROR_MARK) record_conds (bb, code, lhs, rhs, ! (e->flags & EDGE_TRUE_VALUE) == 0); } } } --- 4437,4447 ---- tree lhs = gimple_cond_lhs (stmt); tree rhs = gimple_cond_rhs (stmt); record_conds (bb, code, lhs, rhs, ! (pred_e->flags & EDGE_TRUE_VALUE) != 0); code = invert_tree_comparison (code, HONOR_NANS (lhs)); if (code != ERROR_MARK) record_conds (bb, code, lhs, rhs, ! (pred_e->flags & EDGE_TRUE_VALUE) == 0); } } } Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-52.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-52.c (revision 0) --- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-52.c (working copy) *************** *** 0 **** --- 1,26 ---- + /* { dg-do compile } */ + /* { dg-options "-O -fdump-tree-fre1" } */ + + void bar (); + void foo (int n) + { + if (n > 0) + { + int j = 0; + do + { + if (n > 0) + { + int i = 0; + do + { + bar (); + } + while (i < n); + } + } + while (j < n); + } + } + + /* { dg-final { scan-tree-dump-times "if" 1 "fre1" } } */