The following fixes PR57343 - niter analysis uses multiple_of_p to check whether a value is a multiple of another, but multiple_of_p does not refrain from returning true for a * 10 and 10 even when the multiplication may overflow (and changing that would pessimize some callers at least while possibly fixing a latent bug in extract_mul_div). So the following guards the use of multiple_of_p in niter analysis properly and implements the important special-cases for wrapping types.
Bootstrapped and tested on x86_64-unknown-linux-gnu, ok for trunk? Thanks, Richard. 2013-05-27 Richard Biener <rguent...@suse.de> PR tree-optimization/57343 * tree-ssa-loop-niter.c (number_of_iterations_ne_max): Do not use multiple_of_p if not TYPE_OVERFLOW_UNDEFINED. (number_of_iterations_cond): Do not build the folded tree. * gcc.dg/torture/pr57343.c: New testcase. Index: gcc/tree-ssa-loop-niter.c =================================================================== *** gcc/tree-ssa-loop-niter.c (revision 199350) --- gcc/tree-ssa-loop-niter.c (working copy) *************** number_of_iterations_ne_max (mpz_t bnd, *** 552,561 **** { double_int max; mpz_t d; bool bnds_u_valid = ((no_overflow && exit_must_be_taken) || mpz_sgn (bnds->below) >= 0); ! if (multiple_of_p (TREE_TYPE (c), c, s)) { /* If C is an exact multiple of S, then its value will be reached before the induction variable overflows (unless the loop is exited in some --- 552,569 ---- { double_int max; mpz_t d; + tree type = TREE_TYPE (c); bool bnds_u_valid = ((no_overflow && exit_must_be_taken) || mpz_sgn (bnds->below) >= 0); ! if (integer_onep (s) ! || (TREE_CODE (c) == INTEGER_CST ! && TREE_CODE (s) == INTEGER_CST ! && tree_to_double_int (c).mod (tree_to_double_int (s), ! TYPE_UNSIGNED (type), ! EXACT_DIV_EXPR).is_zero ()) ! || (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (c)) ! && multiple_of_p (type, c, s))) { /* If C is an exact multiple of S, then its value will be reached before the induction variable overflows (unless the loop is exited in some *************** number_of_iterations_ne_max (mpz_t bnd, *** 572,587 **** the whole # of iterations analysis will fail). */ if (!no_overflow) { ! max = double_int::mask (TYPE_PRECISION (TREE_TYPE (c)) ! - tree_low_cst (num_ending_zeros (s), 1)); mpz_set_double_int (bnd, max, true); return; } /* Now we know that the induction variable does not overflow, so the loop iterates at most (range of type / S) times. */ ! mpz_set_double_int (bnd, double_int::mask (TYPE_PRECISION (TREE_TYPE (c))), ! true); /* If the induction variable is guaranteed to reach the value of C before overflow, ... */ --- 580,594 ---- the whole # of iterations analysis will fail). */ if (!no_overflow) { ! max = double_int::mask (TYPE_PRECISION (type) ! - tree_low_cst (num_ending_zeros (s), 1)); mpz_set_double_int (bnd, max, true); return; } /* Now we know that the induction variable does not overflow, so the loop iterates at most (range of type / S) times. */ ! mpz_set_double_int (bnd, double_int::mask (TYPE_PRECISION (type)), true); /* If the induction variable is guaranteed to reach the value of C before overflow, ... */ *************** number_of_iterations_cond (struct loop * *** 1311,1317 **** } /* If the loop exits immediately, there is nothing to do. */ ! if (integer_zerop (fold_build2 (code, boolean_type_node, iv0->base, iv1->base))) { niter->niter = build_int_cst (unsigned_type_for (type), 0); niter->max = double_int_zero; --- 1318,1325 ---- } /* If the loop exits immediately, there is nothing to do. */ ! tree tem = fold_binary (code, boolean_type_node, iv0->base, iv1->base); ! if (tem && integer_zerop (tem)) { niter->niter = build_int_cst (unsigned_type_for (type), 0); niter->max = double_int_zero; Index: gcc/testsuite/gcc.dg/torture/pr57343.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr57343.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr57343.c (working copy) *************** *** 0 **** --- 1,22 ---- + /* { dg-do run } */ + + int c = 0; + + int + main () + { + int i, f = 1; + for (i = 0; i < 5; i++) + { + --c; + unsigned char h = c * 100; + if (h == 0) + { + f = 0; + break; + } + } + if (f != 1) + __builtin_abort (); + return 0; + }