Commit 9983270b by Diego Novillo Committed by Diego Novillo

re PR tree-optimization/22018 (VRP miscompiles multiply)


	PR 22018
	* tree-vrp.c (vrp_int_const_binop): New.
	(extract_range_from_binary_expr): Call it.
	Unify handling division and multiplication.

testsuite/ChangeLog:

	PR 22018
	* gcc.dg/tree-ssa/vrp13.c: Add multiplication tests.
	* gcc.dg/tree-ssa/pr22018.c: New test.

From-SVN: r100978
parent f6d7e7d8
2005-06-15 Diego Novillo <dnovillo@redhat.com>
PR 22018
* tree-vrp.c (vrp_int_const_binop): New.
(extract_range_from_binary_expr): Call it.
Unify handling division and multiplication.
2005-06-15 Aldy Hernandez <aldyh@redhat.com> 2005-06-15 Aldy Hernandez <aldyh@redhat.com>
* c-common.h (same_scalar_type_ignoring_signedness): Protoize. * c-common.h (same_scalar_type_ignoring_signedness): Protoize.
......
2005-06-15 Diego Novillo <dnovillo@redhat.com>
PR 22018
* gcc.dg/tree-ssa/vrp13.c: Add multiplication tests.
* gcc.dg/tree-ssa/pr22018.c: New test.
2005-06-15 Aldy Hernandez <aldyh@redhat.com> 2005-06-15 Aldy Hernandez <aldyh@redhat.com>
* gcc.dg/simd-1.c: Update error messages. * gcc.dg/simd-1.c: Update error messages.
......
/* { dg-do run } */
/* { dg-options -O2 } */
void abort (void);
void g(int);
void f(int l)
{
unsigned i;
for (i = 0; i < l; i++)
{
int y = i;
/* VRP was wrongfully computing z's range to be [0, 0] instead
of [-INF, 0]. */
int z = y*-32;
g(z);
}
}
void g(int i)
{
static int x = 0;
if (i == 0)
x ++;
if (x > 1)
abort ();
}
int main(void)
{
f(3);
return 0;
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
extern void abort (void); extern void abort (void);
foo (int i, int j) foo_div (int i, int j)
{ {
int k; int k;
...@@ -112,27 +112,146 @@ foo (int i, int j) ...@@ -112,27 +112,146 @@ foo (int i, int j)
} }
foo_mult (int i, int j)
{
int k;
/* [-20, -10] * [2, 10] should give [-200, -20]. */
if (i >= -20)
if (i <= -10)
if (j >= 2)
if (j <= 10)
{
k = i * j;
if (k < -200)
link_error ();
if (k > -20)
link_error ();
return k;
}
/* [-20, -10] * [-10, -2] should give [20, 200]. */
if (i >= -20)
if (i <= -10)
if (j >= -10)
if (j <= -2)
{
k = i * j;
if (k < 20)
link_error ();
if (k > 200)
link_error ();
return k;
}
/* [-20, 10] * [2, 10] should give [-200, 100]. */
if (i >= -20)
if (i <= 10)
if (j >= 2)
if (j <= 10)
{
k = i * j;
if (k < -200)
link_error ();
if (k > 100)
link_error ();
return k;
}
/* [-20, 10] * [-10, -2] should give [-100, 200]. */
if (i >= -20)
if (i <= 10)
if (j >= -10)
if (j <= -2)
{
k = i * j;
if (k < -100)
link_error ();
if (k > 200)
link_error ();
return k;
}
/* [10, 20] * [2, 10] should give [20, 200]. */
if (i >= 10)
if (i <= 20)
if (j >= 2)
if (j <= 10)
{
k = i * j;
if (k < 20)
link_error ();
if (k > 200)
link_error ();
return k;
}
/* [10, 20] * [-10, -2] should give [-200, -20]. */
if (i >= 10)
if (i <= 20)
if (j >= -10)
if (j <= -2)
{
k = i * j;
if (k < -200)
link_error ();
if (k > -20)
link_error ();
return k;
}
abort ();
}
main() main()
{ {
if (foo (-10, 5) != -2) if (foo_div (-10, 5) != -2)
abort ();
if (foo_div (-16, 4) != -4)
abort ();
if (foo_div (-15, -5) != 3)
abort ();
if (foo_div (8, 2) != 4)
abort ();
if (foo_div (10, -2) != -5)
abort ();
if (foo_div (20, 5) != 4)
abort ();
if (foo_div (15, -3) != -5)
abort ();
if (foo_mult (-10, 5) != -50)
abort (); abort ();
if (foo (-16, 4) != -4) if (foo_mult (-16, 4) != -64)
abort (); abort ();
if (foo (-15, -5) != 3) if (foo_mult (-15, -5) != 75)
abort (); abort ();
if (foo (8, 2) != 4) if (foo_mult (8, 2) != 16)
abort (); abort ();
if (foo (10, -2) != -5) if (foo_mult (10, -2) != -20)
abort (); abort ();
if (foo (20, 5) != 4) if (foo_mult (20, 5) != 100)
abort (); abort ();
if (foo (15, -3) != -5) if (foo_mult (15, -3) != -45)
abort (); abort ();
return 0; return 0;
......
...@@ -969,6 +969,50 @@ extract_range_from_ssa_name (value_range_t *vr, tree var) ...@@ -969,6 +969,50 @@ extract_range_from_ssa_name (value_range_t *vr, tree var)
} }
/* Wrapper around int_const_binop. If the operation overflows and we
are not using wrapping arithmetic, then adjust the result to be
-INF or +INF depending on CODE, VAL1 and VAL2. */
static inline tree
vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
{
tree res;
if (flag_wrapv)
return int_const_binop (code, val1, val2, 0);
/* If we are not using wrapping arithmetic, operate symbolically
on -INF and +INF. */
res = int_const_binop (code, val1, val2, 0);
/* If the operation overflowed but neither VAL1 nor VAL2 are
overflown, return -INF or +INF depending on whether VAL1 CODE
VAL2 is a growing function or not. */
if (TREE_OVERFLOW (res)
&& !TREE_OVERFLOW (val1)
&& !TREE_OVERFLOW (val2))
{
bool grows = false;
int sgn1 = tree_int_cst_sgn (val1);
int sgn2 = tree_int_cst_sgn (val2);
/* Notice that we only need to handle the restricted set of
operations handled by extract_range_from_binary_expr. */
if (((code == PLUS_EXPR || code == MAX_EXPR) && sgn2 >= 0)
|| (code == MULT_EXPR && sgn1 == sgn2)
|| (code == MINUS_EXPR && sgn2 < 0))
grows = true;
if (grows)
return TYPE_MAX_VALUE (TREE_TYPE (res));
else
return TYPE_MIN_VALUE (TREE_TYPE (res));
}
return res;
}
/* Extract range information from a binary expression EXPR based on /* Extract range information from a binary expression EXPR based on
the ranges of each of its operands and the expression code. */ the ranges of each of its operands and the expression code. */
...@@ -1076,96 +1120,85 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr) ...@@ -1076,96 +1120,85 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
max = fold_binary (code, TREE_TYPE (expr), vr0.max, vr1.max); max = fold_binary (code, TREE_TYPE (expr), vr0.max, vr1.max);
} }
else if (code == PLUS_EXPR else if (code == PLUS_EXPR
|| code == MULT_EXPR
|| code == MIN_EXPR || code == MIN_EXPR
|| code == MAX_EXPR) || code == MAX_EXPR)
{ {
/* For operations that make the resulting range directly /* For operations that make the resulting range directly
proportional to the original ranges, apply the operation to proportional to the original ranges, apply the operation to
the same end of each range. */ the same end of each range. */
min = int_const_binop (code, vr0.min, vr1.min, 0); min = vrp_int_const_binop (code, vr0.min, vr1.min);
max = int_const_binop (code, vr0.max, vr1.max, 0); max = vrp_int_const_binop (code, vr0.max, vr1.max);
} }
else if (code == TRUNC_DIV_EXPR else if (code == MULT_EXPR
|| code == TRUNC_DIV_EXPR
|| code == FLOOR_DIV_EXPR || code == FLOOR_DIV_EXPR
|| code == CEIL_DIV_EXPR || code == CEIL_DIV_EXPR
|| code == EXACT_DIV_EXPR || code == EXACT_DIV_EXPR
|| code == ROUND_DIV_EXPR) || code == ROUND_DIV_EXPR)
{ {
tree zero; tree val[4];
size_t i;
/* Multiplications and divisions are a bit tricky to handle,
depending on the mix of signs we have in the two ranges, we
need to operate on different values to get the minimum and
maximum values for the new range. One approach is to figure
out all the variations of range combinations and do the
operations.
/* Divisions are a bit tricky to handle, depending on the mix of However, this involves several calls to compare_values and it
signs we have in the two range, we will need to divide is pretty convoluted. It's simpler to do the 4 operations
different values to get the minimum and maximum values for (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
the new range. If VR1 includes zero, the result is VARYING. */ MAX1) and then figure the smallest and largest values to form
if (range_includes_zero_p (&vr1)) the new range. */
/* Divisions by zero result in a VARYING value. */
if (code != MULT_EXPR && range_includes_zero_p (&vr1))
{ {
set_value_range_to_varying (vr); set_value_range_to_varying (vr);
return; return;
} }
/* We have three main variations to handle for VR0: all negative /* Compute the 4 cross operations. */
values, all positive values and a mix of negative and val[0] = vrp_int_const_binop (code, vr0.min, vr1.min);
positive. For each of these, we need to consider if VR1 is
all negative or all positive. In total, there are 6 val[1] = (vr1.max != vr1.min)
combinations to handle. */ ? vrp_int_const_binop (code, vr0.min, vr1.max)
zero = build_int_cst (TREE_TYPE (expr), 0); : NULL_TREE;
if (compare_values (vr0.max, zero) == -1)
{ val[2] = (vr0.max != vr0.min)
/* VR0 is all negative. */ ? vrp_int_const_binop (code, vr0.max, vr1.min)
if (compare_values (vr1.min, zero) == 1) : NULL_TREE;
{
/* If VR1 is all positive, the new range is obtained val[3] = (vr0.min != vr1.min && vr0.max != vr1.max)
with [VR0.MIN / VR1.MIN, VR0.MAX / VR1.MAX]. */ ? vrp_int_const_binop (code, vr0.max, vr1.max)
min = int_const_binop (code, vr0.min, vr1.min, 0); : NULL_TREE;
max = int_const_binop (code, vr0.max, vr1.max, 0);
} /* Set MIN to the minimum of VAL[i] and MAX to the maximum
else of VAL[i]. */
{ min = val[0];
/* If VR1 is all negative, the new range is obtained max = val[0];
with [VR0.MAX / VR1.MIN, VR0.MIN / VR1.MAX]. */ for (i = 1; i < 4; i++)
gcc_assert (compare_values (vr1.max, zero) == -1);
min = int_const_binop (code, vr0.max, vr1.min, 0);
max = int_const_binop (code, vr0.min, vr1.max, 0);
}
}
else if (range_includes_zero_p (&vr0))
{
/* VR0 is a mix of negative and positive values. */
if (compare_values (vr1.min, zero) == 1)
{
/* If VR1 is all positive, the new range is obtained
with [VR0.MIN / VR1.MIN, VR0.MAX / VR1.MIN]. */
min = int_const_binop (code, vr0.min, vr1.min, 0);
max = int_const_binop (code, vr0.max, vr1.min, 0);
}
else
{
/* If VR1 is all negative, the new range is obtained
with [VR0.MAX / VR1.MAX, VR0.MIN / VR1.MAX]. */
gcc_assert (compare_values (vr1.max, zero) == -1);
min = int_const_binop (code, vr0.max, vr1.max, 0);
max = int_const_binop (code, vr0.min, vr1.max, 0);
}
}
else
{ {
/* VR0 is all positive. */ if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max))
gcc_assert (compare_values (vr0.min, zero) == 1); break;
if (compare_values (vr1.min, zero) == 1)
{ if (val[i])
/* If VR1 is all positive, the new range is obtained
with [VR0.MIN / VR1.MAX, VR0.MAX / VR1.MIN]. */
min = int_const_binop (code, vr0.min, vr1.max, 0);
max = int_const_binop (code, vr0.max, vr1.min, 0);
}
else
{ {
/* If VR1 is all negative, the new range is obtained if (TREE_OVERFLOW (val[i]))
with [VR0.MAX / VR1.MAX, VR0.MIN / VR1.MIN]. */ {
gcc_assert (compare_values (vr1.max, zero) == -1); /* If we found an overflowed value, set MIN and MAX
min = int_const_binop (code, vr0.max, vr1.max, 0); to it so that we set the resulting range to
max = int_const_binop (code, vr0.min, vr1.min, 0); VARYING. */
min = max = val[i];
break;
}
if (compare_values (val[i], min) == -1)
min = val[i];
if (compare_values (val[i], max) == 1)
max = val[i];
} }
} }
} }
...@@ -1173,42 +1206,18 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr) ...@@ -1173,42 +1206,18 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
{ {
/* For MINUS_EXPR, apply the operation to the opposite ends of /* For MINUS_EXPR, apply the operation to the opposite ends of
each range. */ each range. */
min = int_const_binop (code, vr0.min, vr1.max, 0); min = vrp_int_const_binop (code, vr0.min, vr1.max);
max = int_const_binop (code, vr0.max, vr1.min, 0); max = vrp_int_const_binop (code, vr0.max, vr1.min);
} }
else else
gcc_unreachable (); gcc_unreachable ();
/* If MAX overflowed, then the result depends on whether we are /* If either MIN or MAX overflowed, then set the resulting range to
using wrapping arithmetic or not. */ VARYING. */
if (TREE_OVERFLOW (max)) if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max))
{ {
/* If we are using wrapping arithmetic, set the result to set_value_range_to_varying (vr);
VARYING. */ return;
if (flag_wrapv)
{
set_value_range_to_varying (vr);
return;
}
/* Otherwise, set MAX to +INF. */
max = TYPE_MAX_VALUE (TREE_TYPE (expr));
}
/* If MIN overflowed, then the result depends on whether we are
using wrapping arithmetic or not. */
if (TREE_OVERFLOW (min))
{
/* If we are using wrapping arithmetic, set the result to
VARYING. */
if (flag_wrapv)
{
set_value_range_to_varying (vr);
return;
}
/* Otherwise, set MIN to -INF. */
min = TYPE_MIN_VALUE (TREE_TYPE (expr));
} }
cmp = compare_values (min, max); cmp = compare_values (min, max);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment