gcc/ * tree-vrp.c (abs_extent_range): Remove. (extract_range_into_wide_ints): Pass wide ints by reference. (extract_range_from_binary_expr_1): Rewrite the *DIV_EXPR code. Pass wide ints by reference in all calls to extract_range_into_wide_ints. * wide-int-range.cc (wide_int_range_div): New. * wide-int-range.h (wide_int_range_div): New. (wide_int_range_includes_zero_p): New. (wide_int_range_zero_p): New. diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 24e089b019b..c563ab1225a 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -478,42 +478,6 @@ set_value_range_to_null (value_range *vr, tree type) set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv); } - -/* If abs (min) < abs (max), set VR to [-max, max], if - abs (min) >= abs (max), set VR to [-min, min]. */ - -static void -abs_extent_range (value_range *vr, tree min, tree max) -{ - int cmp; - - gcc_assert (TREE_CODE (min) == INTEGER_CST); - gcc_assert (TREE_CODE (max) == INTEGER_CST); - gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (min))); - gcc_assert (!TYPE_UNSIGNED (TREE_TYPE (min))); - min = fold_unary (ABS_EXPR, TREE_TYPE (min), min); - max = fold_unary (ABS_EXPR, TREE_TYPE (max), max); - if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max)) - { - set_value_range_to_varying (vr); - return; - } - cmp = compare_values (min, max); - if (cmp == -1) - min = fold_unary (NEGATE_EXPR, TREE_TYPE (min), max); - else if (cmp == 0 || cmp == 1) - { - max = min; - min = fold_unary (NEGATE_EXPR, TREE_TYPE (min), min); - } - else - { - set_value_range_to_varying (vr); - return; - } - set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL); -} - /* Return true, if VAL1 and VAL2 are equal values for VRP purposes. */ bool @@ -997,6 +961,9 @@ ranges_from_anti_range (value_range *ar, vr0->type = VR_UNDEFINED; vr1->type = VR_UNDEFINED; + /* As a future improvement, we could handle ~[0, A] as: [-INF, -1] U + [A+1, +INF]. Not sure if this helps in practice, though. */ + if (ar->type != VR_ANTI_RANGE || TREE_CODE (ar->min) != INTEGER_CST || TREE_CODE (ar->max) != INTEGER_CST @@ -1034,17 +1001,17 @@ ranges_from_anti_range (value_range *ar, static void inline extract_range_into_wide_ints (value_range *vr, signop sign, unsigned prec, - wide_int *wmin, wide_int *wmax) + wide_int &wmin, wide_int &wmax) { if (range_int_cst_p (vr)) { - *wmin = wi::to_wide (vr->min); - *wmax = wi::to_wide (vr->max); + wmin = wi::to_wide (vr->min); + wmax = wi::to_wide (vr->max); } else { - *wmin = wi::min_value (prec, sign); - *wmax = wi::max_value (prec, sign); + wmin = wi::min_value (prec, sign); + wmax = wi::max_value (prec, sign); } } @@ -1597,8 +1564,8 @@ extract_range_from_binary_expr_1 (value_range *vr, 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); + 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, @@ -1668,109 +1635,55 @@ extract_range_from_binary_expr_1 (value_range *vr, || code == EXACT_DIV_EXPR || code == ROUND_DIV_EXPR) { - if (vr0.type != VR_RANGE || symbolic_range_p (&vr0)) + wide_int dividend_min, dividend_max, divisor_min, divisor_max; + wide_int wmin, wmax, extra_min, extra_max; + bool extra_range_p; + + /* Special case explicit division by zero as undefined. */ + if (range_is_null (&vr1)) { - /* For division, if op1 has VR_RANGE but op0 does not, something - can be deduced just from that range. Say [min, max] / [4, max] - gives [min / 4, max / 4] range. */ - if (vr1.type == VR_RANGE - && !symbolic_range_p (&vr1) - && range_includes_zero_p (vr1.min, vr1.max) == 0) - { - vr0.type = type = VR_RANGE; - vr0.min = vrp_val_min (expr_type); - vr0.max = vrp_val_max (expr_type); - } + /* However, we must not eliminate a division by zero if + flag_non_call_exceptions. */ + if (cfun->can_throw_non_call_exceptions) + set_value_range_to_varying (vr); else - { - set_value_range_to_varying (vr); - return; - } + set_value_range_to_undefined (vr); + return; } - /* For divisions, if flag_non_call_exceptions is true, we must - not eliminate a division by zero. */ - if (cfun->can_throw_non_call_exceptions - && (vr1.type != VR_RANGE - || range_includes_zero_p (vr1.min, vr1.max) != 0)) + /* First, normalize ranges into constants we can handle. Note + that VR_ANTI_RANGE's of constants were already normalized + before arriving here. + + NOTE: As a future improvement, we may be able to do better + with mixed symbolic (anti-)ranges like [0, A]. See note in + ranges_from_anti_range. */ + extract_range_into_wide_ints (&vr0, sign, prec, + dividend_min, dividend_max); + extract_range_into_wide_ints (&vr1, sign, prec, + divisor_min, divisor_max); + if (!wide_int_range_div (wmin, wmax, code, sign, prec, + dividend_min, dividend_max, + divisor_min, divisor_max, + TYPE_OVERFLOW_UNDEFINED (expr_type), + TYPE_OVERFLOW_WRAPS (expr_type), + extra_range_p, extra_min, extra_max)) { set_value_range_to_varying (vr); return; } - - /* For divisions, if op0 is VR_RANGE, we can deduce a range - even if op1 is VR_VARYING, VR_ANTI_RANGE, symbolic or can - include 0. */ - if (vr0.type == VR_RANGE - && (vr1.type != VR_RANGE - || range_includes_zero_p (vr1.min, vr1.max) != 0)) - { - tree zero = build_int_cst (TREE_TYPE (vr0.min), 0); - int cmp; - - min = NULL_TREE; - max = NULL_TREE; - if (TYPE_UNSIGNED (expr_type) - || value_range_nonnegative_p (&vr1)) - { - /* For unsigned division or when divisor is known - to be non-negative, the range has to cover - all numbers from 0 to max for positive max - and all numbers from min to 0 for negative min. */ - cmp = compare_values (vr0.max, zero); - if (cmp == -1) - { - /* When vr0.max < 0, vr1.min != 0 and value - ranges for dividend and divisor are available. */ - if (vr1.type == VR_RANGE - && !symbolic_range_p (&vr0) - && !symbolic_range_p (&vr1) - && compare_values (vr1.min, zero) != 0) - max = int_const_binop (code, vr0.max, vr1.min); - else - max = zero; - } - else if (cmp == 0 || cmp == 1) - max = vr0.max; - else - type = VR_VARYING; - cmp = compare_values (vr0.min, zero); - if (cmp == 1) - { - /* For unsigned division when value ranges for dividend - and divisor are available. */ - if (vr1.type == VR_RANGE - && !symbolic_range_p (&vr0) - && !symbolic_range_p (&vr1) - && compare_values (vr1.max, zero) != 0) - min = int_const_binop (code, vr0.min, vr1.max); - else - min = zero; - } - else if (cmp == 0 || cmp == -1) - min = vr0.min; - else - type = VR_VARYING; - } - else - { - /* Otherwise the range is -max .. max or min .. -min - depending on which bound is bigger in absolute value, - as the division can change the sign. */ - abs_extent_range (vr, vr0.min, vr0.max); - return; - } - if (type == VR_VARYING) - { - set_value_range_to_varying (vr); - return; - } - } - else if (range_int_cst_p (&vr0) && range_int_cst_p (&vr1)) + set_value_range (vr, VR_RANGE, + wide_int_to_tree (expr_type, wmin), + wide_int_to_tree (expr_type, wmax), NULL); + if (extra_range_p) { - extract_range_from_multiplicative_op (vr, code, &vr0, &vr1); - return; + value_range extra_range = VR_INITIALIZER; + set_value_range (&extra_range, VR_RANGE, + wide_int_to_tree (expr_type, extra_min), + wide_int_to_tree (expr_type, extra_max), NULL); + vrp_meet (vr, &extra_range); } + return; } else if (code == TRUNC_MOD_EXPR) { @@ -1781,8 +1694,8 @@ extract_range_from_binary_expr_1 (value_range *vr, } wide_int wmin, wmax, tmp; wide_int vr0_min, vr0_max, 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); + extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max); + extract_range_into_wide_ints (&vr1, sign, prec, vr1_min, vr1_max); wide_int_range_trunc_mod (wmin, wmax, sign, prec, vr0_min, vr0_max, vr1_min, vr1_max); min = wide_int_to_tree (expr_type, wmin); @@ -1803,8 +1716,8 @@ extract_range_from_binary_expr_1 (value_range *vr, &may_be_nonzero0, &must_be_nonzero0); vrp_set_zero_nonzero_bits (expr_type, &vr1, &may_be_nonzero1, &must_be_nonzero1); - extract_range_into_wide_ints (&vr0, sign, prec, &vr0_min, &vr0_max); - extract_range_into_wide_ints (&vr1, sign, prec, &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 (code == BIT_AND_EXPR) { if (wide_int_range_bit_and (wmin, wmax, sign, prec, @@ -2033,7 +1946,7 @@ extract_range_from_unary_expr (value_range *vr, } wide_int wmin, wmax; wide_int vr0_min, vr0_max; - extract_range_into_wide_ints (&vr0, sign, prec, &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, diff --git a/gcc/wide-int-range.cc b/gcc/wide-int-range.cc index a202b5fd503..cbc71c25cfe 100644 --- a/gcc/wide-int-range.cc +++ b/gcc/wide-int-range.cc @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tree.h" +#include "function.h" #include "fold-const.h" #include "wide-int-range.h" @@ -663,3 +664,75 @@ wide_int_range_abs (wide_int &min, wide_int &max, return false; return true; } + +/* Calculate a division operation on two ranges and store the result in + [WMIN, WMAX] U [EXTRA_MIN, EXTRA_MAX]. + + If EXTRA_RANGE_P is set upon return, EXTRA_MIN/EXTRA_MAX hold + meaningful information, otherwise they should be ignored. + + Return TRUE if we were able to successfully calculate the new range. */ + +bool +wide_int_range_div (wide_int &wmin, wide_int &wmax, + tree_code code, signop sign, unsigned prec, + const wide_int ÷nd_min, const wide_int ÷nd_max, + const wide_int &divisor_min, const wide_int &divisor_max, + bool overflow_undefined, + bool overflow_wraps, + bool &extra_range_p, + wide_int &extra_min, wide_int &extra_max) +{ + extra_range_p = false; + + /* If we know we won't divide by zero, just do the division. */ + if (!wide_int_range_includes_zero_p (divisor_min, divisor_max, sign)) + { + wide_int_range_multiplicative_op (wmin, wmax, code, sign, prec, + dividend_min, dividend_max, + divisor_min, divisor_max, + overflow_undefined, + overflow_wraps); + return true; + } + + /* If flag_non_call_exceptions, we must not eliminate a division + by zero. */ + if (cfun->can_throw_non_call_exceptions) + return false; + + /* If we're definitely dividing by zero, there's nothing to do. */ + if (wide_int_range_zero_p (divisor_min, divisor_max, prec)) + return false; + + /* Perform the division in 2 parts, [LB, -1] and [1, UB], + which will skip any division by zero. + + First divide by the negative numbers, if any. */ + if (wi::neg_p (divisor_min, sign)) + { + if (!wide_int_range_multiplicative_op (wmin, wmax, + code, sign, prec, + dividend_min, dividend_max, + divisor_min, wi::minus_one (prec), + overflow_undefined, + overflow_wraps)) + return false; + extra_range_p = true; + } + /* Then divide by the non-zero positive numbers, if any. */ + if (wi::gt_p (divisor_max, wi::zero (prec), sign)) + { + if (!wide_int_range_multiplicative_op (extra_range_p ? extra_min : wmin, + extra_range_p ? extra_max : wmax, + code, sign, prec, + dividend_min, dividend_max, + wi::one (prec), divisor_max, + overflow_undefined, + overflow_wraps)) + return false; + } + else + extra_range_p = false; + return true; +} diff --git a/gcc/wide-int-range.h b/gcc/wide-int-range.h index 41198e05b13..427ef34c6b4 100644 --- a/gcc/wide-int-range.h +++ b/gcc/wide-int-range.h @@ -99,6 +99,17 @@ extern bool wide_int_range_abs (wide_int &min, wide_int &max, const wide_int &vr0_min, const wide_int &vr0_max, bool overflow_undefined); +extern bool wide_int_range_div (wide_int &wmin, wide_int &wmax, + enum tree_code code, + signop sign, unsigned prec, + const wide_int ÷nd_min, + const wide_int ÷nd_max, + const wide_int &divisor_min, + const wide_int &divisor_max, + bool overflow_undefined, + bool overflow_wraps, + bool &extra_range_p, + wide_int &extra_min, wide_int &extra_max); /* Return TRUE if shifting by range [MIN, MAX] is undefined behavior. */ @@ -137,4 +148,22 @@ wide_int_range_min_max (wide_int &min, wide_int &max, return true; } +/* Return TRUE if 0 is within [WMIN, WMAX]. */ + +inline bool +wide_int_range_includes_zero_p (const wide_int &wmin, const wide_int &wmax, + signop sign) +{ + return wi::le_p (wmin, 0, sign) && wi::ge_p (wmax, 0, sign); +} + +/* Return TRUE if [WMIN, WMAX] is the singleton 0. */ + +inline bool +wide_int_range_zero_p (const wide_int &wmin, const wide_int &wmax, + unsigned prec) +{ + return wmin == wmax && wi::eq_p (wmin, wi::zero (prec)); +} + #endif /* GCC_WIDE_INT_RANGE_H */