abstract remaining wide int operations in VRP
diff mbox series

Message ID 870b9190-3784-964f-f2f8-7250e3e3bcc4@redhat.com
State New
Headers show
Series
  • abstract remaining wide int operations in VRP
Related show

Commit Message

Aldy Hernandez July 30, 2018, 7:09 a.m. UTC
...well, most of them anyhow...

I got tired of submitting these piecemeal, and it's probably easier to 
review them in one go.

There should be no difference in functionality, barring an extra call to 
set_and_canonicalize_value_range (instead of set_value_range) due to the 
way I've organized multiplication and lshifts for maximal sharing.  This 
also gets rid of some repetitive stuff.

I've also added a value_range::dump like wide_int::dump.  It makes 
debugging a lot easier.

My next patch will move all the wide_int_range_* stuff into 
wide-int-range.[hc].

I'm really liking how this is turning out, BTW: a *lot* cleaner, less 
code duplication, and shareable to boot :).

OK pending one more round of tests?

Aldy

Comments

Richard Biener Aug. 1, 2018, 10:32 a.m. UTC | #1
On Mon, Jul 30, 2018 at 9:09 AM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> ...well, most of them anyhow...
>
> I got tired of submitting these piecemeal, and it's probably easier to
> review them in one go.
>
> There should be no difference in functionality, barring an extra call to
> set_and_canonicalize_value_range (instead of set_value_range) due to the
> way I've organized multiplication and lshifts for maximal sharing.  This
> also gets rid of some repetitive stuff.
>
> I've also added a value_range::dump like wide_int::dump.  It makes
> debugging a lot easier.
>
> My next patch will move all the wide_int_range_* stuff into
> wide-int-range.[hc].
>
> I'm really liking how this is turning out, BTW: a *lot* cleaner, less
> code duplication, and shareable to boot :).
>
> OK pending one more round of tests?

Only coarsely reviewed the big patch but the result looks nice.

Thus, OK.

Thanks,
Richard.

> Aldy

Patch
diff mbox series

gcc/

	* tree-vrp (zero_nonzero_bits_from_bounds): Rename to...
	(wide_int_set_zero_nonzero_bits): ...this.
	(zero_nonzero_bits_from_vr): Rename to...
	(vrp_set_zero_nonzero_bits): ...this.
	(extract_range_from_multiplicative_op_1): Abstract wide int
	code...
	(wide_int_range_multiplicative_op): ...here.
	(extract_range_from_binary_expr_1): Extract wide int binary
	operations into their own functions.
	(wide_int_range_lshift): New.
	(wide_int_range_can_optimize_bit_op): New.
	(wide_int_range_shift_undefined_p): New.
	(wide_int_range_bit_xor): New.
	(wide_int_range_bit_ior): New.
	(wide_int_range_bit_and): New.
	(wide_int_range_trunc_mod): New.
	(extract_range_into_wide_ints): New.
	(vrp_shift_undefined_p): New.
	(extract_range_from_multiplicative_op): New.
	(vrp_can_optimize_bit_op): New.
	* tree-vrp.h (value_range::dump): New.
	(wide_int_range_multiplicative_op): New.
	(wide_int_range_lshift):New.
	(wide_int_range_shift_undefined_p): New.
	(wide_int_range_bit_xor): New.
	(wide_int_range_bit_ior): New.
	(wide_int_range_bit_and): New.
	(wide_int_range_trunc_mod): New.
	(zero_nonzero_bits_from_bounds): Rename to...
	(wide_int_set_zero_nonzero_bits): ...this.
	(zero_nonzero_bits_from_vr): Rename to...
	(vrp_set_zero_nonzero_bits): ...this.
	(range_easy_mask_min_max): Rename to...
	(wide_int_range_can_optimize_bit_op): this.
	* vr-values.c (simplify_bit_ops_using_ranges): Rename
	zero_nonzero_bits_from_vr into vrp_set_zero_nonzero_bits.

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 7ab8898b453..619be7d07be 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -1008,45 +1008,54 @@  wide_int_binop_overflow (wide_int &res,
   return !overflow;
 }
 
