re PR tree-optimization/40087 (Number of iterations analysis wrong)

PR tree-optimization/40087
	* tree-ssa-loop-niter.c (number_of_iterations_ne_max,
	number_of_iterations_ne): Rename never_infinite argument.
	(number_of_iterations_lt_to_ne, number_of_iterations_lt,
	number_of_iterations_le): Handle pointer-type ivs when
	exit_must_be_taken is false.
	(number_of_iterations_cond):  Do not always assume that
	exit_must_be_taken if the control variable is a pointer.

	* gcc.dg/tree-ssa/pr40087.c: New test.

From-SVN: r147727
This commit is contained in:
Zdenek Dvorak 2009-05-20 02:33:54 +02:00 committed by Zdenek Dvorak
parent 03d33c2a44
commit e36dc33956
4 changed files with 102 additions and 53 deletions

View File

@ -1,3 +1,14 @@
2009-05-19 Zdenek Dvorak <ook@ucw.cz>
PR tree-optimization/40087
* tree-ssa-loop-niter.c (number_of_iterations_ne_max,
number_of_iterations_ne): Rename never_infinite argument.
(number_of_iterations_lt_to_ne, number_of_iterations_lt,
number_of_iterations_le): Handle pointer-type ivs when
exit_must_be_taken is false.
(number_of_iterations_cond): Do not always assume that
exit_must_be_taken if the control variable is a pointer.
2009-05-19 Andrew Pinski <andrew_pinski@playstation.sony.com>
* c-typeck.c (build_binary_op): Allow % on integal vectors.

View File

@ -1,3 +1,8 @@
2009-05-19 Zdenek Dvorak <ook@ucw.cz>
PR tree-optimization/40087
* gcc.dg/tree-ssa/pr40087.c: New test.
2009-05-19 Andrew Pinski <andrew_pinski@playstation.sony.com>
* gcc.dg/vector-4.c: New testcase.

View File

