diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eb162f4a2b2..78f4cbc6ce7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2013-09-17 Jeff Law + + * tree-ssa-dom.c (cprop_into_successor_phis): Also propagate + edge implied equivalences into successor phis. + * tree-ssa-threadupdate.c (phi_args_equal_on_edges): Moved into + here from tree-ssa-threadedge.c. + (mark_threaded_blocks): When threading through a joiner, if both + successors of the joiner's clone reach the same block, verify the + PHI arguments are equal. If not, cancel the jump threading request. + * tree-ssa-threadedge.c (phi_args_equal_on_edges): Moved into + tree-ssa-threadupdate.c + (thread_across_edge): Don't check PHI argument equality when + threading through joiner block here. + 2013-09-17 Andrew MacLeod * tree-flow.h (ssa_undefined_value_p): Remove prototype. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a7b90f0a957..d51c300bd10 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2013-09-17 Jeff Law + + * gcc.c-torture/execute/pr58387.c: New test. + 2013-09-17 Kyrylo Tkachov PR tree-optimization/58088 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr58387.c b/gcc/testsuite/gcc.c-torture/execute/pr58387.c new file mode 100644 index 00000000000..74c32dfaf10 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr58387.c @@ -0,0 +1,11 @@ +extern void abort(void); + +int a = -1; + +int main () +{ + int b = a == 0 ? 0 : -a; + if (b < 1) + abort (); + return 0; +} diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index e02a56662b9..4a2b48bd93d 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -1235,7 +1235,7 @@ record_equivalences_from_incoming_edge (basic_block bb) /* If the conversion widens the original value and the constant is in the range of the type of OLD_RHS, - then convert the constant and record the equivalence. + then convert the constant and record the equivalence. Note that int_fits_type_p does not check the precision if the upper and lower bounds are OK. */ @@ -1642,6 +1642,28 @@ cprop_into_successor_phis (basic_block bb) if (gsi_end_p (gsi)) continue; + /* We may have an equivalence associated with this edge. While + we can not propagate it into non-dominated blocks, we can + propagate them into PHIs in non-dominated blocks. */ + + /* Push the unwind marker so we can reset the const and copies + table back to its original state after processing this edge. */ + const_and_copies_stack.safe_push (NULL_TREE); + + /* Extract and record any simple NAME = VALUE equivalences. + + Don't bother with [01] = COND equivalences, they're not useful + here. */ + struct edge_info *edge_info = (struct edge_info *) e->aux; + if (edge_info) + { + tree lhs = edge_info->lhs; + tree rhs = edge_info->rhs; + + if (lhs && TREE_CODE (lhs) == SSA_NAME) + record_const_or_copy (lhs, rhs); + } + indx = e->dest_idx; for ( ; !gsi_end_p (gsi); gsi_next (&gsi)) { @@ -1667,6 +1689,8 @@ cprop_into_successor_phis (basic_block bb) && may_propagate_copy (orig_val, new_val)) propagate_value (orig_p, new_val); } + + restore_vars_to_original_value (); } } diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 42474f16bb8..47db2804117 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -841,28 +841,6 @@ thread_around_empty_blocks (edge taken_edge, return false; } -/* E1 and E2 are edges into the same basic block. Return TRUE if the - PHI arguments associated with those edges are equal or there are no - PHI arguments, otherwise return FALSE. */ - -static bool -phi_args_equal_on_edges (edge e1, edge e2) -{ - gimple_stmt_iterator gsi; - int indx1 = e1->dest_idx; - int indx2 = e2->dest_idx; - - for (gsi = gsi_start_phis (e1->dest); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple phi = gsi_stmt (gsi); - - if (!operand_equal_p (gimple_phi_arg_def (phi, indx1), - gimple_phi_arg_def (phi, indx2), 0)) - return false; - } - return true; -} - /* We are exiting E->src, see if E->dest ends with a conditional jump which has a known value when reached via E. @@ -1021,18 +999,9 @@ thread_across_edge (gimple dummy_cond, record the jump threading opportunity. */ if (found) { - edge tmp; - /* If there is already an edge from the block to be duplicated - (E2->src) to the final target (E3->dest), then make sure that - the PHI args associated with the edges E2 and E3 are the - same. */ - tmp = find_edge (taken_edge->src, path[path.length () - 1]->dest); - if (!tmp || phi_args_equal_on_edges (tmp, path[path.length () - 1])) - { - propagate_threaded_block_debug_into (path[path.length () - 1]->dest, - taken_edge->dest); - register_jump_thread (path, true); - } + propagate_threaded_block_debug_into (path[path.length () - 1]->dest, + taken_edge->dest); + register_jump_thread (path, true); } path.release(); diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index d75526643b0..413112814d6 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -1147,6 +1147,28 @@ fail: return false; } +/* E1 and E2 are edges into the same basic block. Return TRUE if the + PHI arguments associated with those edges are equal or there are no + PHI arguments, otherwise return FALSE. */ + +static bool +phi_args_equal_on_edges (edge e1, edge e2) +{ + gimple_stmt_iterator gsi; + int indx1 = e1->dest_idx; + int indx2 = e2->dest_idx; + + for (gsi = gsi_start_phis (e1->dest); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple phi = gsi_stmt (gsi); + + if (!operand_equal_p (gimple_phi_arg_def (phi, indx1), + gimple_phi_arg_def (phi, indx2), 0)) + return false; + } + return true; +} + /* Walk through the registered jump threads and convert them into a form convenient for this pass. @@ -1219,6 +1241,46 @@ mark_threaded_blocks (bitmap threaded_blocks) } } + /* If we have a joiner block (J) which has two successors S1 and S2 and + we are threading though S1 and the final destination of the thread + is S2, then we must verify that any PHI nodes in S2 have the same + PHI arguments for the edge J->S2 and J->S1->...->S2. + + We used to detect this prior to registering the jump thread, but + that prohibits propagation of edge equivalences into non-dominated + PHI nodes as the equivalency test might occur before propagation. + + This works for now, but will need improvement as part of the FSA + optimization. + + Note since we've moved the thread request data to the edges, + we have to iterate on those rather than the threaded_edges vector. */ + EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi) + { + bb = BASIC_BLOCK (i); + FOR_EACH_EDGE (e, ei, bb->preds) + { + if (e->aux) + { + bool have_joiner = THREAD_TARGET2 (e) != NULL; + + if (have_joiner) + { + basic_block joiner = e->dest; + edge final_edge = THREAD_TARGET2 (e); + basic_block final_dest = final_edge->dest; + edge e2 = find_edge (joiner, final_dest); + + if (e2 && !phi_args_equal_on_edges (e2, final_edge)) + { + free (e->aux); + e->aux = NULL; + } + } + } + } + } + /* If optimizing for size, only thread through block if we don't have to duplicate it or it's an otherwise empty redirection block. */