-/* For range [LB, UB] compute two wide_int bitmasks.  In *MAY_BE_NONZERO
-   bitmask, if some bit is unset, it means for all numbers in the range
-   the bit is 0, otherwise it might be 0 or 1.  In *MUST_BE_NONZERO
-   bitmask, if some bit is set, it means for all numbers in the range
-   the bit is 1, otherwise it might be 0 or 1.  */
+/* 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
-zero_nonzero_bits_from_bounds (signop sign,
-			       const wide_int &lb, const wide_int &ub,
-			       wide_int *may_be_nonzero,
-			       wide_int *must_be_nonzero)
+wide_int_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 ());
+  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;
+      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;
+      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);
+				    may_be_nonzero.get_precision ());
+	  may_be_nonzero = may_be_nonzero | mask;
+	  must_be_nonzero = wi::bit_and_not (must_be_nonzero, mask);
 	}
     }
 }
 
-/* Like zero_nonzero_bits_from_bounds, but use the range in value_range VR.  */
+/* Value range wrapper for wide_int_set_zero_nonzero_bits.
+
+   Compute MAY_BE_NONZERO and MUST_BE_NONZERO bit masks for range in VR.
+
+   Return TRUE if VR was a constant range and we were able to compute
+   the bit masks.  */
 
 bool
-zero_nonzero_bits_from_vr (const tree expr_type,
+vrp_set_zero_nonzero_bits (const tree expr_type,
 			   value_range *vr,
 			   wide_int *may_be_nonzero,
 			   wide_int *must_be_nonzero)
@@ -1057,10 +1066,9 @@  zero_nonzero_bits_from_vr (const tree expr_type,
       *must_be_nonzero = wi::zero (TYPE_PRECISION (expr_type));
       return false;
     }
-
-  zero_nonzero_bits_from_bounds (TYPE_SIGN (expr_type),
+  wide_int_set_zero_nonzero_bits (TYPE_SIGN (expr_type),
 				 wi::to_wide (vr->min), wi::to_wide (vr->max),
-				 may_be_nonzero, must_be_nonzero);
+				 *may_be_nonzero, *must_be_nonzero);
   return true;
 }
 
@@ -1177,7 +1185,9 @@  wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub,
      [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].  */
+   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,
@@ -1249,13 +1259,27 @@  wide_int_range_mult_wrapping (wide_int &res_lb,
   return true;
 }
 
-/* Helper to extract a value-range *VR for a multiplicative operation
-   *VR0 CODE *VR1.  */
+/* Perform multiplicative operation CODE on two ranges:
 
-static void
-extract_range_from_multiplicative_op_1 (value_range *vr,
-					enum tree_code code,
-					value_range *vr0, value_range *vr1)
+     [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_WRAPS, 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,
+				  bool overflow_wraps)
 {
   /* Multiplications, divisions and shifts are a bit tricky to handle,
      depending on the mix of signs we have in the two ranges, we
@@ -1269,62 +1293,131 @@  extract_range_from_multiplicative_op_1 (value_range *vr,
      (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.  */
-  gcc_assert (code == MULT_EXPR
-	      || code == TRUNC_DIV_EXPR
-	      || code == FLOOR_DIV_EXPR
-	      || code == CEIL_DIV_EXPR
-	      || code == EXACT_DIV_EXPR
-	      || code == ROUND_DIV_EXPR
-	      || code == RSHIFT_EXPR
-	      || code == LSHIFT_EXPR);
-  gcc_assert (vr0->type == VR_RANGE
-	      && vr0->type == vr1->type);
+  if (code == MULT_EXPR && overflow_wraps)
+    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);
+}
 
