| /* Support routines for range operations on wide ints. |
| Copyright (C) 2018-2019 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tree.h" |
| #include "function.h" |
| #include "fold-const.h" |
| #include "wide-int-range.h" |
| |
| /* Wrapper around wide_int_binop that adjusts for overflow. |
| |
| Return true if we can compute the result; i.e. if the operation |
| doesn't overflow or if the overflow is undefined. In the latter |
| case (if the operation overflows and overflow is undefined), then |
| adjust the result to be -INF or +INF depending on CODE, VAL1 and |
| VAL2. Return the value in *RES. |
| |
| Return false for division by zero, for which the result is |
| indeterminate. */ |
| |
| static bool |
| wide_int_binop_overflow (wide_int &res, |
| enum tree_code code, |
| const wide_int &w0, const wide_int &w1, |
| signop sign, bool overflow_undefined) |
| { |
| wi::overflow_type overflow; |
| if (!wide_int_binop (res, code, w0, w1, sign, &overflow)) |
| return false; |
| |
| /* If the operation overflowed return -INF or +INF depending on the |
| operation and the combination of signs of the operands. */ |
| if (overflow && overflow_undefined) |
| { |
| switch (code) |
| { |
| case MULT_EXPR: |
| /* For multiplication, the sign of the overflow is given |
| by the comparison of the signs of the operands. */ |
| if (sign == UNSIGNED || w0.sign_mask () == w1.sign_mask ()) |
| res = wi::max_value (w0.get_precision (), sign); |
| else |
| res = wi::min_value (w0.get_precision (), sign); |
| return true; |
| |
| case TRUNC_DIV_EXPR: |
| case FLOOR_DIV_EXPR: |
| case CEIL_DIV_EXPR: |
| case EXACT_DIV_EXPR: |
| case ROUND_DIV_EXPR: |
| /* For division, the only case is -INF / -1 = +INF. */ |
| res = wi::max_value (w0.get_precision (), sign); |
| return true; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| return !overflow; |
| } |
| |
| /* For range [LB, UB] compute two wide_int bit masks. |
| |
| In the MAY_BE_NONZERO bit mask, if some bit is unset, it means that |
| for all numbers in the range the bit is 0, otherwise it might be 0 |
| or 1. |
| |
| In the MUST_BE_NONZERO bit mask, if some bit is set, it means that |
| for all numbers in the range the bit is 1, otherwise it might be 0 |
| or 1. */ |
| |
| void |
| wide_int_range_set_zero_nonzero_bits (signop sign, |
| const wide_int &lb, const wide_int &ub, |
| wide_int &may_be_nonzero, |
| wide_int &must_be_nonzero) |
| { |
| may_be_nonzero = wi::minus_one (lb.get_precision ()); |
| must_be_nonzero = wi::zero (lb.get_precision ()); |
| |
| if (wi::eq_p (lb, ub)) |
| { |
| may_be_nonzero = lb; |
| must_be_nonzero = may_be_nonzero; |
| } |
| else if (wi::ge_p (lb, 0, sign) || wi::lt_p (ub, 0, sign)) |
| { |
| wide_int xor_mask = lb ^ ub; |
| may_be_nonzero = lb | ub; |
| must_be_nonzero = lb & ub; |
| if (xor_mask != 0) |
| { |
| wide_int mask = wi::mask (wi::floor_log2 (xor_mask), false, |
| may_be_nonzero.get_precision ()); |
| may_be_nonzero = may_be_nonzero | mask; |
| must_be_nonzero = wi::bit_and_not (must_be_nonzero, mask); |
| } |
| } |
| } |
| |
| /* Order 2 sets of wide int ranges (w0/w1, w2/w3) and set MIN/MAX |
| accordingly. */ |
| |
| static void |
| 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)) |
| std::swap (w0, w1); |
| if (wi::gt_p (w2, w3, sign)) |
| std::swap (w2, w3); |
| |
| /* Choose min and max from the ordered pairs. */ |
| min = wi::min (w0, w2, sign); |
| max = wi::max (w1, w3, sign); |
| } |
| |
| /* Calculate the cross product of two sets of ranges (VR0 and VR1) and |
| store the result in [RES_LB, RES_UB]. |
| |
| CODE is the operation to perform with sign SIGN. |
| |
| OVERFLOW_UNDEFINED is set if overflow is undefined for the operation type. |
| |
| Return TRUE if we were able to calculate the cross product. */ |
| |
| bool |
| wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub, |
| enum tree_code code, signop sign, |
| const wide_int &vr0_lb, const wide_int &vr0_ub, |
| const wide_int &vr1_lb, const wide_int &vr1_ub, |
| bool overflow_undefined) |
| { |
| wide_int cp1, cp2, cp3, cp4; |
| |
| /* Compute the 4 cross operations, bailing if we get an overflow we |
| can't handle. */ |
| |
| if (!wide_int_binop_overflow (cp1, code, vr0_lb, vr1_lb, sign, |
| overflow_undefined)) |
| return false; |
| |
| if (wi::eq_p (vr0_lb, vr0_ub)) |
| cp3 = cp1; |
| else if (!wide_int_binop_overflow (cp3, code, vr0_ub, vr1_lb, sign, |
| overflow_undefined)) |
| return false; |
| |
| if (wi::eq_p (vr1_lb, vr1_ub)) |
| cp2 = cp1; |
| else if (!wide_int_binop_overflow (cp2, code, vr0_lb, vr1_ub, sign, |
| overflow_undefined)) |
| return false; |
| |
| if (wi::eq_p (vr0_lb, vr0_ub)) |
| cp4 = cp2; |
| else if (!wide_int_binop_overflow (cp4, code, vr0_ub, vr1_ub, sign, |
| overflow_undefined)) |
| return false; |
| |
| wide_int_range_order_set (res_lb, res_ub, cp1, cp2, cp3, cp4, sign); |
| return true; |
| } |
| |
| /* Multiply two ranges when TYPE_OVERFLOW_WRAPS: |
| |
| [RES_LB, RES_UB] = [MIN0, MAX0] * [MIN1, MAX1] |
| |
| This is basically fancy code so we don't drop to varying with an |
| unsigned [-3,-1]*[-3,-1]. |
| |
| Return TRUE if we were able to perform the operation. */ |
| |
| bool |
| wide_int_range_mult_wrapping (wide_int &res_lb, |
| wide_int &res_ub, |
| signop sign, |
| unsigned prec, |
| const wide_int &min0_, |
| const wide_int &max0_, |
| const wide_int &min1_, |
| const wide_int &max1_) |
| { |
| /* This test requires 2*prec bits if both operands are signed and |
| 2*prec + 2 bits if either is not. Therefore, extend the values |
| using the sign of the result to PREC2. From here on out, |
| everthing is just signed math no matter what the input types |
| were. */ |
| widest2_int min0 = widest2_int::from (min0_, sign); |
| widest2_int max0 = widest2_int::from (max0_, sign); |
| widest2_int min1 = widest2_int::from (min1_, sign); |
| widest2_int max1 = widest2_int::from (max1_, sign); |
| widest2_int sizem1 = wi::mask <widest2_int> (prec, false); |
| widest2_int size = sizem1 + 1; |
| |
| /* Canonicalize the intervals. */ |
| if (sign == UNSIGNED) |
| { |
| if (wi::ltu_p (size, min0 + max0)) |
| { |
| min0 -= size; |
| max0 -= size; |
| } |
| |
| if (wi::ltu_p (size, min1 + max1)) |
| { |
| min1 -= size; |
| max1 -= size; |
| } |
| } |
| |
| widest2_int prod0 = min0 * min1; |
| widest2_int prod1 = min0 * max1; |
| widest2_int prod2 = max0 * min1; |
| widest2_int prod3 = max0 * max1; |
| |
| /* Sort the 4 products so that min is in prod0 and max is in |
| prod3. */ |
| /* min0min1 > max0max1 */ |
| if (prod0 > prod3) |
| std::swap (prod0, prod3); |
| |
| /* min0max1 > max0min1 */ |
| if (prod1 > prod2) |
| std::swap (prod1, prod2); |
| |
| if (prod0 > prod1) |
| std::swap (prod0, prod1); |
| |
| if (prod2 > prod3) |
| std::swap (prod2, prod3); |
| |
| /* diff = max - min. */ |
| prod2 = prod3 - prod0; |
| if (wi::geu_p (prod2, sizem1)) |
| /* The range covers all values. */ |
| return false; |
| |
| res_lb = wide_int::from (prod0, prec, sign); |
| res_ub = wide_int::from (prod3, prec, sign); |
| return true; |
| } |
| |
| /* Perform multiplicative operation CODE on two ranges: |
| |
| [RES_LB, RES_UB] = [VR0_LB, VR0_UB] .CODE. [VR1_LB, VR1_LB] |
| |
| Return TRUE if we were able to perform the operation. |
| |
| NOTE: If code is MULT_EXPR and !TYPE_OVERFLOW_UNDEFINED, the resulting |
| range must be canonicalized by the caller because its components |
| may be swapped. */ |
| |
| bool |
| wide_int_range_multiplicative_op (wide_int &res_lb, wide_int &res_ub, |
| enum tree_code code, |
| signop sign, |
| unsigned prec, |
| const wide_int &vr0_lb, |
| const wide_int &vr0_ub, |
| const wide_int &vr1_lb, |
| const wide_int &vr1_ub, |
| bool overflow_undefined) |
| { |
| /* Multiplications, divisions and shifts 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. |
| |
| However, this involves several calls to compare_values and it |
| is pretty convoluted. It's simpler to do the 4 operations |
| (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP |
| MAX1) and then figure the smallest and largest values to form |
| the new range. */ |
| if (code == MULT_EXPR && !overflow_undefined) |
| return wide_int_range_mult_wrapping (res_lb, res_ub, |
| sign, prec, |
| vr0_lb, vr0_ub, vr1_lb, vr1_ub); |
| return wide_int_range_cross_product (res_lb, res_ub, |
| code, sign, |
| vr0_lb, vr0_ub, vr1_lb, vr1_ub, |
| overflow_undefined); |
| } |
| |
| /* Perform a left shift operation on two ranges: |
| |
| [RES_LB, RES_UB] = [VR0_LB, VR0_UB] << [VR1_LB, VR1_LB] |
| |
| Return TRUE if we were able to perform the operation. |
| |
| NOTE: The resulting range must be canonicalized by the caller |
| because its contents components may be swapped. */ |
| |
| bool |
| wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub, |
| signop sign, unsigned prec, |
| const wide_int &vr0_lb, const wide_int &vr0_ub, |
| const wide_int &vr1_lb, const wide_int &vr1_ub, |
| bool overflow_undefined) |
| { |
| /* Transform left shifts by constants into multiplies. */ |
| if (wi::eq_p (vr1_lb, vr1_ub)) |
| { |
| unsigned shift = vr1_ub.to_uhwi (); |
| wide_int tmp = wi::set_bit_in_zero (shift, prec); |
| return wide_int_range_multiplicative_op (res_lb, res_ub, |
| MULT_EXPR, sign, prec, |
| vr0_lb, vr0_ub, tmp, tmp, |
| /*overflow_undefined=*/false); |
| } |
| |
| int overflow_pos = prec; |
| if (sign == SIGNED) |
| overflow_pos -= 1; |
| int bound_shift = overflow_pos - vr1_ub.to_shwi (); |
| /* If bound_shift == HOST_BITS_PER_WIDE_INT, the llshift can |
| overflow. However, for that to happen, vr1.max needs to be |
| zero, which means vr1 is a singleton range of zero, which |
| means it should be handled by the previous LSHIFT_EXPR |
| if-clause. */ |
| wide_int bound = wi::set_bit_in_zero (bound_shift, prec); |
| wide_int complement = ~(bound - 1); |
| wide_int low_bound, high_bound; |
| bool in_bounds = false; |
| if (sign == UNSIGNED) |
| { |
| low_bound = bound; |
| high_bound = complement; |
| if (wi::ltu_p (vr0_ub, low_bound)) |
| { |
| /* [5, 6] << [1, 2] == [10, 24]. */ |
| /* We're shifting out only zeroes, the value increases |
| monotonically. */ |
| in_bounds = true; |
| } |
| else if (wi::ltu_p (high_bound, vr0_lb)) |
| { |
| /* [0xffffff00, 0xffffffff] << [1, 2] |
| == [0xfffffc00, 0xfffffffe]. */ |
| /* We're shifting out only ones, the value decreases |
| monotonically. */ |
| in_bounds = true; |
| } |
| } |
| else |
| { |
| /* [-1, 1] << [1, 2] == [-4, 4]. */ |
| low_bound = complement; |
| high_bound = bound; |
| if (wi::lts_p (vr0_ub, high_bound) |
| && wi::lts_p (low_bound, vr0_lb)) |
| { |
| /* For non-negative numbers, we're shifting out only |
| zeroes, the value increases monotonically. |
| For negative numbers, we're shifting out only ones, the |
| value decreases monotomically. */ |
| in_bounds = true; |
| } |
| } |
| if (in_bounds) |
| return wide_int_range_multiplicative_op (res_lb, res_ub, |
| LSHIFT_EXPR, sign, prec, |
| vr0_lb, vr0_ub, |
| vr1_lb, vr1_ub, |
| overflow_undefined); |
| return false; |
| } |
| |
| /* Return TRUE if a bit operation on two ranges can be easily |
| optimized in terms of a mask. |
| |
| Basically, for BIT_AND_EXPR or BIT_IOR_EXPR see if we can optimize: |
| |
| [LB, UB] op Z |
| into: |
| [LB op Z, UB op Z] |
| |
| It is up to the caller to perform the actual folding above. */ |
| |
| static bool |
| wide_int_range_can_optimize_bit_op (tree_code code, |
| const wide_int &lb, const wide_int &ub, |
| const wide_int &mask) |
| |
| { |
| if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR) |
| return false; |
| /* If Z is a constant which (for op | its bitwise not) has n |
| consecutive least significant bits cleared followed by m 1 |
| consecutive bits set immediately above it and either |
| m + n == precision, or (x >> (m + n)) == (y >> (m + n)). |
| |
| The least significant n bits of all the values in the range are |
| cleared or set, the m bits above it are preserved and any bits |
| above these are required to be the same for all values in the |
| range. */ |
| |
| wide_int w = mask; |
| int m = 0, n = 0; |
| if (code == BIT_IOR_EXPR) |
| w = ~w; |
| if (wi::eq_p (w, 0)) |
| n = w.get_precision (); |
| else |
| { |
| n = wi::ctz (w); |
| w = ~(w | wi::mask (n, false, w.get_precision ())); |
| if (wi::eq_p (w, 0)) |
| m = w.get_precision () - n; |
| else |
| m = wi::ctz (w) - n; |
| } |
| wide_int new_mask = wi::mask (m + n, true, w.get_precision ()); |
| if ((new_mask & lb) == (new_mask & ub)) |
| return true; |
| |
| return false; |
| } |
| |
| /* Helper function for wide_int_range_optimize_bit_op. |
| |
| Calculates bounds and mask for a pair of ranges. The mask is the |
| singleton range among the ranges, if any. The bounds are the |
| bounds for the remaining range. */ |
| |
| bool |
| wide_int_range_get_mask_and_bounds (wide_int &mask, |
| wide_int &lower_bound, |
| wide_int &upper_bound, |
| const wide_int &vr0_min, |
| const wide_int &vr0_max, |
| const wide_int &vr1_min, |
| const wide_int &vr1_max) |
| { |
| if (wi::eq_p (vr1_min, vr1_max)) |
| { |
| mask = vr1_min; |
| lower_bound = vr0_min; |
| upper_bound = vr0_max; |
| return true; |
| } |
| else if (wi::eq_p (vr0_min, vr0_max)) |
| { |
| mask = vr0_min; |
| lower_bound = vr1_min; |
| upper_bound = vr1_max; |
| return true; |
| } |
| return false; |
| } |
| |
| /* Optimize a bit operation (BIT_AND_EXPR or BIT_IOR_EXPR) if |
| possible. If so, return TRUE and store the result in |
| [RES_LB, RES_UB]. */ |
| |
| bool |
| wide_int_range_optimize_bit_op (wide_int &res_lb, wide_int &res_ub, |
| enum tree_code code, |
| signop sign, |
| const wide_int &vr0_min, |
| const wide_int &vr0_max, |
| const wide_int &vr1_min, |
| const wide_int &vr1_max) |
| { |
| gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); |
| |
| wide_int lower_bound, upper_bound, mask; |
| if (!wide_int_range_get_mask_and_bounds (mask, lower_bound, upper_bound, |
| vr0_min, vr0_max, vr1_min, vr1_max)) |
| return false; |
| if (wide_int_range_can_optimize_bit_op (code, |
| lower_bound, upper_bound, mask)) |
| { |
| wi::overflow_type ovf; |
| wide_int_binop (res_lb, code, lower_bound, mask, sign, &ovf); |
| wide_int_binop (res_ub, code, upper_bound, mask, sign, &ovf); |
| return true; |
| } |
| return false; |
| } |
| |
| /* Calculate the XOR of two ranges and store the result in [WMIN,WMAX]. |
| The two input ranges are described by their MUST_BE_NONZERO and |
| MAY_BE_NONZERO bit masks. |
| |
| Return TRUE if we were able to successfully calculate the new range. */ |
| |
| bool |
| wide_int_range_bit_xor (wide_int &wmin, wide_int &wmax, |
| signop sign, |
| unsigned prec, |
| const wide_int &must_be_nonzero0, |
| const wide_int &may_be_nonzero0, |
| const wide_int &must_be_nonzero1, |
| const wide_int &may_be_nonzero1) |
| { |
| wide_int result_zero_bits = ((must_be_nonzero0 & must_be_nonzero1) |
| | ~(may_be_nonzero0 | may_be_nonzero1)); |
| wide_int result_one_bits |
| = (wi::bit_and_not (must_be_nonzero0, may_be_nonzero1) |
| | wi::bit_and_not (must_be_nonzero1, may_be_nonzero0)); |
| wmax = ~result_zero_bits; |
| wmin = result_one_bits; |
| /* If the range has all positive or all negative values, the result |
| is better than VARYING. */ |
| if (wi::lt_p (wmin, 0, sign) || wi::ge_p (wmax, 0, sign)) |
| return true; |
| wmin = wi::min_value (prec, sign); |
| wmax = wi::max_value (prec, sign); |
| return false; |
| } |
| |
| /* Calculate the IOR of two ranges and store the result in [WMIN,WMAX]. |
| Return TRUE if we were able to successfully calculate the new range. */ |
| |
| bool |
| wide_int_range_bit_ior (wide_int &wmin, wide_int &wmax, |
| signop sign, |
| const wide_int &vr0_min, |
| const wide_int &vr0_max, |
| const wide_int &vr1_min, |
| const wide_int &vr1_max, |
| const wide_int &must_be_nonzero0, |
| const wide_int &may_be_nonzero0, |
| const wide_int &must_be_nonzero1, |
| const wide_int &may_be_nonzero1) |
| { |
| if (wide_int_range_optimize_bit_op (wmin, wmax, BIT_IOR_EXPR, sign, |
| vr0_min, vr0_max, |
| vr1_min, vr1_max)) |
| return true; |
| wmin = must_be_nonzero0 | must_be_nonzero1; |
| wmax = may_be_nonzero0 | may_be_nonzero1; |
| /* If the input ranges contain only positive values we can |
| truncate the minimum of the result range to the maximum |
| of the input range minima. */ |
| if (wi::ge_p (vr0_min, 0, sign) |
| && wi::ge_p (vr1_min, 0, sign)) |
| { |
| wmin = wi::max (wmin, vr0_min, sign); |
| wmin = wi::max (wmin, vr1_min, sign); |
| } |
| /* If either input range contains only negative values |
| we can truncate the minimum of the result range to the |
| respective minimum range. */ |
| if (wi::lt_p (vr0_max, 0, sign)) |
| wmin = wi::max (wmin, vr0_min, sign); |
| if (wi::lt_p (vr1_max, 0, sign)) |
| wmin = wi::max (wmin, vr1_min, sign); |
| /* If the limits got swapped around, indicate error so we can adjust |
| the range to VARYING. */ |
| if (wi::gt_p (wmin, wmax,sign)) |
| return false; |
| return true; |
| } |
| |
| /* Calculate the bitwise AND of two ranges and store the result in [WMIN,WMAX]. |
| Return TRUE if we were able to successfully calculate the new range. */ |
| |
| bool |
| wide_int_range_bit_and (wide_int &wmin, wide_int &wmax, |
| signop sign, |
| unsigned prec, |
| const wide_int &vr0_min, |
| const wide_int &vr0_max, |
| const wide_int &vr1_min, |
| const wide_int &vr1_max, |
| const wide_int &must_be_nonzero0, |
| const wide_int &may_be_nonzero0, |
| const wide_int &must_be_nonzero1, |
| const wide_int &may_be_nonzero1) |
| { |
| if (wide_int_range_optimize_bit_op (wmin, wmax, BIT_AND_EXPR, sign, |
| vr0_min, vr0_max, |
| vr1_min, vr1_max)) |
| return true; |
| wmin = must_be_nonzero0 & must_be_nonzero1; |
| wmax = may_be_nonzero0 & may_be_nonzero1; |
| /* If both input ranges contain only negative values we can |
| truncate the result range maximum to the minimum of the |
| input range maxima. */ |
| if (wi::lt_p (vr0_max, 0, sign) && wi::lt_p (vr1_max, 0, sign)) |
| { |
| wmax = wi::min (wmax, vr0_max, sign); |
| wmax = wi::min (wmax, vr1_max, sign); |
| } |
| /* If either input range contains only non-negative values |
| we can truncate the result range maximum to the respective |
| maximum of the input range. */ |
| if (wi::ge_p (vr0_min, 0, sign)) |
| wmax = wi::min (wmax, vr0_max, sign); |
| if (wi::ge_p (vr1_min, 0, sign)) |
| wmax = wi::min (wmax, vr1_max, sign); |
| /* PR68217: In case of signed & sign-bit-CST should |
| result in [-INF, 0] instead of [-INF, INF]. */ |
| if (wi::gt_p (wmin, wmax, sign)) |
| { |
| wide_int sign_bit = wi::set_bit_in_zero (prec - 1, prec); |
| if (sign == SIGNED |
| && ((wi::eq_p (vr0_min, vr0_max) |
| && !wi::cmps (vr0_min, sign_bit)) |
| || (wi::eq_p (vr1_min, vr1_max) |
| && !wi::cmps (vr1_min, sign_bit)))) |
| { |
| wmin = wi::min_value (prec, sign); |
| wmax = wi::zero (prec); |
| } |
| } |
| /* If the limits got swapped around, indicate error so we can adjust |
| the range to VARYING. */ |
| if (wi::gt_p (wmin, wmax,sign)) |
| return false; |
| return true; |
| } |
| |
| /* Calculate TRUNC_MOD_EXPR on two ranges and store the result in |
| [WMIN,WMAX]. */ |
| |
| void |
| wide_int_range_trunc_mod (wide_int &wmin, wide_int &wmax, |
| signop sign, |
| unsigned prec, |
| const wide_int &vr0_min, |
| const wide_int &vr0_max, |
| const wide_int &vr1_min, |
| const wide_int &vr1_max) |
| { |
| wide_int tmp; |
| |
| /* ABS (A % B) < ABS (B) and either |
| 0 <= A % B <= A or A <= A % B <= 0. */ |
| wmax = vr1_max - 1; |
| if (sign == SIGNED) |
| { |
| tmp = -1 - vr1_min; |
| wmax = wi::smax (wmax, tmp); |
| } |
| |
| if (sign == UNSIGNED) |
| wmin = wi::zero (prec); |
| else |
| { |
| wmin = -wmax; |
| tmp = vr0_min; |
| if (wi::gts_p (tmp, 0)) |
| tmp = wi::zero (prec); |
| wmin = wi::smax (wmin, tmp); |
| } |
| tmp = vr0_max; |
| if (sign == SIGNED && wi::neg_p (tmp)) |
| 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. The only thing |
| we know is that the result is positive. */ |
| if (wi::gt_p (min, max, sign)) |
| { |
| min = wi::zero (prec); |
| max = max_value; |
| } |
| return true; |
| } |
| |
| /* Calculate ABSU_EXPR on a range and store the result in [MIN, MAX]. */ |
| |
| void |
| wide_int_range_absu (wide_int &min, wide_int &max, |
| unsigned prec, const wide_int &vr0_min, |
| const wide_int &vr0_max) |
| { |
| /* Pass through VR0 the easy cases. */ |
| if (wi::ges_p (vr0_min, 0)) |
| { |
| min = vr0_min; |
| max = vr0_max; |
| return; |
| } |
| |
| min = wi::abs (vr0_min); |
| 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::ges_p (vr0_max, 0)) |
| { |
| if (wi::gtu_p (min, max)) |
| max = min; |
| min = wi::zero (prec); |
| } |
| else |
| /* Otherwise, swap MIN and MAX. */ |
| std::swap (min, max); |
| } |
| |
| /* Convert range in [VR0_MIN, VR0_MAX] with INNER_SIGN and INNER_PREC, |
| to a range in [MIN, MAX] with OUTER_SIGN and OUTER_PREC. |
| |
| Return TRUE if we were able to successfully calculate the new range. |
| |
| Caller is responsible for canonicalizing the resulting range. */ |
| |
| bool |
| wide_int_range_convert (wide_int &min, wide_int &max, |
| signop inner_sign, |
| unsigned inner_prec, |
| signop outer_sign, |
| unsigned outer_prec, |
| const wide_int &vr0_min, |
| const wide_int &vr0_max) |
| { |
| /* If the conversion is not truncating we can convert the min and |
| max values and canonicalize the resulting range. Otherwise we |
| can do the conversion if the size of the range is less than what |
| the precision of the target type can represent. */ |
| if (outer_prec >= inner_prec |
| || wi::rshift (wi::sub (vr0_max, vr0_min), |
| wi::uhwi (outer_prec, inner_prec), |
| inner_sign) == 0) |
| { |
| min = wide_int::from (vr0_min, outer_prec, inner_sign); |
| max = wide_int::from (vr0_max, outer_prec, inner_sign); |
| return (!wi::eq_p (min, wi::min_value (outer_prec, outer_sign)) |
| || !wi::eq_p (max, wi::max_value (outer_prec, outer_sign))); |
| } |
| return false; |
| } |
| |
| /* 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 &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)) |
| return wide_int_range_multiplicative_op (wmin, wmax, code, sign, prec, |
| dividend_min, dividend_max, |
| divisor_min, divisor_max, |
| overflow_undefined); |
| |
| /* 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)) |
| 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)) |
| return false; |
| } |
| else |
| extra_range_p = false; |
| return true; |
| } |