aboutsummaryrefslogtreecommitdiff
path: root/gcc/wide-int-range.cc
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2018-08-23 13:25:36 +0000
committerAldy Hernandez <aldyh@gcc.gnu.org>2018-08-23 13:25:36 +0000
commit62852194225ed2df31ff6a600659e5cefbb1e8c0 (patch)
tree0ae9ff87faf8a472941922a6c3732b1148f5c74f /gcc/wide-int-range.cc
parent488461d8622d5d7b5f85612562fd5abb979f5d57 (diff)
downloadgcc-62852194225ed2df31ff6a600659e5cefbb1e8c0.zip
gcc-62852194225ed2df31ff6a600659e5cefbb1e8c0.tar.gz
gcc-62852194225ed2df31ff6a600659e5cefbb1e8c0.tar.bz2
tree-vrp.c (abs_extent_range): Remove.
* 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. From-SVN: r263813
Diffstat (limited to 'gcc/wide-int-range.cc')
-rw-r--r--gcc/wide-int-range.cc73
1 files changed, 73 insertions, 0 deletions
diff --git a/gcc/wide-int-range.cc b/gcc/wide-int-range.cc
index a202b5f..cbc71c2 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 &dividend_min, const wide_int &dividend_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;
+}