else if (code == MIN_EXPR
|| code == MAX_EXPR)
{
- if (vr0.type == VR_RANGE
- && !symbolic_range_p (&vr0))
- {
- type = VR_RANGE;
- if (vr1.type == VR_RANGE
- && !symbolic_range_p (&vr1))
- {
- /* For operations that make the resulting range directly
- proportional to the original ranges, apply the operation to
- the same end of each range. */
- min = int_const_binop (code, vr0.min, vr1.min);
- max = int_const_binop (code, vr0.max, vr1.max);
- }
- else if (code == MIN_EXPR)
- {
- min = vrp_val_min (expr_type);
- max = vr0.max;
- }
- else if (code == MAX_EXPR)
- {
- min = vr0.min;
- max = vrp_val_max (expr_type);
- }
- }
- else if (vr1.type == VR_RANGE
- && !symbolic_range_p (&vr1))
- {
- type = VR_RANGE;
- if (code == MIN_EXPR)
- {
- min = vrp_val_min (expr_type);
- max = vr1.max;
- }
- else if (code == MAX_EXPR)
- {
- min = vr1.min;
- max = vrp_val_max (expr_type);
- }
- }
+ wide_int wmin, wmax;
+ wide_int vr0_min, vr0_max;
+ wide_int vr1_min, vr1_max;
+ extract_range_into_wide_ints (&vr0, sign, prec, &vr0_min, &vr0_max);
+ extract_range_into_wide_ints (&vr1, sign, prec, &vr1_min, &vr1_max);
+ if (wide_int_range_min_max (wmin, wmax, code, sign, prec,
+ vr0_min, vr0_max, vr1_min, vr1_max))
+ set_value_range (vr, VR_RANGE,
+ wide_int_to_tree (expr_type, wmin),
+ wide_int_to_tree (expr_type, wmax), NULL);
else
- {
- set_value_range_to_varying (vr);
- return;
- }
+ set_value_range_to_varying (vr);
+ return;
}
else if (code == MULT_EXPR)
{
set_value_range (vr, type, min, max, NULL);
}
-/* Calculates the absolute value of a range and puts the result in VR.
- VR0 is the input range. TYPE is the type of the resulting
- range. */
-
-static void
-extract_range_from_abs_expr (value_range &vr, tree type, value_range &vr0)
-{
- /* Pass through vr0 in the easy cases. */
- if (TYPE_UNSIGNED (type)
- || value_range_nonnegative_p (&vr0))
- {
- copy_value_range (&vr, &vr0);
- return;
- }
-
- /* For the remaining varying or symbolic ranges we can't do anything
- useful. */
- if (vr0.type == VR_VARYING
- || symbolic_range_p (&vr0))
- {
- set_value_range_to_varying (&vr);
- return;
- }
-
- /* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a
- useful range. */
- if (!TYPE_OVERFLOW_UNDEFINED (type)
- && ((vr0.type == VR_RANGE
- && vrp_val_is_min (vr0.min))
- || (vr0.type == VR_ANTI_RANGE
- && !vrp_val_is_min (vr0.min))))
- {
- set_value_range_to_varying (&vr);
- return;
- }
-
- /* ABS_EXPR may flip the range around, if the original range
- included negative values. */
- tree min, max;
- if (!vrp_val_is_min (vr0.min))
- min = fold_unary_to_constant (ABS_EXPR, type, vr0.min);
- else
- min = TYPE_MAX_VALUE (type);
-
- if (!vrp_val_is_min (vr0.max))
- max = fold_unary_to_constant (ABS_EXPR, type, vr0.max);
- else
- max = TYPE_MAX_VALUE (type);
-
- int cmp = compare_values (min, max);
- gcc_assert (vr0.type != VR_ANTI_RANGE);
-
- /* If the range contains zero then we know that the minimum value in the
- range will be zero. */
- if (range_includes_zero_p (vr0.min, vr0.max) == 1)
- {
- if (cmp == 1)
- max = min;
- min = build_int_cst (type, 0);
- }
- else
- {
- /* If the range was reversed, swap MIN and MAX. */
- if (cmp == 1)
- std::swap (min, max);
- }
-
- cmp = compare_values (min, max);
- if (cmp == -2 || cmp == 1)
- {
- /* 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, vr0.type, min, max, NULL);
-}
-
/* Extract range information from a unary operation CODE based on
the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE.
The resulting range is stored in *VR. */
enum tree_code code, tree type,
value_range *vr0_, tree op0_type)
{
+ signop sign = TYPE_SIGN (type);
+ unsigned int prec = TYPE_PRECISION (type);
value_range vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
/* VRP only operates on integral and pointer types. */
return;
}
else if (code == ABS_EXPR)
- return extract_range_from_abs_expr (*vr, type, vr0);
+ {
+ if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
+ {
+ set_value_range_to_varying (vr);
+ return;
+ }
+ wide_int wmin, wmax;
+ wide_int vr0_min, vr0_max;
+ extract_range_into_wide_ints (&vr0, sign, prec, &vr0_min, &vr0_max);
+ if (wide_int_range_abs (wmin, wmax, sign, prec, vr0_min, vr0_max,
+ TYPE_OVERFLOW_UNDEFINED (type)))
+ set_value_range (vr, VR_RANGE,
+ wide_int_to_tree (type, wmin),
+ wide_int_to_tree (type, wmax), NULL);
+ else
+ set_value_range_to_varying (vr);
+ return;
+ }
/* For unhandled operations fall back to varying. */
set_value_range_to_varying (vr);
accordingly. */
static void
-wide_int_range_min_max (wide_int &min, wide_int &max,
- wide_int &w0, wide_int &w1, wide_int &w2, wide_int &w3,
- signop sign)
+wide_int_range_order_set (wide_int &min, wide_int &max,
+ wide_int &w0, wide_int &w1,
+ wide_int &w2, wide_int &w3,
+ signop sign)
{
/* Order pairs w0,w1 and w2,w3. */
if (wi::gt_p (w0, w1, sign))
overflow_undefined))
return false;
- wide_int_range_min_max (res_lb, res_ub, cp1, cp2, cp3, cp4, sign);
+ wide_int_range_order_set (res_lb, res_ub, cp1, cp2, cp3, cp4, sign);
return true;
}
tmp = wi::zero (prec);
wmax = wi::min (wmax, tmp, sign);
}
+
+/* Calculate ABS_EXPR on a range and store the result in [MIN, MAX]. */
+
+bool
+wide_int_range_abs (wide_int &min, wide_int &max,
+ signop sign, unsigned prec,
+ const wide_int &vr0_min, const wide_int &vr0_max,
+ bool overflow_undefined)
+{
+ /* Pass through VR0 the easy cases. */
+ if (sign == UNSIGNED || wi::ge_p (vr0_min, 0, sign))
+ {
+ min = vr0_min;
+ max = vr0_max;
+ return true;
+ }
+
+ /* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a
+ useful range. */
+ wide_int min_value = wi::min_value (prec, sign);
+ wide_int max_value = wi::max_value (prec, sign);
+ if (!overflow_undefined && wi::eq_p (vr0_min, min_value))
+ return false;
+
+ /* ABS_EXPR may flip the range around, if the original range
+ included negative values. */
+ if (wi::eq_p (vr0_min, min_value))
+ min = max_value;
+ else
+ min = wi::abs (vr0_min);
+ if (wi::eq_p (vr0_max, min_value))
+ max = max_value;
+ else
+ max = wi::abs (vr0_max);
+
+ /* If the range contains zero then we know that the minimum value in the
+ range will be zero. */
+ if (wi::le_p (vr0_min, 0, sign) && wi::ge_p (vr0_max, 0, sign))
+ {
+ if (wi::gt_p (min, max, sign))
+ max = min;
+ min = wi::zero (prec);
+ }
+ else
+ {
+ /* If the range was reversed, swap MIN and MAX. */
+ if (wi::gt_p (min, max, sign))
+ std::swap (min, max);
+ }
+
+ /* 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. */
+ if (wi::gt_p (min, max, sign))
+ return false;
+ return true;
+}
const wide_int &vr0_max,
const wide_int &vr1_min,
const wide_int &vr1_max);
+extern bool wide_int_range_abs (wide_int &min, wide_int &max,
+ signop sign, unsigned prec,
+ const wide_int &vr0_min,
+ const wide_int &vr0_max,
+ bool overflow_undefined);
/* Return TRUE if shifting by range [MIN, MAX] is undefined behavior. */
return wi::lt_p (min, 0, sign) || wi::ge_p (max, prec, sign);
}
+/* Calculate MIN/MAX_EXPR of two ranges and store the result in [MIN, MAX]. */
+
+inline bool
+wide_int_range_min_max (wide_int &min, wide_int &max,
+ tree_code code,
+ signop sign, unsigned prec,
+ const wide_int &vr0_min, const wide_int &vr0_max,
+ const wide_int &vr1_min, const wide_int &vr1_max)
+{
+ wi::overflow_type overflow;
+ wide_int_binop (min, code, vr0_min, vr1_min, sign, &overflow);
+ wide_int_binop (max, code, vr0_max, vr1_max, sign, &overflow);
+ /* If the new range covers the entire domain, that's really no range
+ at all. */
+ if (min == wi::min_value (prec, sign)
+ && max == wi::max_value (prec, sign))
+ return false;
+ return true;
+}
+
#endif /* GCC_WIDE_INT_RANGE_H */