backport: re PR tree-optimization/81388 (Incorrect code generation with -O1)
Backport from 2017-07-20 trunk r250384. PR tree-optimization/81388 Revert r238585: 2016-07-21 Bin Cheng <bin.cheng@arm.com> * tree-ssa-loop-niter.c (number_of_iterations_lt_to_ne): Clean up by removing computation of may_be_zero. gcc/testsuite PR tree-optimization/81388 * gcc.dg/tree-ssa/pr81388-1.c: New test. * gcc.dg/tree-ssa/pr81388-2.c: New test. From-SVN: r250497
This commit is contained in:
parent
cc30cfd553
commit
16ac9369b0
|
@ -1,3 +1,14 @@
|
||||||
|
2017-07-25 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
Backport from 2017-07-20 trunk r250384.
|
||||||
|
|
||||||
|
PR tree-optimization/81388
|
||||||
|
Revert r238585:
|
||||||
|
2016-07-21 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
* tree-ssa-loop-niter.c (number_of_iterations_lt_to_ne): Clean up
|
||||||
|
by removing computation of may_be_zero.
|
||||||
|
|
||||||
2017-07-23 Uros Bizjak <ubizjak@gmail.com>
|
2017-07-23 Uros Bizjak <ubizjak@gmail.com>
|
||||||
|
|
||||||
PR target/80569
|
PR target/80569
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
2017-07-25 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
Backport from 2017-07-20 trunk r250384.
|
||||||
|
|
||||||
|
PR tree-optimization/81388
|
||||||
|
* gcc.dg/tree-ssa/pr81388-1.c: New test.
|
||||||
|
* gcc.dg/tree-ssa/pr81388-2.c: New test.
|
||||||
|
|
||||||
2017-07-23 Uros Bizjak <ubizjak@gmail.com>
|
2017-07-23 Uros Bizjak <ubizjak@gmail.com>
|
||||||
|
|
||||||
PR target/80569
|
PR target/80569
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O2 -fno-strict-overflow -fdump-tree-ivcanon-details" } */
|
||||||
|
|
||||||
|
void bar();
|
||||||
|
void foo(char *dst)
|
||||||
|
{
|
||||||
|
char *const end = dst;
|
||||||
|
do {
|
||||||
|
bar();
|
||||||
|
dst += 2;
|
||||||
|
} while (dst < end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-tree-dump " zero if " "ivcanon" } } */
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O2 -fdump-tree-ivcanon-details" } */
|
||||||
|
|
||||||
|
void bar();
|
||||||
|
void foo(unsigned dst)
|
||||||
|
{
|
||||||
|
unsigned end = dst;
|
||||||
|
do {
|
||||||
|
bar();
|
||||||
|
dst += 2;
|
||||||
|
} while (dst < end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-tree-dump " zero if " "ivcanon" } } */
|
|
@ -1142,8 +1142,12 @@ number_of_iterations_lt_to_ne (tree type, affine_iv *iv0, affine_iv *iv1,
|
||||||
tree niter_type = TREE_TYPE (step);
|
tree niter_type = TREE_TYPE (step);
|
||||||
tree mod = fold_build2 (FLOOR_MOD_EXPR, niter_type, *delta, step);
|
tree mod = fold_build2 (FLOOR_MOD_EXPR, niter_type, *delta, step);
|
||||||
tree tmod;
|
tree tmod;
|
||||||
tree assumption = boolean_true_node, bound;
|
mpz_t mmod;
|
||||||
tree type1 = (POINTER_TYPE_P (type)) ? sizetype : type;
|
tree assumption = boolean_true_node, bound, noloop;
|
||||||
|
bool ret = false, fv_comp_no_overflow;
|
||||||
|
tree type1 = type;
|
||||||
|
if (POINTER_TYPE_P (type))
|
||||||
|
type1 = sizetype;
|
||||||
|
|
||||||
if (TREE_CODE (mod) != INTEGER_CST)
|
if (TREE_CODE (mod) != INTEGER_CST)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1151,51 +1155,96 @@ number_of_iterations_lt_to_ne (tree type, affine_iv *iv0, affine_iv *iv1,
|
||||||
mod = fold_build2 (MINUS_EXPR, niter_type, step, mod);
|
mod = fold_build2 (MINUS_EXPR, niter_type, step, mod);
|
||||||
tmod = fold_convert (type1, mod);
|
tmod = fold_convert (type1, mod);
|
||||||
|
|
||||||
|
mpz_init (mmod);
|
||||||
|
wi::to_mpz (mod, mmod, UNSIGNED);
|
||||||
|
mpz_neg (mmod, mmod);
|
||||||
|
|
||||||
/* If the induction variable does not overflow and the exit is taken,
|
/* If the induction variable does not overflow and the exit is taken,
|
||||||
then the computation of the final value does not overflow. There
|
then the computation of the final value does not overflow. This is
|
||||||
are three cases:
|
also obviously the case if the new final value is equal to the
|
||||||
1) The case if the new final value is equal to the current one.
|
current one. Finally, we postulate this for pointer type variables,
|
||||||
2) Induction varaible has pointer type, as the code cannot rely
|
as the code cannot rely on the object to that the pointer points being
|
||||||
on the object to that the pointer points being placed at the
|
placed at the end of the address space (and more pragmatically,
|
||||||
end of the address space (and more pragmatically,
|
TYPE_{MIN,MAX}_VALUE is not defined for pointers). */
|
||||||
TYPE_{MIN,MAX}_VALUE is not defined for pointers).
|
if (integer_zerop (mod) || POINTER_TYPE_P (type))
|
||||||
3) EXIT_MUST_BE_TAKEN is true, note it implies that the induction
|
fv_comp_no_overflow = true;
|
||||||
variable does not overflow. */
|
else if (!exit_must_be_taken)
|
||||||
if (!integer_zerop (mod) && !POINTER_TYPE_P (type) && !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))
|
if (integer_nonzerop (iv0->step))
|
||||||
{
|
{
|
||||||
/* The final value of the iv is iv1->base + MOD, assuming
|
/* The final value of the iv is iv1->base + MOD, assuming that this
|
||||||
that this computation does not overflow, and that
|
computation does not overflow, and that
|
||||||
iv0->base <= iv1->base + MOD. */
|
iv0->base <= iv1->base + MOD. */
|
||||||
|
if (!fv_comp_no_overflow)
|
||||||
|
{
|
||||||
bound = fold_build2 (MINUS_EXPR, type1,
|
bound = fold_build2 (MINUS_EXPR, type1,
|
||||||
TYPE_MAX_VALUE (type1), tmod);
|
TYPE_MAX_VALUE (type1), tmod);
|
||||||
assumption = fold_build2 (LE_EXPR, boolean_type_node,
|
assumption = fold_build2 (LE_EXPR, boolean_type_node,
|
||||||
iv1->base, bound);
|
iv1->base, bound);
|
||||||
|
if (integer_zerop (assumption))
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (mpz_cmp (mmod, bnds->below) < 0)
|
||||||
|
noloop = boolean_false_node;
|
||||||
|
else if (POINTER_TYPE_P (type))
|
||||||
|
noloop = fold_build2 (GT_EXPR, boolean_type_node,
|
||||||
|
iv0->base,
|
||||||
|
fold_build_pointer_plus (iv1->base, tmod));
|
||||||
|
else
|
||||||
|
noloop = fold_build2 (GT_EXPR, boolean_type_node,
|
||||||
|
iv0->base,
|
||||||
|
fold_build2 (PLUS_EXPR, type1,
|
||||||
|
iv1->base, tmod));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The final value of the iv is iv0->base - MOD, assuming
|
/* The final value of the iv is iv0->base - MOD, assuming that this
|
||||||
that this computation does not overflow, and that
|
computation does not overflow, and that
|
||||||
iv0->base - MOD <= iv1->base. */
|
iv0->base - MOD <= iv1->base. */
|
||||||
|
if (!fv_comp_no_overflow)
|
||||||
|
{
|
||||||
bound = fold_build2 (PLUS_EXPR, type1,
|
bound = fold_build2 (PLUS_EXPR, type1,
|
||||||
TYPE_MIN_VALUE (type1), tmod);
|
TYPE_MIN_VALUE (type1), tmod);
|
||||||
assumption = fold_build2 (GE_EXPR, boolean_type_node,
|
assumption = fold_build2 (GE_EXPR, boolean_type_node,
|
||||||
iv0->base, bound);
|
iv0->base, bound);
|
||||||
}
|
|
||||||
if (integer_zerop (assumption))
|
if (integer_zerop (assumption))
|
||||||
return false;
|
goto end;
|
||||||
else if (!integer_nonzerop (assumption))
|
}
|
||||||
niter->assumptions = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
|
if (mpz_cmp (mmod, bnds->below) < 0)
|
||||||
niter->assumptions, assumption);
|
noloop = boolean_false_node;
|
||||||
|
else if (POINTER_TYPE_P (type))
|
||||||
|
noloop = fold_build2 (GT_EXPR, boolean_type_node,
|
||||||
|
fold_build_pointer_plus (iv0->base,
|
||||||
|
fold_build1 (NEGATE_EXPR,
|
||||||
|
type1, tmod)),
|
||||||
|
iv1->base);
|
||||||
|
else
|
||||||
|
noloop = fold_build2 (GT_EXPR, boolean_type_node,
|
||||||
|
fold_build2 (MINUS_EXPR, type1,
|
||||||
|
iv0->base, tmod),
|
||||||
|
iv1->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Since we are transforming LT to NE and DELTA is constant, there
|
if (!integer_nonzerop (assumption))
|
||||||
is no need to compute may_be_zero because this loop must roll. */
|
niter->assumptions = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
|
||||||
|
niter->assumptions,
|
||||||
|
assumption);
|
||||||
|
if (!integer_zerop (noloop))
|
||||||
|
niter->may_be_zero = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
|
||||||
|
niter->may_be_zero,
|
||||||
|
noloop);
|
||||||
bounds_add (bnds, wi::to_widest (mod), type);
|
bounds_add (bnds, wi::to_widest (mod), type);
|
||||||
*delta = fold_build2 (PLUS_EXPR, niter_type, *delta, mod);
|
*delta = fold_build2 (PLUS_EXPR, niter_type, *delta, mod);
|
||||||
return true;
|
|
||||||
|
ret = true;
|
||||||
|
end:
|
||||||
|
mpz_clear (mmod);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add assertions to NITER that ensure that the control variable of the loop
|
/* Add assertions to NITER that ensure that the control variable of the loop
|
||||||
|
|
Loading…
Reference in New Issue