From: hubicka Date: Wed, 9 Jan 2013 15:10:43 +0000 (+0000) Subject: PR tree-optimiation/55875 X-Git-Tag: upstream/4.9.2~8194 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=64552007d8a577b79d9655c273e1c8f820dba9a4;p=platform%2Fupstream%2Flinaro-gcc.git PR tree-optimiation/55875 * gcc.c-torture/execute/pr55875.c: New testcase. * g++.dg/torture/pr55875.C: New testcase. * tree-ssa-loop-niter.c (number_of_iterations_cond): Add EVERY_ITERATION parameter. (number_of_iterations_exit): Check if exit is executed every iteration. (idx_infer_loop_bounds): Similarly here. (n_of_executions_at_most): Simplify to only test for cases where statement is dominated by the particular bound; handle correctly the "postdominance" test. (scev_probably_wraps_p): Use max loop iterations info as a global bound first. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@195054 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d76456f..01fb93c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2013-01-09 Jan Hubicka + + PR tree-optimiation/55875 + * tree-ssa-loop-niter.c (number_of_iterations_cond): Add + EVERY_ITERATION parameter. + (number_of_iterations_exit): Check if exit is executed every + iteration. + (idx_infer_loop_bounds): Similarly here. + (n_of_executions_at_most): Simplify + to only test for cases where statement is dominated by the + particular bound; handle correctly the "postdominance" + test. + (scev_probably_wraps_p): Use max loop iterations info + as a global bound first. + 2013-01-09 Nguyen Duy Dat Nick Clifton diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5b95a47..74d7ea4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2013-01-09 Jan Hubicka + + PR tree-optimiation/55875 + * gcc.c-torture/execute/pr55875.c: New testcase. + * g++.dg/torture/pr55875.C: New testcase. + 2013-01-09 Jakub Jelinek PR c/48418 diff --git a/gcc/testsuite/g++.dg/torture/pr55875.C b/gcc/testsuite/g++.dg/torture/pr55875.C new file mode 100644 index 0000000..faadf88 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr55875.C @@ -0,0 +1,55 @@ +// { dg-do run } + +struct A +{ + short int a1; + unsigned char a2; + unsigned int a3; +}; + +struct B +{ + unsigned short b1; + const A *b2; +}; + +B b; + +__attribute__((noinline, noclone)) +int foo (unsigned x) +{ + __asm volatile ("" : "+r" (x) : : "memory"); + return x; +} + +inline void +bar (const int &) +{ +} + +__attribute__((noinline)) void +baz () +{ + const A *a = b.b2; + unsigned int i; + unsigned short n = b.b1; + for (i = 0; i < n; ++i) + if (a[i].a1 == 11) + { + if (i > 0 && (a[i - 1].a2 & 1)) + continue; + bar (foo (2)); + return; + } +} + +int +main () +{ + A a[4] = { { 10, 0, 0 }, { 11, 1, 0 }, { 11, 1, 0 }, { 11, 1, 0 } }; + b.b1 = 4; + b.b2 = a; + baz (); + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/pr55875.c b/gcc/testsuite/gcc.c-torture/execute/pr55875.c new file mode 100644 index 0000000..4a0ce1b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr55875.c @@ -0,0 +1,17 @@ +int a[250]; +__attribute__ ((noinline)) +t(int i) +{ + if (i==0) + exit(0); + if (i>255) + abort (); +} +main() +{ + unsigned int i; + for (i=0;;i++) + { + a[i]=t((unsigned char)(i+5)); + } +} diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c index 7a15ff82..fe2bbc1 100644 --- a/gcc/tree-ssa-loop-niter.c +++ b/gcc/tree-ssa-loop-niter.c @@ -1208,6 +1208,8 @@ dump_affine_iv (FILE *file, affine_iv *iv) -- in this case we can use the information whether the control induction variables can overflow or not in a more efficient way. + if EVERY_ITERATION is true, we know the test is executed on every iteration. + The results (number of iterations and assumptions as described in comments at struct tree_niter_desc in tree-flow.h) are stored to NITER. Returns false if it fails to determine number of iterations, true if it @@ -1217,11 +1219,21 @@ static bool number_of_iterations_cond (struct loop *loop, tree type, affine_iv *iv0, enum tree_code code, affine_iv *iv1, struct tree_niter_desc *niter, - bool only_exit) + bool only_exit, bool every_iteration) { bool exit_must_be_taken = false, ret; bounds bnds; + /* If the test is not executed every iteration, wrapping may make the test + to pass again. + TODO: the overflow case can be still used as unreliable estimate of upper + bound. But we have no API to pass it down to number of iterations code + and, at present, it will not use it anyway. */ + if (!every_iteration + && (!iv0->no_overflow || !iv1->no_overflow + || code == NE_EXPR || code == EQ_EXPR)) + return false; + /* The meaning of these assumptions is this: if !assumptions then the rest of information does not have to be valid @@ -1807,9 +1819,11 @@ number_of_iterations_exit (struct loop *loop, edge exit, tree op0, op1; enum tree_code code; affine_iv iv0, iv1; + bool safe; - if (every_iteration - && !dominated_by_p (CDI_DOMINATORS, loop->latch, exit->src)) + safe = dominated_by_p (CDI_DOMINATORS, loop->latch, exit->src); + + if (every_iteration && !safe) return false; niter->assumptions = boolean_false_node; @@ -1826,9 +1840,9 @@ number_of_iterations_exit (struct loop *loop, edge exit, { case GT_EXPR: case GE_EXPR: - case NE_EXPR: case LT_EXPR: case LE_EXPR: + case NE_EXPR: break; default: @@ -1855,7 +1869,7 @@ number_of_iterations_exit (struct loop *loop, edge exit, iv0.base = expand_simple_operations (iv0.base); iv1.base = expand_simple_operations (iv1.base); if (!number_of_iterations_cond (loop, type, &iv0, code, &iv1, niter, - loop_only_exit_p (loop, exit))) + loop_only_exit_p (loop, exit), safe)) { fold_undefer_and_ignore_overflow_warnings (); return false; @@ -2657,6 +2671,7 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta) tree low, high, type, next; bool sign, upper = true, at_end = false; struct loop *loop = data->loop; + bool reliable = true; if (TREE_CODE (base) != ARRAY_REF) return true; @@ -2728,7 +2743,14 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta) && tree_int_cst_compare (next, high) <= 0) return true; - record_nonwrapping_iv (loop, init, step, data->stmt, low, high, true, upper); + /* If access is not executed on every iteration, we must ensure that overlow may + not make the access valid later. */ + if (!dominated_by_p (CDI_DOMINATORS, loop->latch, gimple_bb (data->stmt)) + && scev_probably_wraps_p (initial_condition_in_loop_num (ev, loop->num), + step, data->stmt, loop, true)) + reliable = false; + + record_nonwrapping_iv (loop, init, step, data->stmt, low, high, reliable, upper); return true; } @@ -3549,8 +3571,15 @@ stmt_dominates_stmt_p (gimple s1, gimple s2) /* Returns true when we can prove that the number of executions of STMT in the loop is at most NITER, according to the bound on the number of executions of the statement NITER_BOUND->stmt recorded in - NITER_BOUND. If STMT is NULL, we must prove this bound for all - statements in the loop. */ + NITER_BOUND and fact that NITER_BOUND->stmt dominate STMT. + + ??? This code can become quite a CPU hog - we can have many bounds, + and large basic block forcing stmt_dominates_stmt_p to be queried + many times on a large basic blocks, so the whole thing is O(n^2) + for scev_probably_wraps_p invocation (that can be done n times). + + It would make more sense (and give better answers) to remember BB + bounds computed by discover_iteration_bound_by_body_walk. */ static bool n_of_executions_at_most (gimple stmt, @@ -3571,32 +3600,43 @@ n_of_executions_at_most (gimple stmt, /* We know that NITER_BOUND->stmt is executed at most NITER_BOUND->bound + 1 times. This means that: - -- if NITER_BOUND->is_exit is true, then everything before - NITER_BOUND->stmt is executed at most NITER_BOUND->bound + 1 - times, and everything after it at most NITER_BOUND->bound times. + -- if NITER_BOUND->is_exit is true, then everything after + it at most NITER_BOUND->bound times. -- If NITER_BOUND->is_exit is false, then if we can prove that when STMT is executed, then NITER_BOUND->stmt is executed as well in the same - iteration (we conclude that if both statements belong to the same - basic block, or if STMT is after NITER_BOUND->stmt), then STMT - is executed at most NITER_BOUND->bound + 1 times. Otherwise STMT is - executed at most NITER_BOUND->bound + 2 times. */ + iteration then STMT is executed at most NITER_BOUND->bound + 1 times. + + If we can determine that NITER_BOUND->stmt is always executed + after STMT, then STMT is executed at most NITER_BOUND->bound + 2 times. + We conclude that if both statements belong to the same + basic block and STMT is before NITER_BOUND->stmt and there are no + statements with side effects in between. */ if (niter_bound->is_exit) { - if (stmt - && stmt != niter_bound->stmt - && stmt_dominates_stmt_p (niter_bound->stmt, stmt)) - cmp = GE_EXPR; - else - cmp = GT_EXPR; + if (stmt == niter_bound->stmt + || !stmt_dominates_stmt_p (niter_bound->stmt, stmt)) + return false; + cmp = GE_EXPR; } else { - if (!stmt - || (gimple_bb (stmt) != gimple_bb (niter_bound->stmt) - && !stmt_dominates_stmt_p (niter_bound->stmt, stmt))) + if (!stmt_dominates_stmt_p (niter_bound->stmt, stmt)) { + gimple_stmt_iterator bsi; + if (gimple_bb (stmt) != gimple_bb (niter_bound->stmt) + || gimple_code (stmt) == GIMPLE_PHI + || gimple_code (niter_bound->stmt) == GIMPLE_PHI) + return false; + + /* By stmt_dominates_stmt_p we already know that STMT appears + before NITER_BOUND->STMT. Still need to test that the loop + can not be terinated by a side effect in between. */ + for (bsi = gsi_for_stmt (stmt); gsi_stmt (bsi) != niter_bound->stmt; + gsi_next (&bsi)) + if (gimple_has_side_effects (gsi_stmt (bsi))) + return false; bound += double_int_one; if (bound.is_zero () || !double_int_fits_to_tree_p (nit_type, bound)) @@ -3640,10 +3680,12 @@ scev_probably_wraps_p (tree base, tree step, gimple at_stmt, struct loop *loop, bool use_overflow_semantics) { - struct nb_iter_bound *bound; tree delta, step_abs; tree unsigned_type, valid_niter; tree type = TREE_TYPE (step); + tree e; + double_int niter; + struct nb_iter_bound *bound; /* FIXME: We really need something like http://gcc.gnu.org/ml/gcc-patches/2005-06/msg02025.html. @@ -3706,14 +3748,26 @@ scev_probably_wraps_p (tree base, tree step, valid_niter = fold_build2 (FLOOR_DIV_EXPR, unsigned_type, delta, step_abs); estimate_numbers_of_iterations_loop (loop); - for (bound = loop->bounds; bound; bound = bound->next) + + if (max_loop_iterations (loop, &niter) + && double_int_fits_to_tree_p (TREE_TYPE (valid_niter), niter) + && (e = fold_binary (GT_EXPR, boolean_type_node, valid_niter, + double_int_to_tree (TREE_TYPE (valid_niter), + niter))) != NULL + && integer_nonzerop (e)) { - if (n_of_executions_at_most (at_stmt, bound, valid_niter)) - { - fold_undefer_and_ignore_overflow_warnings (); - return false; - } + fold_undefer_and_ignore_overflow_warnings (); + return false; } + if (at_stmt) + for (bound = loop->bounds; bound; bound = bound->next) + { + if (n_of_executions_at_most (at_stmt, bound, valid_niter)) + { + fold_undefer_and_ignore_overflow_warnings (); + return false; + } + } fold_undefer_and_ignore_overflow_warnings ();