-  tree type = TREE_TYPE (vr0->min);
-  wide_int res_lb, res_ub;
-  wide_int vr0_lb = wi::to_wide (vr0->min);
-  wide_int vr0_ub = wi::to_wide (vr0->max);
-  wide_int vr1_lb = wi::to_wide (vr1->min);
-  wide_int vr1_ub = wi::to_wide (vr1->max);
-  bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (vr0->min));
+/* Perform a left shift operation on two ranges:
 
-  if (!wide_int_range_cross_product (res_lb, res_ub,
-				     code, TYPE_SIGN (type),
-				     vr0_lb, vr0_ub, vr1_lb, vr1_ub,
-				     overflow_undefined))
+     [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, bool overflow_wraps)
+{
+  /* Transform left shifts by constants into multiplies.  */
+  if (wi::eq_p (vr1_lb, vr1_ub))
     {
-      set_value_range_to_varying (vr);
-      return;
+      int shift = wi::extract_uhwi (vr1_ub, 0, vr1_ub.get_precision ());
+      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,
+					       /*overflow_wraps=*/true);
+    }
+
+  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;
+	}
     }
-  set_value_range (vr, VR_RANGE,
-		   wide_int_to_tree (type, res_lb),
-		   wide_int_to_tree (type, res_ub), NULL);
+  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,
+					     overflow_wraps);
+  return false;
 }
 
-/* For op & or | attempt to optimize:
+/* 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]
 
-   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.
-
-   Return TRUE if the min and max can simply be folded.  */
+   It is up to the caller to perform the actual folding above.  */
 
 bool
-range_easy_mask_min_max (tree_code code,
-			 const wide_int &lb, const wide_int &ub,
-			 const wide_int &mask)
+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)
@@ -1347,6 +1440,308 @@  range_easy_mask_min_max (tree_code code,
   return false;
 }
 
