===================================================================
@@ -2345,157 +2345,194 @@ extract_range_from_binary_expr_1 (value_
set_value_range_to_varying (vr);
}
else
set_value_range_to_varying (vr);
return;
}
/* For integer ranges, apply the operation to each end of the
range and see what we end up with. */
- if (code == PLUS_EXPR)
+ if (code == PLUS_EXPR || code == MINUS_EXPR)
{
/* If we have a PLUS_EXPR with two VR_RANGE integer constant
ranges compute the precise range for such case if possible. */
if (range_int_cst_p (&vr0)
&& range_int_cst_p (&vr1)
- /* We attempt to do infinite precision signed integer arithmetic,
- thus we need two more bits than the possibly unsigned inputs. */
- && TYPE_PRECISION (expr_type) < HOST_BITS_PER_DOUBLE_INT - 1)
+ /* We need as many bits as the possibly unsigned inputs. */
+ && TYPE_PRECISION (expr_type) <= HOST_BITS_PER_DOUBLE_INT)
{
double_int min0 = tree_to_double_int (vr0.min);
double_int max0 = tree_to_double_int (vr0.max);
double_int min1 = tree_to_double_int (vr1.min);
double_int max1 = tree_to_double_int (vr1.max);
bool uns = TYPE_UNSIGNED (expr_type);
double_int type_min
= double_int_min_value (TYPE_PRECISION (expr_type), uns);
double_int type_max
= double_int_max_value (TYPE_PRECISION (expr_type), uns);
double_int dmin, dmax;
+ int min_ovf = 0;
+ int max_ovf = 0;
- dmin = double_int_add (min0, min1);
- dmax = double_int_add (max0, max1);
+ if (code == PLUS_EXPR)
+ {
+ dmin = double_int_add (min0, min1);
+ dmax = double_int_add (max0, max1);
+
+ /* Check for overflow in double_int. */
+ if (double_int_cmp (min1, double_int_zero, uns)
+ != double_int_cmp (dmin, min0, uns))
+ min_ovf = double_int_cmp (min0, dmin, uns);
+ if (double_int_cmp (max1, double_int_zero, uns)
+ != double_int_cmp (dmax, max0, uns))
+ max_ovf = double_int_cmp (max0, dmax, uns);
+ }
+ else /* if (code == MINUS_EXPR) */
+ {
+ dmin = double_int_sub (min0, max1);
+ dmax = double_int_sub (max0, min1);
+
+ if (double_int_cmp (double_int_zero, max1, uns)
+ != double_int_cmp (dmin, min0, uns))
+ min_ovf = double_int_cmp (min0, max1, uns);
+ if (double_int_cmp (double_int_zero, min1, uns)
+ != double_int_cmp (dmax, max0, uns))
+ max_ovf = double_int_cmp (max0, min1, uns);
+ }
+
+ /* For non-wrapping arithmetic look at possibly smaller
+ value-ranges of the type. */
+ if (!TYPE_OVERFLOW_WRAPS (expr_type))
+ {
+ if (vrp_val_min (expr_type))
+ type_min = tree_to_double_int (vrp_val_min (expr_type));
+ if (vrp_val_max (expr_type))
+ type_max = tree_to_double_int (vrp_val_max (expr_type));
+ }
+
+ /* Check for type overflow. */
+ if (min_ovf == 0)
+ {
+ if (double_int_cmp (dmin, type_min, uns) == -1)
+ min_ovf = -1;
+ else if (double_int_cmp (dmin, type_max, uns) == 1)
+ min_ovf = 1;
+ }
+ if (max_ovf == 0)
+ {
+ if (double_int_cmp (dmax, type_min, uns) == -1)
+ max_ovf = -1;
+ else if (double_int_cmp (dmax, type_max, uns) == 1)
+ max_ovf = 1;
+ }
if (TYPE_OVERFLOW_WRAPS (expr_type))
{
/* If overflow wraps, truncate the values and adjust the
range kind and bounds appropriately. */
double_int tmin
= double_int_ext (dmin, TYPE_PRECISION (expr_type), uns);
double_int tmax
= double_int_ext (dmax, TYPE_PRECISION (expr_type), uns);
- gcc_assert (double_int_scmp (dmin, dmax) <= 0);
- if ((double_int_scmp (dmin, type_min) == -1
- && double_int_scmp (dmax, type_min) == -1)
- || (double_int_scmp (dmin, type_max) == 1
- && double_int_scmp (dmax, type_max) == 1)
- || (double_int_scmp (type_min, dmin) <= 0
- && double_int_scmp (dmax, type_max) <= 0))
+ if (min_ovf == max_ovf)
{
/* No overflow or both overflow or underflow. The
range kind stays VR_RANGE. */
min = double_int_to_tree (expr_type, tmin);
max = double_int_to_tree (expr_type, tmax);
}
- else if (double_int_scmp (dmin, type_min) == -1
- && double_int_scmp (dmax, type_max) == 1)
+ else if (min_ovf == -1
+ && max_ovf == 1)
{
/* Underflow and overflow, drop to VR_VARYING. */
set_value_range_to_varying (vr);
return;
}
else
{
/* Min underflow or max overflow. The range kind
changes to VR_ANTI_RANGE. */
double_int tem = tmin;
- gcc_assert ((double_int_scmp (dmin, type_min) == -1
- && double_int_scmp (dmax, type_min) >= 0
- && double_int_scmp (dmax, type_max) <= 0)
- || (double_int_scmp (dmax, type_max) == 1
- && double_int_scmp (dmin, type_min) >= 0
- && double_int_scmp (dmin, type_max) <= 0));
+ gcc_assert ((min_ovf == -1 && max_ovf == 0)
+ || (max_ovf == 1 && min_ovf == 0));
type = VR_ANTI_RANGE;
tmin = double_int_add (tmax, double_int_one);
tmax = double_int_add (tem, double_int_minus_one);
/* If the anti-range would cover nothing, drop to varying.
Likewise if the anti-range bounds are outside of the
types values. */
if (double_int_cmp (tmin, tmax, uns) > 0
|| double_int_cmp (tmin, type_min, uns) < 0
|| double_int_cmp (tmax, type_max, uns) > 0)
{
set_value_range_to_varying (vr);
return;
}
min = double_int_to_tree (expr_type, tmin);
max = double_int_to_tree (expr_type, tmax);
}
}
else
{
- /* For non-wrapping arithmetic look at possibly smaller
- value-ranges of the type. */
- if (vrp_val_min (expr_type))
- type_min = tree_to_double_int (vrp_val_min (expr_type));
- if (vrp_val_max (expr_type))
- type_max = tree_to_double_int (vrp_val_max (expr_type));
-
/* If overflow does not wrap, saturate to the types min/max
value. */
- if (double_int_scmp (dmin, type_min) == -1)
+ if (min_ovf == -1)
{
if (needs_overflow_infinity (expr_type)
&& supports_overflow_infinity (expr_type))
min = negative_overflow_infinity (expr_type);
else
min = double_int_to_tree (expr_type, type_min);
}
- else if (double_int_scmp (dmin, type_max) == 1)
+ else if (min_ovf == 1)
{
if (needs_overflow_infinity (expr_type)
&& supports_overflow_infinity (expr_type))
min = positive_overflow_infinity (expr_type);
else
min = double_int_to_tree (expr_type, type_max);
}
else
min = double_int_to_tree (expr_type, dmin);
- if (double_int_scmp (dmax, type_min) == -1)
+ if (max_ovf == -1)
{
if (needs_overflow_infinity (expr_type)
&& supports_overflow_infinity (expr_type))
max = negative_overflow_infinity (expr_type);
else
max = double_int_to_tree (expr_type, type_min);
}
- else if (double_int_scmp (dmax, type_max) == 1)
+ else if (max_ovf == 1)
{
if (needs_overflow_infinity (expr_type)
&& supports_overflow_infinity (expr_type))
max = positive_overflow_infinity (expr_type);
else
max = double_int_to_tree (expr_type, type_max);
}
else
max = double_int_to_tree (expr_type, dmax);
}
if (needs_overflow_infinity (expr_type)
&& supports_overflow_infinity (expr_type))
{
if (is_negative_overflow_infinity (vr0.min)
- || is_negative_overflow_infinity (vr1.min))
+ || (code == PLUS_EXPR
+ ? is_negative_overflow_infinity (vr1.min)
+ : is_positive_overflow_infinity (vr1.max)))
min = negative_overflow_infinity (expr_type);
if (is_positive_overflow_infinity (vr0.max)
- || is_positive_overflow_infinity (vr1.max))
+ || (code == PLUS_EXPR
+ ? is_positive_overflow_infinity (vr1.max)
+ : is_negative_overflow_infinity (vr1.min)))
max = positive_overflow_infinity (expr_type);
}
}
else
{
/* For other cases, for example if we have a PLUS_EXPR with two
VR_ANTI_RANGEs, drop to VR_VARYING. It would take more effort
to compute a precise range for such a case.
??? General even mixed range kind operations can be expressed
by for example transforming ~[3, 5] + [1, 2] to range-only
@@ -2710,40 +2747,20 @@ extract_range_from_binary_expr_1 (value_
max = vr1.max;
max = int_const_binop (MINUS_EXPR, max, integer_one_node);
/* If the dividend is non-negative the modulus will be
non-negative as well. */
if (TYPE_UNSIGNED (expr_type)
|| value_range_nonnegative_p (&vr0))
min = build_int_cst (TREE_TYPE (max), 0);
else
min = fold_unary_to_constant (NEGATE_EXPR, expr_type, max);
}
- else if (code == MINUS_EXPR)
- {
- /* If we have a MINUS_EXPR with two VR_ANTI_RANGEs, drop to
- VR_VARYING. It would take more effort to compute a precise
- range for such a case. For example, if we have op0 == 1 and
- op1 == 1 with their ranges both being ~[0,0], we would have
- op0 - op1 == 0, so we cannot claim that the difference is in
- ~[0,0]. Note that we are guaranteed to have
- vr0.type == vr1.type at this point. */
- if (vr0.type == VR_ANTI_RANGE)
- {
- set_value_range_to_varying (vr);
- return;
- }
-
- /* For MINUS_EXPR, apply the operation to the opposite ends of
- each range. */
- min = vrp_int_const_binop (code, vr0.min, vr1.max);
- max = vrp_int_const_binop (code, vr0.max, vr1.min);
- }
else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR)
{
bool int_cst_range0, int_cst_range1;
double_int may_be_nonzero0, may_be_nonzero1;
double_int must_be_nonzero0, must_be_nonzero1;
int_cst_range0 = zero_nonzero_bits_from_vr (&vr0, &may_be_nonzero0,
&must_be_nonzero0);
int_cst_range1 = zero_nonzero_bits_from_vr (&vr1, &may_be_nonzero1,
&must_be_nonzero1);