| /* 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/>. */ |
| |
| #ifndef GCC_WIDE_INT_RANGE_H |
| #define GCC_WIDE_INT_RANGE_H |
| |
| extern bool wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub, |
| enum tree_code code, signop sign, |
| const wide_int &, const wide_int &, |
| const wide_int &, const wide_int &, |
| bool overflow_undefined); |
| extern 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_); |
| extern 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); |
| extern bool wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub, |
| signop sign, unsigned prec, |
| const wide_int &, const wide_int &, |
| const wide_int &, const wide_int &, |
| bool overflow_undefined); |
| extern void wide_int_range_set_zero_nonzero_bits (signop, |
| const wide_int &lb, |
| const wide_int &ub, |
| wide_int &may_be_nonzero, |
| wide_int &must_be_nonzero); |
| extern 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_lb, |
| const wide_int &vr0_ub, |
| const wide_int &vr1_lb, |
| const wide_int &vr1_ub); |
| extern 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); |
| extern 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); |
| extern 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); |
| extern 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); |
| extern 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); |
| 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); |
| extern void wide_int_range_absu (wide_int &min, wide_int &max, |
| unsigned prec, |
| const wide_int &vr0_min, |
| const wide_int &vr0_max); |
| extern 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); |
| 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 &extra_range_p, |
| wide_int &extra_min, wide_int &extra_max); |
| |
| /* Return TRUE if shifting by range [MIN, MAX] is undefined behavior, |
| interpreting MIN and MAX according to SIGN. */ |
| |
| inline bool |
| wide_int_range_shift_undefined_p (signop sign, unsigned prec, |
| const wide_int &min, const wide_int &max) |
| { |
| /* ?? Note: The original comment said this only applied to |
| RSHIFT_EXPR, but it was being applied to both left and right |
| shifts. */ |
| |
| /* Shifting by any values outside [0..prec-1], gets undefined |
| behavior from the shift operation. We cannot even trust |
| SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl |
| shifts, and the operation at the tree level may be widened. */ |
| 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; |
| } |
| |
| /* 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 */ |