+/* Return TRUE if shifting by range [MIN, MAX] is undefined behavior.
+
+   FIXME: Make this inline when it moves outside of tree-vrp.  */
+
+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.  Is this OK?  */
+
+  /* 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 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)
+{
+  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)
+{
+  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);
+}
+
+/* Extract the components of a value range into a pair of wide ints in
+   [WMIN, WMAX].
+
+   If the value range is anything but a VR_RANGE of constants, the
+   resulting wide ints are set to [-MIN, +MAX] for the type.  */
+
+static void inline
+extract_range_into_wide_ints (value_range *vr,
+			      signop sign, unsigned prec,
+			      wide_int *wmin, wide_int *wmax)
+{
+  if (range_int_cst_p (vr))
+    {
+      *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);
+    }
+}
+
+/* Value range wrapper for wide_int_range_shift_undefined_p.  */
+
+static inline bool
+vrp_shift_undefined_p (const value_range &shifter)
+{
+  tree type = TREE_TYPE (shifter.min);
+  return wide_int_range_shift_undefined_p (TYPE_SIGN (type),
+					   TYPE_PRECISION (type),
+					   wi::to_wide (shifter.min),
+					   wi::to_wide (shifter.max));
+}
+
+/* Value range wrapper for wide_int_range_multiplicative_op:
+
+     *VR = *VR0 .CODE. *VR1.  */
+
+static void
+extract_range_from_multiplicative_op (value_range *vr,
+				      enum tree_code code,
+				      value_range *vr0, value_range *vr1)
+{
+  gcc_assert (code == MULT_EXPR
+	      || code == TRUNC_DIV_EXPR
+	      || code == FLOOR_DIV_EXPR
+	      || code == CEIL_DIV_EXPR
+	      || code == EXACT_DIV_EXPR
+	      || code == ROUND_DIV_EXPR
+	      || code == RSHIFT_EXPR
+	      || code == LSHIFT_EXPR);
+  gcc_assert (vr0->type == VR_RANGE && vr0->type == vr1->type);
+
+  tree type = TREE_TYPE (vr0->min);
+  wide_int res_lb, res_ub;
+  wide_int vr0_lb = wi::to_wide (vr0->min);
+  wide_int vr0_ub = wi::to_wide (vr0->max);
+  wide_int vr1_lb = wi::to_wide (vr1->min);
+  wide_int vr1_ub = wi::to_wide (vr1->max);
+  bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
+  bool overflow_wraps = TYPE_OVERFLOW_WRAPS (type);
+  unsigned prec = TYPE_PRECISION (type);
+
+  if (wide_int_range_multiplicative_op (res_lb, res_ub,
+					 code, TYPE_SIGN (type), prec,
+					 vr0_lb, vr0_ub, vr1_lb, vr1_ub,
+					 overflow_undefined, overflow_wraps))
+    set_and_canonicalize_value_range (vr, VR_RANGE,
+				      wide_int_to_tree (type, res_lb),
+				      wide_int_to_tree (type, res_ub), NULL);
+  else
+    set_value_range_to_varying (vr);
+}
+
+/* Value range wrapper for wide_int_range_can_optimize_bit_op.
+
+   If a bit operation on two ranges can be easily optimized in terms
+   of a mask, store the optimized new range in VR and return TRUE.  */
+
+static bool
+vrp_can_optimize_bit_op (value_range *vr, enum tree_code code,
+			 value_range *vr0, value_range *vr1)
+{
+  tree lower_bound, upper_bound, mask;
+  if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR)
+    return false;
+  if (range_int_cst_singleton_p (vr1))
+    {
+      if (!range_int_cst_p (vr0))
+	return false;
+      mask = vr1->min;
+      lower_bound = vr0->min;
+      upper_bound = vr0->max;
+    }
+  else if (range_int_cst_singleton_p (vr0))
+    {
+      if (!range_int_cst_p (vr1))
+	return false;
+      mask = vr0->min;
+      lower_bound = vr1->min;
+      upper_bound = vr1->max;
+    }
+  else
+    return false;
+  if (wide_int_range_can_optimize_bit_op (code,
+					  wi::to_wide (lower_bound),
+					  wi::to_wide (upper_bound),
+					  wi::to_wide (mask)))
+    {
+      tree min = int_const_binop (code, lower_bound, mask);
+      tree max = int_const_binop (code, upper_bound, mask);
+      set_value_range (vr, VR_RANGE, min, max, NULL);
+      return true;
+    }
+  return false;
+}
+
 /* If BOUND will include a symbolic bound, adjust it accordingly,
    otherwise leave it as is.
 
@@ -1522,6 +1917,8 @@  extract_range_from_binary_expr_1 (value_range *vr,
 				  enum tree_code code, tree expr_type,
 				  value_range *vr0_, value_range *vr1_)
 {
+  signop sign = TYPE_SIGN (expr_type);
+  unsigned int prec = TYPE_PRECISION (expr_type);
   value_range vr0 = *vr0_, vr1 = *vr1_;
   value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
   enum value_range_type type;
@@ -1845,40 +2242,14 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	  set_value_range_to_varying (vr);
 	  return;
 	}
-      if (TYPE_OVERFLOW_WRAPS (expr_type))
-	{
-	  signop sign = TYPE_SIGN (expr_type);
-	  unsigned int prec = TYPE_PRECISION (expr_type);
-	  wide_int res_lb, res_ub;
-	  if (!wide_int_range_mult_wrapping (res_lb, res_ub,
-					     sign, prec,
-					     wi::to_wide (vr0.min),
-					     wi::to_wide (vr0.max),
-					     wi::to_wide (vr1.min),
-					     wi::to_wide (vr1.max)))
-	    {
-	      set_value_range_to_varying (vr);
-	      return;
-	    }
-	  min = wide_int_to_tree (expr_type, res_lb);
-	  max = wide_int_to_tree (expr_type, res_ub);
-	  set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
-	  return;
-	}
-      extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+      extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
       return;
     }
   else if (code == RSHIFT_EXPR
 	   || code == LSHIFT_EXPR)
     {
-      /* If we have a RSHIFT_EXPR with any shift values outside [0..prec-1],
-	 then drop to VR_VARYING.  Outside of this range we get 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.  */
       if (range_int_cst_p (&vr1)
-	  && compare_tree_int (vr1.min, 0) >= 0
-	  && compare_tree_int (vr1.max, TYPE_PRECISION (expr_type)) == -1)
+	  && !vrp_shift_undefined_p (vr1))
 	{
 	  if (code == RSHIFT_EXPR)
 	    {
@@ -1891,91 +2262,25 @@  extract_range_from_binary_expr_1 (value_range *vr,
 		  vr0.min = vrp_val_min (expr_type);
 		  vr0.max = vrp_val_max (expr_type);
 		}
-	      extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
-	      return;
-	    }
-	  /* We can map lshifts by constants to MULT_EXPR handling.  */
-	  else if (code == LSHIFT_EXPR
-		   && range_int_cst_singleton_p (&vr1))
-	    {
-	      bool saved_flag_wrapv;
-	      value_range vr1p = VR_INITIALIZER;
-	      vr1p.type = VR_RANGE;
-	      vr1p.min = (wide_int_to_tree
-			  (expr_type,
-			   wi::set_bit_in_zero (tree_to_shwi (vr1.min),
-						TYPE_PRECISION (expr_type))));
-	      vr1p.max = vr1p.min;
-	      /* We have to use a wrapping multiply though as signed overflow
-		 on lshifts is implementation defined in C89.  */
-	      saved_flag_wrapv = flag_wrapv;
-	      flag_wrapv = 1;
-	      extract_range_from_binary_expr_1 (vr, MULT_EXPR, expr_type,
-						&vr0, &vr1p);
-	      flag_wrapv = saved_flag_wrapv;
+	      extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
 	      return;
 	    }
 	  else if (code == LSHIFT_EXPR
 		   && range_int_cst_p (&vr0))
 	    {
-	      int prec = TYPE_PRECISION (expr_type);
-	      int overflow_pos = prec;
-	      int bound_shift;
-	      wide_int low_bound, high_bound;
-	      bool uns = TYPE_UNSIGNED (expr_type);
-	      bool in_bounds = false;
-
-	      if (!uns)
-		overflow_pos -= 1;
-
-	      bound_shift = overflow_pos - tree_to_shwi (vr1.max);
-	      /* 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);
-
-	      if (uns)
-		{
-		  low_bound = bound;
-		  high_bound = complement;
-		  if (wi::ltu_p (wi::to_wide (vr0.max), 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, wi::to_wide (vr0.min)))
-		    {
-		      /* [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 (wi::to_wide (vr0.max), high_bound)
-		      && wi::lts_p (low_bound, wi::to_wide (vr0.min)))
-		    {
-		      /* 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)
+	      wide_int res_lb, res_ub;
+	      if (wide_int_range_lshift (res_lb, res_ub, sign, prec,
+					 wi::to_wide (vr0.min),
+					 wi::to_wide (vr0.max),
+					 wi::to_wide (vr1.min),
+					 wi::to_wide (vr1.max),
+					 TYPE_OVERFLOW_UNDEFINED (expr_type),
+					 TYPE_OVERFLOW_WRAPS (expr_type)))
 		{
-		  extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+		  min = wide_int_to_tree (expr_type, res_lb);
+		  max = wide_int_to_tree (expr_type, res_ub);
+		  set_and_canonicalize_value_range (vr, VR_RANGE,
+						    min, max, NULL);
 		  return;
 		}
 	    }
@@ -2089,7 +2394,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	}
       else if (range_int_cst_p (&vr0) && range_int_cst_p (&vr1))
 	{
-	  extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+	  extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
 	  return;
 	}
     }
@@ -2100,187 +2405,83 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	  set_value_range_to_undefined (vr);
 	  return;
 	}
-      /* ABS (A % B) < ABS (B) and either
-	 0 <= A % B <= A or A <= A % B <= 0.  */
-      type = VR_RANGE;
-      signop sgn = TYPE_SIGN (expr_type);
-      unsigned int prec = TYPE_PRECISION (expr_type);
       wide_int wmin, wmax, tmp;
-      if (vr1.type == VR_RANGE && !symbolic_range_p (&vr1))
-	{
-	  wmax = wi::to_wide (vr1.max) - 1;
-	  if (sgn == SIGNED)
-	    {
-	      tmp = -1 - wi::to_wide (vr1.min);
-	      wmax = wi::smax (wmax, tmp);
-	    }
-	}
-      else
-	{
-	  wmax = wi::max_value (prec, sgn);
-	  /* X % INT_MIN may be INT_MAX.  */
-	  if (sgn == UNSIGNED)
-	    wmax = wmax - 1;
-	}
-
-      if (sgn == UNSIGNED)
-	wmin = wi::zero (prec);
-      else
-	{
-	  wmin = -wmax;
-	  if (vr0.type == VR_RANGE && TREE_CODE (vr0.min) == INTEGER_CST)
-	    {
-	      tmp = wi::to_wide (vr0.min);
-	      if (wi::gts_p (tmp, 0))
-		tmp = wi::zero (prec);
-	      wmin = wi::smax (wmin, tmp);
-	    }
-	}
-
-      if (vr0.type == VR_RANGE && TREE_CODE (vr0.max) == INTEGER_CST)
-	{
-	  tmp = wi::to_wide (vr0.max);
-	  if (sgn == SIGNED && wi::neg_p (tmp))
-	    tmp = wi::zero (prec);
-	  wmax = wi::min (wmax, tmp, sgn);
-	}
-
+      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);
+      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);
       max = wide_int_to_tree (expr_type, wmax);
