diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b02cf8af5aa..7306064b140 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2013-11-04 Jakub Jelinek + + PR tree-optimization/58946 + * tree-ssa-reassoc.c (maybe_optimize_range_tests): Update all + bbs with bbinfo[idx].op != NULL before all blocks with + bbinfo[idx].op == NULL. + 2013-11-04 Richard Sandiford * config/avr/avr-log.c (avr_double_int_pop_digit): Delete. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 19e5c3803fc..ad988239b38 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-11-04 Jakub Jelinek + + PR tree-optimization/58946 + * gcc.c-torture/compile/pr58946.c: New test. + 2013-11-03 Paolo Carlini PR c++/52071 diff --git a/gcc/testsuite/gcc.c-torture/compile/pr58946.c b/gcc/testsuite/gcc.c-torture/compile/pr58946.c new file mode 100644 index 00000000000..0ec5eba16f0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr58946.c @@ -0,0 +1,20 @@ +/* PR tree-optimization/58946 */ + +int +foo (unsigned int c) +{ + unsigned int d, e, f; + if ((int) c < 0) + d = 0; + else + d = c; + if (d == 0) + e = __INT_MAX__ + 1U; + else + e = d; + if ((int) e < 0) + f = 0; + else + f = e; + return f; +} diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 39982f1a8d3..538a8ef0e4a 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -2657,6 +2657,7 @@ maybe_optimize_range_tests (gimple stmt) edge e; vec ops = vNULL; vec bbinfo = vNULL; + bool any_changes = false; /* Consider only basic blocks that end with GIMPLE_COND or a cast statement satisfying final_range_test_p. All @@ -2870,41 +2871,31 @@ maybe_optimize_range_tests (gimple stmt) break; } if (ops.length () > 1) + any_changes = optimize_range_tests (ERROR_MARK, &ops); + if (any_changes) { unsigned int idx; - bool any_changes = optimize_range_tests (ERROR_MARK, &ops); - for (bb = last_bb, idx = 0; any_changes; bb = single_pred (bb), idx++) + /* update_ops relies on has_single_use predicates returning the + same values as it did during get_ops earlier. Additionally it + never removes statements, only adds new ones and it should walk + from the single imm use and check the predicate already before + making those changes. + On the other side, the handling of GIMPLE_COND directly can turn + previously multiply used SSA_NAMEs into single use SSA_NAMEs, so + it needs to be done in a separate loop afterwards. */ + for (bb = last_bb, idx = 0; ; bb = single_pred (bb), idx++) { - if (bbinfo[idx].first_idx < bbinfo[idx].last_idx) + if (bbinfo[idx].first_idx < bbinfo[idx].last_idx + && bbinfo[idx].op != NULL_TREE) { - gimple stmt = last_stmt (bb); tree new_op; - if (bbinfo[idx].op == NULL_TREE) - { - if (ops[bbinfo[idx].first_idx]->op != NULL_TREE) - { - if (integer_zerop (ops[bbinfo[idx].first_idx]->op)) - gimple_cond_make_false (stmt); - else if (integer_onep (ops[bbinfo[idx].first_idx]->op)) - gimple_cond_make_true (stmt); - else - { - gimple_cond_set_code (stmt, NE_EXPR); - gimple_cond_set_lhs (stmt, - ops[bbinfo[idx].first_idx]->op); - gimple_cond_set_rhs (stmt, boolean_false_node); - } - update_stmt (stmt); - } - bbinfo[idx].op = new_op = boolean_false_node; - } - else - new_op = update_ops (bbinfo[idx].op, - (enum tree_code) - ops[bbinfo[idx].first_idx]->rank, - ops, &bbinfo[idx].first_idx, - loop_containing_stmt (stmt)); + stmt = last_stmt (bb); + new_op = update_ops (bbinfo[idx].op, + (enum tree_code) + ops[bbinfo[idx].first_idx]->rank, + ops, &bbinfo[idx].first_idx, + loop_containing_stmt (stmt)); if (new_op == NULL_TREE) { gcc_assert (bb == last_bb); @@ -2956,6 +2947,28 @@ maybe_optimize_range_tests (gimple stmt) if (bb == first_bb) break; } + for (bb = last_bb, idx = 0; ; bb = single_pred (bb), idx++) + { + if (bbinfo[idx].first_idx < bbinfo[idx].last_idx + && bbinfo[idx].op == NULL_TREE + && ops[bbinfo[idx].first_idx]->op != NULL_TREE) + { + stmt = last_stmt (bb); + if (integer_zerop (ops[bbinfo[idx].first_idx]->op)) + gimple_cond_make_false (stmt); + else if (integer_onep (ops[bbinfo[idx].first_idx]->op)) + gimple_cond_make_true (stmt); + else + { + gimple_cond_set_code (stmt, NE_EXPR); + gimple_cond_set_lhs (stmt, ops[bbinfo[idx].first_idx]->op); + gimple_cond_set_rhs (stmt, boolean_false_node); + } + update_stmt (stmt); + } + if (bb == first_bb) + break; + } } bbinfo.release (); ops.release ();