@ -0,0 +1,30 @@
/* { dg-do run } */
/* { dg-options "-O1 " } */
extern void abort (void);
static void __attribute__((always_inline))
reverse(int *first, int *last)
{
if (first == last--)
return;
while (first != last)
{
int t = *first;
*first = *last;
*last = t;
if (++first == last--)
break;
}
}
int main()
{
int seq[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
reverse(seq, seq + 8);
if (seq[3] != 5 || seq[4] != 4)
abort ();
return 0;
}

View File

@ -534,7 +534,7 @@ inverse (tree x, tree mask)
}
/* Derives the upper bound BND on the number of executions of loop with exit
condition S * i <> C, assuming that the loop is not infinite. If
condition S * i <> C, assuming that this exit is taken. If
NO_OVERFLOW is true, then the control variable of the loop does not
overflow. If NO_OVERFLOW is true or BNDS.below >= 0, then BNDS.up
contains the upper bound on the value of C. */
@ -574,7 +574,7 @@ number_of_iterations_ne_max (mpz_t bnd, bool no_overflow, tree c, tree s,
/* Determines number of iterations of loop whose ending condition
is IV <> FINAL. TYPE is the type of the iv. The number of
iterations is stored to NITER. NEVER_INFINITE is true if
iterations is stored to NITER. EXIT_MUST_BE_TAKEN is true if
we know that the exit must be taken eventually, i.e., that the IV
ever reaches the value FINAL (we derived this earlier, and possibly set
NITER->assumptions to make sure this is the case). BNDS contains the
@ -582,7 +582,7 @@ number_of_iterations_ne_max (mpz_t bnd, bool no_overflow, tree c, tree s,
static bool
number_of_iterations_ne (tree type, affine_iv *iv, tree final,
struct tree_niter_desc *niter, bool never_infinite,
struct tree_niter_desc *niter, bool exit_must_be_taken,
bounds *bnds)
{
tree niter_type = unsigned_type_for (type);
@ -639,9 +639,9 @@ number_of_iterations_ne (tree type, affine_iv *iv, tree final,
build_int_cst (niter_type, 1), bits);
s = fold_binary_to_constant (RSHIFT_EXPR, niter_type, s, bits);
if (!never_infinite)
if (!exit_must_be_taken)
{
/* If we cannot assume that the loop is not infinite, record the
/* If we cannot assume that the exit is taken eventually, record the
assumptions for divisibility of c. */
assumption = fold_build2 (FLOOR_MOD_EXPR, niter_type, c, d);
assumption = fold_build2 (EQ_EXPR, boolean_type_node,
@ -664,20 +664,21 @@ number_of_iterations_ne (tree type, affine_iv *iv, tree final,
of the final value does not overflow are recorded in NITER. If we
find the final value, we adjust DELTA and return TRUE. Otherwise
we return false. BNDS bounds the value of IV1->base - IV0->base,
and will be updated by the same amount as DELTA. */
and will be updated by the same amount as DELTA. EXIT_MUST_BE_TAKEN is
true if we know that the exit must be taken eventually. */
static bool
number_of_iterations_lt_to_ne (tree type, affine_iv *iv0, affine_iv *iv1,
struct tree_niter_desc *niter,
tree *delta, tree step,
bounds *bnds)
bool exit_must_be_taken, bounds *bnds)
{
tree niter_type = TREE_TYPE (step);
tree mod = fold_build2 (FLOOR_MOD_EXPR, niter_type, *delta, step);
tree tmod;
mpz_t mmod;
tree assumption = boolean_true_node, bound, noloop;
bool ret = false;
bool ret = false, fv_comp_no_overflow;
tree type1 = type;
if (POINTER_TYPE_P (type))
type1 = sizetype;
@ -692,17 +693,31 @@ number_of_iterations_lt_to_ne (tree type, affine_iv *iv0, affine_iv *iv1,
mpz_set_double_int (mmod, tree_to_double_int (mod), true);
mpz_neg (mmod, mmod);
/* If the induction variable does not overflow and the exit is taken,
then the computation of the final value does not overflow. This is
also obviously the case if the new final value is equal to the
current one. Finally, we postulate this for pointer type variables,
as the code cannot rely on the object to that the pointer points being
placed at the end of the address space (and more pragmatically,
TYPE_{MIN,MAX}_VALUE is not defined for pointers). */
if (integer_zerop (mod) || POINTER_TYPE_P (type))
fv_comp_no_overflow = true;
else if (!exit_must_be_taken)
fv_comp_no_overflow = false;
else
fv_comp_no_overflow =
(iv0->no_overflow && integer_nonzerop (iv0->step))
|| (iv1->no_overflow && integer_nonzerop (iv1->step));
if (integer_nonzerop (iv0->step))
{
/* The final value of the iv is iv1->base + MOD, assuming that this
computation does not overflow, and that
iv0->base <= iv1->base + MOD. */
if (!iv0->no_overflow && !integer_zerop (mod))
if (!fv_comp_no_overflow)
{
bound = fold_build2 (MINUS_EXPR, type1,
TYPE_MAX_VALUE (type1), tmod);
if (POINTER_TYPE_P (type))
bound = fold_convert (type, bound);
assumption = fold_build2 (LE_EXPR, boolean_type_node,
iv1->base, bound);
if (integer_zerop (assumption))
@ -726,12 +741,10 @@ number_of_iterations_lt_to_ne (tree type, affine_iv *iv0, affine_iv *iv1,
/* The final value of the iv is iv0->base - MOD, assuming that this
computation does not overflow, and that
iv0->base - MOD <= iv1->base. */
if (!iv1->no_overflow && !integer_zerop (mod))
if (!fv_comp_no_overflow)
{
bound = fold_build2 (PLUS_EXPR, type1,
TYPE_MIN_VALUE (type1), tmod);
if (POINTER_TYPE_P (type))
bound = fold_convert (type, bound);
assumption = fold_build2 (GE_EXPR, boolean_type_node,
iv0->base, bound);
if (integer_zerop (assumption))
@ -969,13 +982,13 @@ assert_loop_rolls_lt (tree type, affine_iv *iv0, affine_iv *iv1,
/* Determines number of iterations of loop whose ending condition
is IV0 < IV1. TYPE is the type of the iv. The number of
iterations is stored to NITER. BNDS bounds the difference
IV1->base - IV0->base. */
IV1->base - IV0->base. EXIT_MUST_BE_TAKEN is true if we know
that the exit must be taken eventually. */
static bool
number_of_iterations_lt (tree type, affine_iv *iv0, affine_iv *iv1,
struct tree_niter_desc *niter,
bool never_infinite ATTRIBUTE_UNUSED,
bounds *bnds)
bool exit_must_be_taken, bounds *bnds)
{
tree niter_type = unsigned_type_for (type);
tree delta, step, s;
@ -1034,7 +1047,7 @@ number_of_iterations_lt (tree type, affine_iv *iv0, affine_iv *iv1,
transform the condition to != comparison. In particular, this will be
the case if DELTA is constant. */
if (number_of_iterations_lt_to_ne (type, iv0, iv1, niter, &delta, step,
bnds))
exit_must_be_taken, bnds))
{
affine_iv zps;
@ -1076,14 +1089,14 @@ number_of_iterations_lt (tree type, affine_iv *iv0, affine_iv *iv1,
/* Determines number of iterations of loop whose ending condition
is IV0 <= IV1. TYPE is the type of the iv. The number of
iterations is stored to NITER. NEVER_INFINITE is true if
iterations is stored to NITER. EXIT_MUST_BE_TAKEN is true if
we know that this condition must eventually become false (we derived this
earlier, and possibly set NITER->assumptions to make sure this
is the case). BNDS bounds the difference IV1->base - IV0->base. */
static bool
number_of_iterations_le (tree type, affine_iv *iv0, affine_iv *iv1,
struct tree_niter_desc *niter, bool never_infinite,
struct tree_niter_desc *niter, bool exit_must_be_taken,
bounds *bnds)
{
tree assumption;
@ -1094,9 +1107,13 @@ number_of_iterations_le (tree type, affine_iv *iv0, affine_iv *iv1,
/* Say that IV0 is the control variable. Then IV0 <= IV1 iff
IV0 < IV1 + 1, assuming that IV1 is not equal to the greatest
value of the type. This we must know anyway, since if it is
equal to this value, the loop rolls forever. */
equal to this value, the loop rolls forever. We do not check
this condition for pointer type ivs, as the code cannot rely on
the object to that the pointer points being placed at the end of
the address space (and more pragmatically, TYPE_{MIN,MAX}_VALUE is
not defined for pointers). */
if (!never_infinite)
if (!exit_must_be_taken && !POINTER_TYPE_P (type))
{
if (integer_nonzerop (iv0->step))
assumption = fold_build2 (NE_EXPR, boolean_type_node,
@ -1131,7 +1148,8 @@ number_of_iterations_le (tree type, affine_iv *iv0, affine_iv *iv1,
bounds_add (bnds, double_int_one, type1);
return number_of_iterations_lt (type, iv0, iv1, niter, never_infinite, bnds);
return number_of_iterations_lt (type, iv0, iv1, niter, exit_must_be_taken,
bnds);
}
/* Dumps description of affine induction variable IV to FILE. */
@ -1177,7 +1195,7 @@ number_of_iterations_cond (struct loop *loop,
affine_iv *iv1, struct tree_niter_desc *niter,
bool only_exit)
{
bool never_infinite, ret;
bool exit_must_be_taken = false, ret;
bounds bnds;
/* The meaning of these assumptions is this:
@ -1202,42 +1220,27 @@ number_of_iterations_cond (struct loop *loop,
code = swap_tree_comparison (code);
}
if (!only_exit)
{
/* If this is not the only possible exit from the loop, the information
that the induction variables cannot overflow as derived from
signedness analysis cannot be relied upon. We use them e.g. in the
following way: given loop for (i = 0; i <= n; i++), if i is
signed, it cannot overflow, thus this loop is equivalent to
for (i = 0; i < n + 1; i++); however, if n == MAX, but the loop
is exited in some other way before i overflows, this transformation
is incorrect (the new loop exits immediately). */
iv0->no_overflow = false;
iv1->no_overflow = false;
}
if (POINTER_TYPE_P (type))
{
/* Comparison of pointers is undefined unless both iv0 and iv1 point
to the same object. If they do, the control variable cannot wrap
(as wrap around the bounds of memory will never return a pointer
that would be guaranteed to point to the same object, even if we
avoid undefined behavior by casting to size_t and back). The
restrictions on pointer arithmetics and comparisons of pointers
ensure that using the no-overflow assumptions is correct in this
case even if ONLY_EXIT is false. */
avoid undefined behavior by casting to size_t and back). */
iv0->no_overflow = true;
iv1->no_overflow = true;
}
/* If the control induction variable does not overflow, the loop obviously
cannot be infinite. */
if (!integer_zerop (iv0->step) && iv0->no_overflow)
never_infinite = true;
else if (!integer_zerop (iv1->step) && iv1->no_overflow)
never_infinite = true;
else
never_infinite = false;
/* If the control induction variable does not overflow and the only exit
from the loop is the one that we analyze, we know it must be taken
eventually. */
if (only_exit)
{
if (!integer_zerop (iv0->step) && iv0->no_overflow)
exit_must_be_taken = true;
else if (!integer_zerop (iv1->step) && iv1->no_overflow)
exit_must_be_taken = true;
}
/* We can handle the case when neither of the sides of the comparison is
invariant, provided that the test is NE_EXPR. This rarely occurs in
@ -1308,16 +1311,16 @@ number_of_iterations_cond (struct loop *loop,
case NE_EXPR:
gcc_assert (integer_zerop (iv1->step));
ret = number_of_iterations_ne (type, iv0, iv1->base, niter,
never_infinite, &bnds);
exit_must_be_taken, &bnds);
break;
case LT_EXPR:
ret = number_of_iterations_lt (type, iv0, iv1, niter, never_infinite,
ret = number_of_iterations_lt (type, iv0, iv1, niter, exit_must_be_taken,
&bnds);
break;
case LE_EXPR:
ret = number_of_iterations_le (type, iv0, iv1, niter, never_infinite,
ret = number_of_iterations_le (type, iv0, iv1, niter, exit_must_be_taken,
&bnds);
break;