+      set_value_range (vr, VR_RANGE, min, max, NULL);
+      return;
     }
   else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR)
     {
-      bool int_cst_range0, int_cst_range1;
+      if (vrp_can_optimize_bit_op (vr, code, &vr0, &vr1))
+	return;
+
       wide_int may_be_nonzero0, may_be_nonzero1;
       wide_int must_be_nonzero0, must_be_nonzero1;
-
-      int_cst_range0 = zero_nonzero_bits_from_vr (expr_type, &vr0,
-						  &may_be_nonzero0,
-						  &must_be_nonzero0);
-      int_cst_range1 = zero_nonzero_bits_from_vr (expr_type, &vr1,
-						  &may_be_nonzero1,
-						  &must_be_nonzero1);
-
-      if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
-	{
-	  value_range *vr0p = NULL, *vr1p = NULL;
-	  if (range_int_cst_singleton_p (&vr1))
-	    {
-	      vr0p = &vr0;
-	      vr1p = &vr1;
-	    }
-	  else if (range_int_cst_singleton_p (&vr0))
+      wide_int wmin, wmax;
+      wide_int vr0_min, vr0_max, vr1_min, vr1_max;
+      vrp_set_zero_nonzero_bits (expr_type, &vr0,
+				 &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);
+      if (code == BIT_AND_EXPR)
+	{
+	  if (wide_int_range_bit_and (wmin, wmax, sign, prec,
+				      vr0_min, vr0_max,
+				      vr1_min, vr1_max,
+				      must_be_nonzero0,
+				      may_be_nonzero0,
+				      must_be_nonzero1,
+				      may_be_nonzero1))
 	    {
-	      vr0p = &vr1;
-	      vr1p = &vr0;
-	    }
-	  /* For op & or | attempt to optimize:
-	     [x, y] op z into [x op z, y op z].  */
-	  if (vr0p && range_int_cst_p (vr0p)
-	      && range_easy_mask_min_max (code, wi::to_wide (vr0p->min),
-					  wi::to_wide (vr0p->max),
-					  wi::to_wide (vr1p->min)))
-	    {
-	      min = int_const_binop (code, vr0p->min, vr1p->min);
-	      max = int_const_binop (code, vr0p->max, vr1p->min);
-	    }
-	}
-
-      type = VR_RANGE;
-      if (min && max)
-	/* Optimized above already.  */;
-      else if (code == BIT_AND_EXPR)
-	{
-	  min = wide_int_to_tree (expr_type,
-				  must_be_nonzero0 & must_be_nonzero1);
-	  wide_int 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 (int_cst_range0 && int_cst_range1
-	      && tree_int_cst_sgn (vr0.max) < 0
-	      && tree_int_cst_sgn (vr1.max) < 0)
-	    {
-	      wmax = wi::min (wmax, wi::to_wide (vr0.max),
-			      TYPE_SIGN (expr_type));
-	      wmax = wi::min (wmax, wi::to_wide (vr1.max),
-			      TYPE_SIGN (expr_type));
-	    }
-	  /* 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 (int_cst_range0 && tree_int_cst_sgn (vr0.min) >= 0)
-	    wmax = wi::min (wmax, wi::to_wide (vr0.max),
-			    TYPE_SIGN (expr_type));
-	  if (int_cst_range1 && tree_int_cst_sgn (vr1.min) >= 0)
-	    wmax = wi::min (wmax, wi::to_wide (vr1.max),
-			    TYPE_SIGN (expr_type));
-	  max = wide_int_to_tree (expr_type, wmax);
-	  cmp = compare_values (min, max);
-	  /* PR68217: In case of signed & sign-bit-CST should
-	     result in [-INF, 0] instead of [-INF, INF].  */
-	  if (cmp == -2 || cmp == 1)
-	    {
-	      wide_int sign_bit
-		= wi::set_bit_in_zero (TYPE_PRECISION (expr_type) - 1,
-				       TYPE_PRECISION (expr_type));
-	      if (!TYPE_UNSIGNED (expr_type)
-		  && ((int_cst_range0
-		       && value_range_constant_singleton (&vr0)
-		       && !wi::cmps (wi::to_wide (vr0.min), sign_bit))
-		      || (int_cst_range1
-			  && value_range_constant_singleton (&vr1)
-			  && !wi::cmps (wi::to_wide (vr1.min), sign_bit))))
-		{
-		  min = TYPE_MIN_VALUE (expr_type);
-		  max = build_int_cst (expr_type, 0);
-		}
+	      min = wide_int_to_tree (expr_type, wmin);
+	      max = wide_int_to_tree (expr_type, wmax);
+	      set_value_range (vr, VR_RANGE, min, max, NULL);
 	    }
+	  else
+	    set_value_range_to_varying (vr);
+	  return;
 	}
       else if (code == BIT_IOR_EXPR)
 	{
-	  max = wide_int_to_tree (expr_type,
-				  may_be_nonzero0 | may_be_nonzero1);
-	  wide_int wmin = must_be_nonzero0 | must_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 (int_cst_range0 && int_cst_range1
-	      && tree_int_cst_sgn (vr0.min) >= 0
-	      && tree_int_cst_sgn (vr1.min) >= 0)
+	  if (wide_int_range_bit_ior (wmin, wmax, sign,
+				      vr0_min, vr0_max,
+				      vr1_min, vr1_max,
+				      must_be_nonzero0,
+				      may_be_nonzero0,
+				      must_be_nonzero1,
+				      may_be_nonzero1))
 	    {
-	      wmin = wi::max (wmin, wi::to_wide (vr0.min),
-			      TYPE_SIGN (expr_type));
-	      wmin = wi::max (wmin, wi::to_wide (vr1.min),
-			      TYPE_SIGN (expr_type));
+	      min = wide_int_to_tree (expr_type, wmin);
+	      max = wide_int_to_tree (expr_type, wmax);
+	      set_value_range (vr, VR_RANGE, min, max, NULL);
 	    }
-	  /* If either input range contains only negative values
-	     we can truncate the minimum of the result range to the
-	     respective minimum range.  */
-	  if (int_cst_range0 && tree_int_cst_sgn (vr0.max) < 0)
-	    wmin = wi::max (wmin, wi::to_wide (vr0.min),
-			    TYPE_SIGN (expr_type));
-	  if (int_cst_range1 && tree_int_cst_sgn (vr1.max) < 0)
-	    wmin = wi::max (wmin, wi::to_wide (vr1.min),
-			    TYPE_SIGN (expr_type));
-	  min = wide_int_to_tree (expr_type, wmin);
+	  else
+	    set_value_range_to_varying (vr);
+	  return;
 	}
       else if (code == BIT_XOR_EXPR)
 	{
-	  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));
-	  max = wide_int_to_tree (expr_type, ~result_zero_bits);
-	  min = wide_int_to_tree (expr_type, result_one_bits);
-	  /* If the range has all positive or all negative values the
-	     result is better than VARYING.  */
-	  if (tree_int_cst_sgn (min) < 0
-	      || tree_int_cst_sgn (max) >= 0)
-	    ;
+	  if (wide_int_range_bit_xor (wmin, wmax, sign, prec,
+				      must_be_nonzero0,
+				      may_be_nonzero0,
+				      must_be_nonzero1,
+				      may_be_nonzero1))
+	    {
+	      min = wide_int_to_tree (expr_type, wmin);
+	      max = wide_int_to_tree (expr_type, wmax);
+	      set_value_range (vr, VR_RANGE, min, max, NULL);
+	    }
 	  else
-	    max = min = NULL_TREE;
+	    set_value_range_to_varying (vr);
+	  return;
 	}
     }
   else
