Commit 44dedb4b by Richard Biener Committed by Richard Biener

tree-vrp.c (vrp_int_const_binop): Use wide-ints and simplify.

2017-05-09  Richard Biener  <rguenther@suse.de>

	* tree-vrp.c (vrp_int_const_binop): Use wide-ints and simplify.
	(extract_range_from_multiplicative_op_1): Adjust.
	(extract_range_from_binary_expr_1): Use int_const_binop.

From-SVN: r247779
parent 631238ac
2017-05-09 Richard Biener <rguenther@suse.de>
* tree-vrp.c (vrp_int_const_binop): Use wide-ints and simplify.
(extract_range_from_multiplicative_op_1): Adjust.
(extract_range_from_binary_expr_1): Use int_const_binop.
2017-05-08 Kelvin Nilsen <kelvin@gcc.gnu.org> 2017-05-08 Kelvin Nilsen <kelvin@gcc.gnu.org>
PR target/80101 PR target/80101
......
...@@ -1618,66 +1618,91 @@ extract_range_from_ssa_name (value_range *vr, tree var) ...@@ -1618,66 +1618,91 @@ extract_range_from_ssa_name (value_range *vr, tree var)
/* Wrapper around int_const_binop. If the operation overflows and we /* Wrapper around int_const_binop. If the operation overflows and we
are not using wrapping arithmetic, then adjust the result to be are not using wrapping arithmetic, then adjust the result to be
-INF or +INF depending on CODE, VAL1 and VAL2. This can return -INF or +INF depending on CODE, VAL1 and VAL2. This can return
NULL_TREE if we need to use an overflow infinity representation but NULL_TREE for division by zero. */
the type does not support it. */
static tree static wide_int
vrp_int_const_binop (enum tree_code code, tree val1, tree val2) vrp_int_const_binop (enum tree_code code, tree val1, tree val2,
bool *overflow_p)
{ {
tree res; bool overflow = false;
signop sign = TYPE_SIGN (TREE_TYPE (val1));
res = int_const_binop (code, val1, val2); wide_int res;
/* If we are using unsigned arithmetic, operate symbolically switch (code)
on -INF and +INF as int_const_binop only handles signed overflow. */
if (TYPE_UNSIGNED (TREE_TYPE (val1)))
{ {
int checkz = compare_values (res, val1); case RSHIFT_EXPR:
bool overflow = false; case LSHIFT_EXPR:
{
wide_int wval2 = wi::to_wide (val2, TYPE_PRECISION (TREE_TYPE (val1)));
if (wi::neg_p (wval2))
{
wval2 = -wval2;
if (code == RSHIFT_EXPR)
code = LSHIFT_EXPR;
else
code = RSHIFT_EXPR;
}
if (code == RSHIFT_EXPR)
/* It's unclear from the C standard whether shifts can overflow.
The following code ignores overflow; perhaps a C standard
interpretation ruling is needed. */
res = wi::rshift (val1, wval2, sign);
else
res = wi::lshift (val1, wval2);
break;
}
/* Ensure that res = val1 [+*] val2 >= val1 case MULT_EXPR:
or that res = val1 - val2 <= val1. */ res = wi::mul (val1, val2, sign, &overflow);
if ((code == PLUS_EXPR break;
&& !(checkz == 1 || checkz == 0))
|| (code == MINUS_EXPR case TRUNC_DIV_EXPR:
&& !(checkz == 0 || checkz == -1))) case EXACT_DIV_EXPR:
if (val2 == 0)
{ {
overflow = true; *overflow_p = true;
return res;
} }
/* Checking for multiplication overflow is done by dividing the else
output of the multiplication by the first input of the res = wi::div_trunc (val1, val2, sign, &overflow);
multiplication. If the result of that division operation is break;
not equal to the second input of the multiplication, then the
multiplication overflowed. */ case FLOOR_DIV_EXPR:
else if (code == MULT_EXPR && !integer_zerop (val1)) if (val2 == 0)
{ {
tree tmp = int_const_binop (TRUNC_DIV_EXPR, *overflow_p = true;
res, return res;
val1); }
int check = compare_values (tmp, val2); res = wi::div_floor (val1, val2, sign, &overflow);
break;
if (check != 0) case CEIL_DIV_EXPR:
overflow = true; if (val2 == 0)
{
*overflow_p = true;
return res;
} }
res = wi::div_ceil (val1, val2, sign, &overflow);
break;
if (overflow) case ROUND_DIV_EXPR:
if (val2 == 0)
{ {
res = copy_node (res); *overflow_p = 0;
TREE_OVERFLOW (res) = 1; return res;
} }
res = wi::div_round (val1, val2, sign, &overflow);
break;
default:
gcc_unreachable ();
} }
else if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (val1)))
/* If the singed operation wraps then int_const_binop has done *overflow_p = overflow;
everything we want. */
; if (overflow
/* Signed division of -1/0 overflows and by the time it gets here && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (val1)))
returns NULL_TREE. */
else if (!res)
return NULL_TREE;
else if (TREE_OVERFLOW (res)
&& ! TREE_OVERFLOW (val1)
&& ! TREE_OVERFLOW (val2))
{ {
/* If the operation overflowed but neither VAL1 nor VAL2 are /* If the operation overflowed but neither VAL1 nor VAL2 are
overflown, return -INF or +INF depending on the operation overflown, return -INF or +INF depending on the operation
...@@ -1711,17 +1736,18 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2) ...@@ -1711,17 +1736,18 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
overflow direction is the same as the sign of val1. overflow direction is the same as the sign of val1.
Actually rshift does not overflow at all, but we only Actually rshift does not overflow at all, but we only
handle the case of shifting overflowed -INF and +INF. */ handle the case of shifting overflowed -INF and +INF. */
|| (code == RSHIFT_EXPR || (code == RSHIFT_EXPR && sgn1 >= 0)
&& sgn1 >= 0)
/* For division, the only case is -INF / -1 = +INF. */ /* For division, the only case is -INF / -1 = +INF. */
|| code == TRUNC_DIV_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)
return TYPE_MAX_VALUE (TREE_TYPE (res)); return wi::max_value (TYPE_PRECISION (TREE_TYPE (val1)),
TYPE_SIGN (TREE_TYPE (val1)));
else else
return TYPE_MIN_VALUE (TREE_TYPE (res)); return wi::min_value (TYPE_PRECISION (TREE_TYPE (val1)),
TYPE_SIGN (TREE_TYPE (val1)));
} }
return res; return res;
...@@ -1818,12 +1844,10 @@ extract_range_from_multiplicative_op_1 (value_range *vr, ...@@ -1818,12 +1844,10 @@ extract_range_from_multiplicative_op_1 (value_range *vr,
enum tree_code code, enum tree_code code,
value_range *vr0, value_range *vr1) value_range *vr0, value_range *vr1)
{ {
enum value_range_type type; enum value_range_type rtype;
tree val[4]; wide_int val, min, max;
size_t i;
tree min, max;
bool sop; bool sop;
int cmp; tree type;
/* Multiplications, divisions and shifts are a bit tricky to handle, /* Multiplications, divisions and shifts are a bit tricky to handle,
depending on the mix of signs we have in the two ranges, we depending on the mix of signs we have in the two ranges, we
...@@ -1849,88 +1873,69 @@ extract_range_from_multiplicative_op_1 (value_range *vr, ...@@ -1849,88 +1873,69 @@ extract_range_from_multiplicative_op_1 (value_range *vr,
|| (code == MULT_EXPR && vr0->type == VR_ANTI_RANGE)) || (code == MULT_EXPR && vr0->type == VR_ANTI_RANGE))
&& vr0->type == vr1->type); && vr0->type == vr1->type);
type = vr0->type; rtype = vr0->type;
type = TREE_TYPE (vr0->min);
signop sgn = TYPE_SIGN (type);
/* Compute the 4 cross operations. */ /* Compute the 4 cross operations and their minimum and maximum value. */
sop = false; sop = false;
val[0] = vrp_int_const_binop (code, vr0->min, vr1->min); val = vrp_int_const_binop (code, vr0->min, vr1->min, &sop);
if (val[0] == NULL_TREE) if (! sop)
sop = true; min = max = val;
if (vr1->max == vr1->min) if (vr1->max == vr1->min)
val[1] = NULL_TREE; ;
else else if (! sop)
{
val = vrp_int_const_binop (code, vr0->min, vr1->max, &sop);
if (! sop)
{ {
val[1] = vrp_int_const_binop (code, vr0->min, vr1->max); if (wi::lt_p (val, min, sgn))
if (val[1] == NULL_TREE) min = val;
sop = true; else if (wi::gt_p (val, max, sgn))
max = val;
}
} }
if (vr0->max == vr0->min) if (vr0->max == vr0->min)
val[2] = NULL_TREE; ;
else else if (! sop)
{
val = vrp_int_const_binop (code, vr0->max, vr1->min, &sop);
if (! sop)
{ {
val[2] = vrp_int_const_binop (code, vr0->max, vr1->min); if (wi::lt_p (val, min, sgn))
if (val[2] == NULL_TREE) min = val;
sop = true; else if (wi::gt_p (val, max, sgn))
max = val;
}
} }
if (vr0->min == vr0->max || vr1->min == vr1->max) if (vr0->min == vr0->max || vr1->min == vr1->max)
val[3] = NULL_TREE; ;
else else if (! sop)
{ {
val[3] = vrp_int_const_binop (code, vr0->max, vr1->max); val = vrp_int_const_binop (code, vr0->max, vr1->max, &sop);
if (val[3] == NULL_TREE) if (! sop)
sop = true; {
if (wi::lt_p (val, min, sgn))
min = val;
else if (wi::gt_p (val, max, sgn))
max = val;
}
} }
/* If either operation overflowed, drop to VARYING. */
if (sop) if (sop)
{ {
set_value_range_to_varying (vr); set_value_range_to_varying (vr);
return; return;
} }
/* Set MIN to the minimum of VAL[i] and MAX to the maximum /* If the new range has its limits swapped around (MIN > MAX),
of VAL[i]. */ then the operation caused one of them to wrap around, mark
min = val[0]; the new range VARYING. */
max = val[0]; if (wi::gt_p (min, max, sgn))
for (i = 1; i < 4; i++)
{
if (!is_gimple_min_invariant (min)
|| TREE_OVERFLOW (min)
|| !is_gimple_min_invariant (max)
|| TREE_OVERFLOW (max))
break;
if (val[i])
{
if (!is_gimple_min_invariant (val[i])
|| TREE_OVERFLOW (val[i]))
{
/* If we found an overflowed value, set MIN and MAX
to it so that we set the resulting range to
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];
}
}
/* If either MIN or MAX overflowed, then set the resulting range to
VARYING. But we do accept an overflow infinity
representation. */
if (min == NULL_TREE
|| !is_gimple_min_invariant (min)
|| TREE_OVERFLOW (min)
|| max == NULL_TREE
|| !is_gimple_min_invariant (max)
|| TREE_OVERFLOW (max))
{ {
set_value_range_to_varying (vr); set_value_range_to_varying (vr);
return; return;
...@@ -1939,23 +1944,16 @@ extract_range_from_multiplicative_op_1 (value_range *vr, ...@@ -1939,23 +1944,16 @@ extract_range_from_multiplicative_op_1 (value_range *vr,
/* We punt for [-INF, +INF]. /* We punt for [-INF, +INF].
We learn nothing when we have INF on both sides. We learn nothing when we have INF on both sides.
Note that we do accept [-INF, -INF] and [+INF, +INF]. */ Note that we do accept [-INF, -INF] and [+INF, +INF]. */
if (vrp_val_is_min (min) if (wi::eq_p (min, wi::min_value (TYPE_PRECISION (type), sgn))
&& vrp_val_is_max (max)) && wi::eq_p (max, wi::max_value (TYPE_PRECISION (type), sgn)))
{ {
set_value_range_to_varying (vr); set_value_range_to_varying (vr);
return; return;
} }
cmp = compare_values (min, max); set_value_range (vr, rtype,
if (cmp == -2 || cmp == 1) wide_int_to_tree (type, min),
{ wide_int_to_tree (type, max), NULL);
/* If the new range has its limits swapped around (MIN > MAX),
then the operation caused one of them to wrap around, mark
the new range VARYING. */
set_value_range_to_varying (vr);
}
else
set_value_range (vr, type, min, max, NULL);
} }
/* Extract range information from a binary operation CODE based on /* Extract range information from a binary operation CODE based on
...@@ -2438,8 +2436,8 @@ extract_range_from_binary_expr_1 (value_range *vr, ...@@ -2438,8 +2436,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
/* 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 = vrp_int_const_binop (code, vr0.min, vr1.min); min = int_const_binop (code, vr0.min, vr1.min);
max = vrp_int_const_binop (code, vr0.max, vr1.max); max = int_const_binop (code, vr0.max, vr1.max);
} }
else if (code == MIN_EXPR) else if (code == MIN_EXPR)
{ {
......
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