@@ -2608,6 +2809,12 @@  debug_value_range (value_range *vr)
   fprintf (stderr, "\n");
 }
 
+void
+value_range::dump ()
+{
+  debug_value_range (this);
+}
+
 
 /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V,
    create a new SSA name N and return the assertion assignment
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index daf12ce31d1..8cac7daada7 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -49,6 +49,9 @@  struct GTY((for_user)) value_range
   /* Set of SSA names whose value ranges are equivalent to this one.
      This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
   bitmap equiv;
+
+  /* Dump value range to stderr.  */
+  void dump ();
 };
 
 extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
@@ -115,6 +118,70 @@  extern bool wide_int_range_mult_wrapping (wide_int &res_lb,
 					  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,
+					      bool overflow_wraps);
+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,
+				   bool overflow_wraps);
+extern bool wide_int_range_shift_undefined_p (signop sign, unsigned prec,
+					      const wide_int &min,
+					      const wide_int &max);
+extern void wide_int_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_can_optimize_bit_op (tree_code,
+						const wide_int &lb,
+						const wide_int &ub,
+						const wide_int &mask);
+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 void extract_range_from_binary_expr_1 (value_range *, enum tree_code,
 					      tree, value_range *,
 					      value_range *);
@@ -125,14 +192,8 @@  extern bool range_int_cst_p (value_range *);
 extern int operand_less_p (tree, tree);
 extern bool find_case_label_range (gswitch *, tree, tree, size_t *, size_t *);
 extern bool find_case_label_index (gswitch *, size_t, tree, size_t *);
-extern void zero_nonzero_bits_from_bounds (signop, const wide_int&,
-					   const wide_int&, wide_int *,
-					   wide_int *);
-extern bool zero_nonzero_bits_from_vr (const tree, value_range *,
+extern bool vrp_set_zero_nonzero_bits (const tree, value_range *,
 				       wide_int *, wide_int *);
-extern bool range_easy_mask_min_max (tree_code,
-				     const wide_int &lb, const wide_int &ub,
-				     const wide_int &mask);
 extern bool overflow_comparison_p (tree_code, tree, tree, bool, tree *);
 extern bool range_int_cst_singleton_p (value_range *);
 extern int value_inside_range (tree, tree, tree);
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index bba170f341b..33335f3da31 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -3300,10 +3300,10 @@  vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
   else
     return false;
 
-  if (!zero_nonzero_bits_from_vr (TREE_TYPE (op0), &vr0, &may_be_nonzero0,
+  if (!vrp_set_zero_nonzero_bits (TREE_TYPE (op0), &vr0, &may_be_nonzero0,
 				  &must_be_nonzero0))
     return false;
-  if (!zero_nonzero_bits_from_vr (TREE_TYPE (op1), &vr1, &may_be_nonzero1,
+  if (!vrp_set_zero_nonzero_bits (TREE_TYPE (op1), &vr1, &may_be_nonzero1,
 				  &must_be_nonzero1))
     return false;