The call to range_operator::fold_range() and wi_fold() originally returned the resulting range in a reference parameter.  When prepping for trunk,  we got excited about something else and I changed it to return the result by value.

As we move towards multiple sub-ranges in value_range, I  recalled the rationale for the reference parameter was to allow us to better support a variable number of sub-ranges.   range-ops will work with as many subranges as are available, and this allows the caller to provide a range object with the desired number.       It also makes fold_range a bit more consistent with the way op1_range and op2_range work.

The fundamental change is moving from:
    virtual value_range fold_range (tree type, const value_range &lh, const value_range &rh) const;
to
    virtual void fold_range (value_range &r, tree type, const value_range &lh, const value_range &rh) const;

and likewise for wi_fold.

The change is quite mechanical.  Bootstraps all languages and causes no regressions.

Checked in as SVN revision 277979

Andrew




Change range_operator methods 'fold_range' and 'wi_fold' to return the result
range by a reference parameter instead of by value.

2019-11-08  Andrew MacLeod <amacl...@redhat.com>

	* range-op.h (range_operator::fold_range): Return result in a
	reference parameter instead of by value.
	(range_operator::wi_fold): Same.
	* range-op.cc (range_operator::wi_fold): Return result in a reference
	parameter instead of by value.
	(range_operator::fold_range): Same.
	(value_range_from_overflowed_bounds): Same.
	(value_range_with_overflow): Same
	(create_possibly_reversed_range): Same.
	(operator_equal::fold_range): Same.
	(operator_not_equal::fold_range): Same.
	(operator_lt::fold_range): Same.
	(operator_le::fold_range): Same.
	(operator_gt::fold_range): Same.
	(operator_ge::fold_range): Same.
	(operator_plus::wi_fold): Same.
	(operator_plus::op1_range): Change call to fold_range.
	(operator_plus::op2_range): Change call to fold_range.
	(operator_minus::wi_fold): Return result via reference parameter.
	(operator_minus::op1_range): Change call to fold_range.
	(operator_minus::op2_range): Change call to fold_range.
	(operator_min::wi_fold): Return result via reference parameter.
	(operator_max::wi_fold): Same.
	(cross_product_operator::wi_cross_product): Same.
	(operator_mult::wi_fold): Same.
	(operator_div::wi_fold): Same.
	(operator_div op_floor_div): Fix whitespace.
	(operator_exact_divide::op1_range): Change call to fold_range.
	(operator_lshift::fold_range): Return result via reference parameter.
	(operator_lshift::wi_fold): Same.
	(operator_rshift::fold_range): Same.
	(operator_rshift::wi_fold): Same.
	(operator_cast::fold_range): Same.
	(operator_cast::op1_range): Change calls to fold_range.
	(operator_logical_and::fold_range): Return result via reference.
	(wi_optimize_and_or): Adjust call to value_range_with_overflow.
	(operator_bitwise_and::wi_fold): Return result via reference.
	(operator_logical_or::fold_range): Same.
	(operator_bitwise_or::wi_fold): Same.
	(operator_bitwise_xor::wi_fold): Same.
	(operator_trunc_mod::wi_fold): Same.
	(operator_logical_not::fold_range): Same.
	(operator_bitwise_not::fold_range): Same.
	(operator_bitwise_not::op1_range): Change call to fold_range.
	(operator_cst::fold_range): Return result via reference.
	(operator_identity::fold_range): Same.
	(operator_abs::wi_fold): Same.
	(operator_absu::wi_fold): Same.
	(operator_negate::fold_range): Same.
	(operator_negate::op1_range): Change call to fold_range.
	(operator_addr_expr::fold_range): Return result via reference.
	(operator_addr_expr::op1_range): Change call to fold_range.
	(operator_pointer_plus::wi_fold): Return result via reference.
	(operator_pointer_min_max::wi_fold): Same.
	(operator_pointer_and::wi_fold): Same.
	(operator_pointer_or::wi_fold): Same.
	(range_op_handler): Change call to fold_range.
	(range_cast): Same.
	* tree-vrp.c (range_fold_binary_symbolics_p): Change call to
	fold_range.
	(range_fold_unary_symbolics_p): Same.
	(range_fold_binary_expr): Same.
	(range_fold_unary_expr): Same.


Index: range-op.h
===================================================================
*** range-op.h	(revision 277853)
--- range-op.h	(working copy)
*************** class range_operator
*** 50,58 ****
  {
  public:
    // Perform an operation between 2 ranges and return it.
!   virtual value_range fold_range (tree type,
! 				  const value_range &lh,
! 				  const value_range &rh) const;
  
    // Return the range for op[12] in the general case.  LHS is the range for
    // the LHS of the expression, OP[12]is the range for the other
--- 50,58 ----
  {
  public:
    // Perform an operation between 2 ranges and return it.
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &lh,
! 			   const value_range &rh) const;
  
    // Return the range for op[12] in the general case.  LHS is the range for
    // the LHS of the expression, OP[12]is the range for the other
*************** public:
*** 74,84 ****
  
  protected:
    // Perform an operation between 2 sub-ranges and return it.
!   virtual value_range wi_fold (tree type,
! 				    const wide_int &lh_lb,
! 				    const wide_int &lh_ub,
! 				    const wide_int &rh_lb,
! 				    const wide_int &rh_ub) const;
  };
  
  extern range_operator *range_op_handler (enum tree_code code, tree type);
--- 74,84 ----
  
  protected:
    // Perform an operation between 2 sub-ranges and return it.
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  };
  
  extern range_operator *range_op_handler (enum tree_code code, tree type);
Index: range-op.cc
===================================================================
*** range-op.cc	(revision 277853)
--- range-op.cc	(working copy)
*************** wi_zero_p (tree type, const wide_int &wm
*** 124,151 ****
  
  // Default wide_int fold operation returns [MIN, MAX].
  
! value_range
! range_operator::wi_fold (tree type,
  			 const wide_int &lh_lb ATTRIBUTE_UNUSED,
  			 const wide_int &lh_ub ATTRIBUTE_UNUSED,
  			 const wide_int &rh_lb ATTRIBUTE_UNUSED,
  			 const wide_int &rh_ub ATTRIBUTE_UNUSED) const
  {
!   return value_range (type);
  }
  
  // The default for fold is to break all ranges into sub-ranges and
  // invoke the wi_fold method on each sub-range pair.
  
! value_range
! range_operator::fold_range (tree type,
  			    const value_range &lh,
  			    const value_range &rh) const
  {
-   value_range r;
    if (empty_range_check (r, lh, rh))
!     return r;
  
    for (unsigned x = 0; x < lh.num_pairs (); ++x)
      for (unsigned y = 0; y < rh.num_pairs (); ++y)
        {
--- 124,151 ----
  
  // Default wide_int fold operation returns [MIN, MAX].
  
! void
! range_operator::wi_fold (value_range &r, tree type,
  			 const wide_int &lh_lb ATTRIBUTE_UNUSED,
  			 const wide_int &lh_ub ATTRIBUTE_UNUSED,
  			 const wide_int &rh_lb ATTRIBUTE_UNUSED,
  			 const wide_int &rh_ub ATTRIBUTE_UNUSED) const
  {
!   r = value_range (type);
  }
  
  // The default for fold is to break all ranges into sub-ranges and
  // invoke the wi_fold method on each sub-range pair.
  
! void
! range_operator::fold_range (value_range &r, tree type,
  			    const value_range &lh,
  			    const value_range &rh) const
  {
    if (empty_range_check (r, lh, rh))
!     return;
  
+   value_range tmp;
    for (unsigned x = 0; x < lh.num_pairs (); ++x)
      for (unsigned y = 0; y < rh.num_pairs (); ++y)
        {
*************** range_operator::fold_range (tree type,
*** 153,163 ****
  	wide_int lh_ub = lh.upper_bound (x);
  	wide_int rh_lb = rh.lower_bound (y);
  	wide_int rh_ub = rh.upper_bound (y);
! 	r.union_ (wi_fold (type, lh_lb, lh_ub, rh_lb, rh_ub));
  	if (r.varying_p ())
! 	  return r;
        }
-   return r;
  }
  
  // The default for op1_range is to return false.
--- 153,163 ----
  	wide_int lh_ub = lh.upper_bound (x);
  	wide_int rh_lb = rh.lower_bound (y);
  	wide_int rh_ub = rh.upper_bound (y);
! 	wi_fold (tmp, type, lh_lb, lh_ub, rh_lb, rh_ub);
! 	r.union_ (tmp);
  	if (r.varying_p ())
! 	  return;
        }
  }
  
  // The default for op1_range is to return false.
*************** range_operator::op2_range (value_range &
*** 186,193 ****
  // Create and return a range from a pair of wide-ints that are known
  // to have overflowed (or underflowed).
  
! static value_range
! value_range_from_overflowed_bounds (tree type,
  				    const wide_int &wmin,
  				    const wide_int &wmax)
  {
--- 186,193 ----
  // Create and return a range from a pair of wide-ints that are known
  // to have overflowed (or underflowed).
  
! static void
! value_range_from_overflowed_bounds (value_range &r, tree type,
  				    const wide_int &wmin,
  				    const wide_int &wmax)
  {
*************** value_range_from_overflowed_bounds (tree
*** 210,226 ****
    // Likewise if the anti-range bounds are outside of the types
    // values.
    if (covers || wi::cmp (tmin, tmax, sgn) > 0)
!     return value_range (type);
! 
!   return value_range (VR_ANTI_RANGE, type, tmin, tmax);
  }
  
  // Create and return a range from a pair of wide-ints.  MIN_OVF and
  // MAX_OVF describe any overflow that might have occurred while
  // calculating WMIN and WMAX respectively.
  
! static value_range
! value_range_with_overflow (tree type,
  			   const wide_int &wmin, const wide_int &wmax,
  			   wi::overflow_type min_ovf = wi::OVF_NONE,
  			   wi::overflow_type max_ovf = wi::OVF_NONE)
--- 210,226 ----
    // Likewise if the anti-range bounds are outside of the types
    // values.
    if (covers || wi::cmp (tmin, tmax, sgn) > 0)
!     r = value_range (type);
!   else
!     r = value_range (VR_ANTI_RANGE, type, tmin, tmax);
  }
  
  // Create and return a range from a pair of wide-ints.  MIN_OVF and
  // MAX_OVF describe any overflow that might have occurred while
  // calculating WMIN and WMAX respectively.
  
! static void
! value_range_with_overflow (value_range &r, tree type,
  			   const wide_int &wmin, const wide_int &wmax,
  			   wi::overflow_type min_ovf = wi::OVF_NONE,
  			   wi::overflow_type max_ovf = wi::OVF_NONE)
*************** value_range_with_overflow (tree type,
*** 232,238 ****
    // For one bit precision if max != min, then the range covers all
    // values.
    if (prec == 1 && wi::ne_p (wmax, wmin))
!     return value_range (type);
  
    if (overflow_wraps)
      {
--- 232,241 ----
    // For one bit precision if max != min, then the range covers all
    // values.
    if (prec == 1 && wi::ne_p (wmax, wmin))
!     {
!       r = value_range (type);
!       return;
!     }
  
    if (overflow_wraps)
      {
*************** value_range_with_overflow (tree type,
*** 245,263 ****
  	  // If the limits are swapped, we wrapped around and cover
  	  // the entire range.
  	  if (wi::gt_p (tmin, tmax, sgn))
! 	    return value_range (type);
! 
! 	  // No overflow or both overflow or underflow.  The range
! 	  // kind stays normal.
! 	  return value_range (type, tmin, tmax);
  	}
  
        if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
  	  || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
! 	return value_range_from_overflowed_bounds (type, wmin, wmax);
! 
!       // Other underflow and/or overflow, drop to VR_VARYING.
!       return value_range (type);
      }
    else
      {
--- 248,267 ----
  	  // If the limits are swapped, we wrapped around and cover
  	  // the entire range.
  	  if (wi::gt_p (tmin, tmax, sgn))
! 	    r = value_range (type);
! 	  else
! 	    // No overflow or both overflow or underflow.  The range
! 	    // kind stays normal.
! 	    r = value_range (type, tmin, tmax);
! 	  return;
  	}
  
        if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
  	  || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
! 	value_range_from_overflowed_bounds (r, type, wmin, wmax);
!       else
! 	// Other underflow and/or overflow, drop to VR_VARYING.
! 	r = value_range (type);
      }
    else
      {
*************** value_range_with_overflow (tree type,
*** 277,283 ****
        else
          new_ub = wmax;
  
!       return value_range (type, new_lb, new_ub);
      }
  }
  
--- 281,287 ----
        else
          new_ub = wmax;
  
!       r = value_range (type, new_lb, new_ub);
      }
  }
  
*************** value_range_with_overflow (tree type,
*** 285,301 ****
  // the case where the bounds are swapped.  In which case, we transform
  // [10,5] into [MIN,5][10,MAX].
  
! static inline value_range
! create_possibly_reversed_range (tree type,
  				const wide_int &new_lb, const wide_int &new_ub)
  {
    signop s = TYPE_SIGN (type);
    // If the bounds are swapped, treat the result as if an overflow occured.
    if (wi::gt_p (new_lb, new_ub, s))
!     return value_range_from_overflowed_bounds (type, new_lb, new_ub);
! 
!   // Otherwise its just a normal range.
!   return value_range (type, new_lb, new_ub);
  }
  
  // Return a value_range instance that is a boolean TRUE.
--- 289,305 ----
  // the case where the bounds are swapped.  In which case, we transform
  // [10,5] into [MIN,5][10,MAX].
  
! static inline void
! create_possibly_reversed_range (value_range &r, tree type,
  				const wide_int &new_lb, const wide_int &new_ub)
  {
    signop s = TYPE_SIGN (type);
    // If the bounds are swapped, treat the result as if an overflow occured.
    if (wi::gt_p (new_lb, new_ub, s))
!     value_range_from_overflowed_bounds (r, type, new_lb, new_ub);
!   else
!     // Otherwise its just a normal range.
!     r = value_range (type, new_lb, new_ub);
  }
  
  // Return a value_range instance that is a boolean TRUE.
*************** get_bool_state (value_range &r, const va
*** 359,367 ****
  class operator_equal : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &val) const;
--- 363,371 ----
  class operator_equal : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &val) const;
*************** public:
*** 370,383 ****
  			  const value_range &val) const;
  } op_equal;
  
! value_range
! operator_equal::fold_range (tree type,
  			    const value_range &op1,
  			    const value_range &op2) const
  {
-   value_range r;
    if (empty_range_check (r, op1, op2))
!     return r;
  
    // We can be sure the values are always equal or not if both ranges
    // consist of a single value, and then compare them.
--- 374,386 ----
  			  const value_range &val) const;
  } op_equal;
  
! void
! operator_equal::fold_range (value_range &r, tree type,
  			    const value_range &op1,
  			    const value_range &op2) const
  {
    if (empty_range_check (r, op1, op2))
!     return;
  
    // We can be sure the values are always equal or not if both ranges
    // consist of a single value, and then compare them.
*************** operator_equal::fold_range (tree type,
*** 399,406 ****
        else
  	r = range_true_and_false (type);
      }
- 
-   return r;
  }
  
  bool
--- 402,407 ----
*************** operator_equal::op2_range (value_range &
*** 442,450 ****
  class operator_not_equal : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
--- 443,451 ----
  class operator_not_equal : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
*************** public:
*** 453,466 ****
  			  const value_range &op1) const;
  } op_not_equal;
  
! value_range
! operator_not_equal::fold_range (tree type,
  				const value_range &op1,
  				const value_range &op2) const
  {
-   value_range r;
    if (empty_range_check (r, op1, op2))
!     return r;
  
    // We can be sure the values are always equal or not if both ranges
    // consist of a single value, and then compare them.
--- 454,466 ----
  			  const value_range &op1) const;
  } op_not_equal;
  
! void
! operator_not_equal::fold_range (value_range &r, tree type,
  				const value_range &op1,
  				const value_range &op2) const
  {
    if (empty_range_check (r, op1, op2))
!     return;
  
    // We can be sure the values are always equal or not if both ranges
    // consist of a single value, and then compare them.
*************** operator_not_equal::fold_range (tree typ
*** 482,489 ****
        else
  	r = range_true_and_false (type);
      }
- 
-   return r;
  }
  
  bool
--- 482,487 ----
*************** build_ge (value_range &r, tree type, con
*** 571,579 ****
  class operator_lt :  public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
--- 569,577 ----
  class operator_lt :  public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
*************** public:
*** 582,595 ****
  			  const value_range &op1) const;
  } op_lt;
  
! value_range
! operator_lt::fold_range (tree type,
  			 const value_range &op1,
  			 const value_range &op2) const
  {
-   value_range r;
    if (empty_range_check (r, op1, op2))
!     return r;
  
    signop sign = TYPE_SIGN (op1.type ());
    gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
--- 580,592 ----
  			  const value_range &op1) const;
  } op_lt;
  
! void
! operator_lt::fold_range (value_range &r, tree type,
  			 const value_range &op1,
  			 const value_range &op2) const
  {
    if (empty_range_check (r, op1, op2))
!     return;
  
    signop sign = TYPE_SIGN (op1.type ());
    gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
*************** operator_lt::fold_range (tree type,
*** 600,606 ****
      r = range_false (type);
    else
      r = range_true_and_false (type);
-   return r;
  }
  
  bool
--- 597,602 ----
*************** operator_lt::op2_range (value_range &r,
*** 649,657 ****
  class operator_le :  public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
--- 645,653 ----
  class operator_le :  public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
*************** public:
*** 660,673 ****
  			  const value_range &op1) const;
  } op_le;
  
! value_range
! operator_le::fold_range (tree type,
  			 const value_range &op1,
  			 const value_range &op2) const
  {
-   value_range r;
    if (empty_range_check (r, op1, op2))
!     return r;
  
    signop sign = TYPE_SIGN (op1.type ());
    gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
--- 656,668 ----
  			  const value_range &op1) const;
  } op_le;
  
! void
! operator_le::fold_range (value_range &r, tree type,
  			 const value_range &op1,
  			 const value_range &op2) const
  {
    if (empty_range_check (r, op1, op2))
!     return;
  
    signop sign = TYPE_SIGN (op1.type ());
    gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
*************** operator_le::fold_range (tree type,
*** 678,684 ****
      r = range_false (type);
    else
      r = range_true_and_false (type);
-   return r;
  }
  
  bool
--- 673,678 ----
*************** operator_le::op2_range (value_range &r,
*** 727,735 ****
  class operator_gt :  public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
--- 721,729 ----
  class operator_gt :  public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
*************** public:
*** 738,750 ****
  			  const value_range &op1) const;
  } op_gt;
  
! value_range
! operator_gt::fold_range (tree type,
  			 const value_range &op1, const value_range &op2) const
  {
-   value_range r;
    if (empty_range_check (r, op1, op2))
!     return r;
  
    signop sign = TYPE_SIGN (op1.type ());
    gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
--- 732,743 ----
  			  const value_range &op1) const;
  } op_gt;
  
! void
! operator_gt::fold_range (value_range &r, tree type,
  			 const value_range &op1, const value_range &op2) const
  {
    if (empty_range_check (r, op1, op2))
!     return;
  
    signop sign = TYPE_SIGN (op1.type ());
    gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
*************** operator_gt::fold_range (tree type,
*** 755,761 ****
      r = range_false (type);
    else
      r = range_true_and_false (type);
-   return r;
  }
  
  bool
--- 748,753 ----
*************** operator_gt::op2_range (value_range &r,
*** 803,811 ****
  class operator_ge :  public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
--- 795,803 ----
  class operator_ge :  public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
*************** public:
*** 814,827 ****
  			  const value_range &op1) const;
  } op_ge;
  
! value_range
! operator_ge::fold_range (tree type,
  			 const value_range &op1,
  			 const value_range &op2) const
  {
-   value_range r;
    if (empty_range_check (r, op1, op2))
!     return r;
  
    signop sign = TYPE_SIGN (op1.type ());
    gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
--- 806,818 ----
  			  const value_range &op1) const;
  } op_ge;
  
! void
! operator_ge::fold_range (value_range &r, tree type,
  			 const value_range &op1,
  			 const value_range &op2) const
  {
    if (empty_range_check (r, op1, op2))
!     return;
  
    signop sign = TYPE_SIGN (op1.type ());
    gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
*************** operator_ge::fold_range (tree type,
*** 832,838 ****
      r = range_false (type);
    else
      r = range_true_and_false (type);
-   return r;
  }
  
  bool
--- 823,828 ----
*************** public:
*** 887,901 ****
    virtual bool op2_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op1) const;
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_plus;
  
! value_range
! operator_plus::wi_fold (tree type,
  			const wide_int &lh_lb, const wide_int &lh_ub,
  			const wide_int &rh_lb, const wide_int &rh_ub) const
  {
--- 877,891 ----
    virtual bool op2_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op1) const;
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_plus;
  
! void
! operator_plus::wi_fold (value_range &r, tree type,
  			const wide_int &lh_lb, const wide_int &lh_ub,
  			const wide_int &rh_lb, const wide_int &rh_ub) const
  {
*************** operator_plus::wi_fold (tree type,
*** 903,909 ****
    signop s = TYPE_SIGN (type);
    wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb);
    wide_int new_ub = wi::add (lh_ub, rh_ub, s, &ov_ub);
!   return value_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub);
  }
  
  bool
--- 893,899 ----
    signop s = TYPE_SIGN (type);
    wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb);
    wide_int new_ub = wi::add (lh_ub, rh_ub, s, &ov_ub);
!   value_range_with_overflow (r, type, new_lb, new_ub, ov_lb, ov_ub);
  }
  
  bool
*************** operator_plus::op1_range (value_range &r
*** 911,917 ****
  			  const value_range &lhs,
  			  const value_range &op2) const
  {
!   r = range_op_handler (MINUS_EXPR, type)->fold_range (type, lhs, op2);
    return true;
  }
  
--- 901,907 ----
  			  const value_range &lhs,
  			  const value_range &op2) const
  {
!   range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
    return true;
  }
  
*************** operator_plus::op2_range (value_range &r
*** 920,926 ****
  			  const value_range &lhs,
  			  const value_range &op1) const
  {
!   r = range_op_handler (MINUS_EXPR, type)->fold_range (type, lhs, op1);
    return true;
  }
  
--- 910,916 ----
  			  const value_range &lhs,
  			  const value_range &op1) const
  {
!   range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
    return true;
  }
  
*************** public:
*** 934,948 ****
    virtual bool op2_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op1) const;
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_minus;
  
! value_range
! operator_minus::wi_fold (tree type,
  			 const wide_int &lh_lb, const wide_int &lh_ub,
  			 const wide_int &rh_lb, const wide_int &rh_ub) const
  {
--- 924,938 ----
    virtual bool op2_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op1) const;
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_minus;
  
! void 
! operator_minus::wi_fold (value_range &r, tree type,
  			 const wide_int &lh_lb, const wide_int &lh_ub,
  			 const wide_int &rh_lb, const wide_int &rh_ub) const
  {
*************** operator_minus::wi_fold (tree type,
*** 950,956 ****
    signop s = TYPE_SIGN (type);
    wide_int new_lb = wi::sub (lh_lb, rh_ub, s, &ov_lb);
    wide_int new_ub = wi::sub (lh_ub, rh_lb, s, &ov_ub);
!   return value_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub);
  }
  
  bool
--- 940,946 ----
    signop s = TYPE_SIGN (type);
    wide_int new_lb = wi::sub (lh_lb, rh_ub, s, &ov_lb);
    wide_int new_ub = wi::sub (lh_ub, rh_lb, s, &ov_ub);
!   value_range_with_overflow (r, type, new_lb, new_ub, ov_lb, ov_ub);
  }
  
  bool
*************** operator_minus::op1_range (value_range &
*** 958,964 ****
  			   const value_range &lhs,
  			   const value_range &op2) const
  {
!   r = range_op_handler (PLUS_EXPR, type)->fold_range (type, lhs, op2);
    return true;
  }
  
--- 948,954 ----
  			   const value_range &lhs,
  			   const value_range &op2) const
  {
!   range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
    return true;
  }
  
*************** operator_minus::op2_range (value_range &
*** 967,973 ****
  			   const value_range &lhs,
  			   const value_range &op1) const
  {
!   r = fold_range (type, op1, lhs);
    return true;
  }
  
--- 957,963 ----
  			   const value_range &lhs,
  			   const value_range &op1) const
  {
!   fold_range (r, type, op1, lhs);
    return true;
  }
  
*************** operator_minus::op2_range (value_range &
*** 975,1018 ****
  class operator_min : public range_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_min;
  
! value_range
! operator_min::wi_fold (tree type,
  		       const wide_int &lh_lb, const wide_int &lh_ub,
  		       const wide_int &rh_lb, const wide_int &rh_ub) const
  {
    signop s = TYPE_SIGN (type);
    wide_int new_lb = wi::min (lh_lb, rh_lb, s);
    wide_int new_ub = wi::min (lh_ub, rh_ub, s);
!   return value_range_with_overflow (type, new_lb, new_ub);
  }
  
  
  class operator_max : public range_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_max;
  
! value_range
! operator_max::wi_fold (tree type,
  		       const wide_int &lh_lb, const wide_int &lh_ub,
  		       const wide_int &rh_lb, const wide_int &rh_ub) const
  {
    signop s = TYPE_SIGN (type);
    wide_int new_lb = wi::max (lh_lb, rh_lb, s);
    wide_int new_ub = wi::max (lh_ub, rh_ub, s);
!   return value_range_with_overflow (type, new_lb, new_ub);
  }
  
  
--- 965,1008 ----
  class operator_min : public range_operator
  {
  public:
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_min;
  
! void
! operator_min::wi_fold (value_range &r, tree type,
  		       const wide_int &lh_lb, const wide_int &lh_ub,
  		       const wide_int &rh_lb, const wide_int &rh_ub) const
  {
    signop s = TYPE_SIGN (type);
    wide_int new_lb = wi::min (lh_lb, rh_lb, s);
    wide_int new_ub = wi::min (lh_ub, rh_ub, s);
!   value_range_with_overflow (r, type, new_lb, new_ub);
  }
  
  
  class operator_max : public range_operator
  {
  public:
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_max;
  
! void
! operator_max::wi_fold (value_range &r, tree type,
  		       const wide_int &lh_lb, const wide_int &lh_ub,
  		       const wide_int &rh_lb, const wide_int &rh_ub) const
  {
    signop s = TYPE_SIGN (type);
    wide_int new_lb = wi::max (lh_lb, rh_lb, s);
    wide_int new_ub = wi::max (lh_ub, rh_ub, s);
!   value_range_with_overflow (r, type, new_lb, new_ub);
  }
  
  
*************** public:
*** 1027,1037 ****
  				const wide_int &) const = 0;
  
    // Calculate the cross product of two sets of sub-ranges and return it.
!   value_range wi_cross_product (tree type,
! 				     const wide_int &lh_lb,
! 				     const wide_int &lh_ub,
! 				     const wide_int &rh_lb,
! 				     const wide_int &rh_ub) const;
  };
  
  // Calculate the cross product of two sets of ranges and return it.
--- 1017,1027 ----
  				const wide_int &) const = 0;
  
    // Calculate the cross product of two sets of sub-ranges and return it.
!   void wi_cross_product (value_range &r, tree type,
! 			 const wide_int &lh_lb,
! 			 const wide_int &lh_ub,
! 			 const wide_int &rh_lb,
! 			 const wide_int &rh_ub) const;
  };
  
  // Calculate the cross product of two sets of ranges and return it.
*************** public:
*** 1047,1077 ****
  // 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.
  
! value_range
! cross_product_operator::wi_cross_product (tree type,
  					  const wide_int &lh_lb,
  					  const wide_int &lh_ub,
  					  const wide_int &rh_lb,
  					  const wide_int &rh_ub) const
  {
    wide_int cp1, cp2, cp3, cp4;
  
    // Compute the 4 cross operations, bailing if we get an overflow we
    // can't handle.
    if (wi_op_overflows (cp1, type, lh_lb, rh_lb))
!     return value_range (type);
    if (wi::eq_p (lh_lb, lh_ub))
      cp3 = cp1;
    else if (wi_op_overflows (cp3, type, lh_ub, rh_lb))
!     return value_range (type);
    if (wi::eq_p (rh_lb, rh_ub))
      cp2 = cp1;
    else if (wi_op_overflows (cp2, type, lh_lb, rh_ub))
!     return value_range (type);
    if (wi::eq_p (lh_lb, lh_ub))
      cp4 = cp2;
    else if (wi_op_overflows (cp4, type, lh_ub, rh_ub))
!     return value_range (type);
  
    // Order pairs.
    signop sign = TYPE_SIGN (type);
--- 1037,1069 ----
  // 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.
  
! void
! cross_product_operator::wi_cross_product (value_range &r, tree type,
  					  const wide_int &lh_lb,
  					  const wide_int &lh_ub,
  					  const wide_int &rh_lb,
  					  const wide_int &rh_ub) const
  {
    wide_int cp1, cp2, cp3, cp4;
+   // Default to varying.
+   r = value_range (type);
  
    // Compute the 4 cross operations, bailing if we get an overflow we
    // can't handle.
    if (wi_op_overflows (cp1, type, lh_lb, rh_lb))
!     return;
    if (wi::eq_p (lh_lb, lh_ub))
      cp3 = cp1;
    else if (wi_op_overflows (cp3, type, lh_ub, rh_lb))
!     return;
    if (wi::eq_p (rh_lb, rh_ub))
      cp2 = cp1;
    else if (wi_op_overflows (cp2, type, lh_lb, rh_ub))
!     return;
    if (wi::eq_p (lh_lb, lh_ub))
      cp4 = cp2;
    else if (wi_op_overflows (cp4, type, lh_ub, rh_ub))
!     return;
  
    // Order pairs.
    signop sign = TYPE_SIGN (type);
*************** cross_product_operator::wi_cross_product
*** 1083,1100 ****
    // Choose min and max from the ordered pairs.
    wide_int res_lb = wi::min (cp1, cp3, sign);
    wide_int res_ub = wi::max (cp2, cp4, sign);
!   return value_range_with_overflow (type, res_lb, res_ub);
  }
  
  
  class operator_mult : public cross_product_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
    virtual bool wi_op_overflows (wide_int &res, tree type,
  				const wide_int &w0, const wide_int &w1) const;
  } op_mult;
--- 1075,1092 ----
    // Choose min and max from the ordered pairs.
    wide_int res_lb = wi::min (cp1, cp3, sign);
    wide_int res_ub = wi::max (cp2, cp4, sign);
!   value_range_with_overflow (r, type, res_lb, res_ub);
  }
  
  
  class operator_mult : public cross_product_operator
  {
  public:
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
    virtual bool wi_op_overflows (wide_int &res, tree type,
  				const wide_int &w0, const wide_int &w1) const;
  } op_mult;
*************** operator_mult::wi_op_overflows (wide_int
*** 1119,1131 ****
     return overflow;
  }
  
! value_range
! operator_mult::wi_fold (tree type,
  			const wide_int &lh_lb, const wide_int &lh_ub,
  			const wide_int &rh_lb, const wide_int &rh_ub) const
  {
    if (TYPE_OVERFLOW_UNDEFINED (type))
!     return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub);
  
    // Multiply the ranges when overflow wraps.  This is basically fancy
    // code so we don't drop to varying with an unsigned
--- 1111,1126 ----
     return overflow;
  }
  
! void 
! operator_mult::wi_fold (value_range &r, tree type,
  			const wide_int &lh_lb, const wide_int &lh_ub,
  			const wide_int &rh_lb, const wide_int &rh_ub) const
  {
    if (TYPE_OVERFLOW_UNDEFINED (type))
!     {
!       wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
!       return;
!     }
  
    // Multiply the ranges when overflow wraps.  This is basically fancy
    // code so we don't drop to varying with an unsigned
*************** operator_mult::wi_fold (tree type,
*** 1186,1196 ****
    prod2 = prod3 - prod0;
    if (wi::geu_p (prod2, sizem1))
      // The range covers all values.
!     return value_range (type);
! 
!   wide_int new_lb = wide_int::from (prod0, prec, sign);
!   wide_int new_ub = wide_int::from (prod3, prec, sign);
!   return create_possibly_reversed_range (type, new_lb, new_ub);
  }
  
  
--- 1181,1193 ----
    prod2 = prod3 - prod0;
    if (wi::geu_p (prod2, sizem1))
      // The range covers all values.
!     r = value_range (type);
!   else
!     {
!       wide_int new_lb = wide_int::from (prod0, prec, sign);
!       wide_int new_ub = wide_int::from (prod3, prec, sign);
!       create_possibly_reversed_range (r, type, new_lb, new_ub);
!     }
  }
  
  
*************** class operator_div : public cross_produc
*** 1198,1208 ****
  {
  public:
    operator_div (enum tree_code c)  { code = c; }
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
    virtual bool wi_op_overflows (wide_int &res, tree type,
  				const wide_int &, const wide_int &) const;
  private:
--- 1195,1205 ----
  {
  public:
    operator_div (enum tree_code c)  { code = c; }
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
    virtual bool wi_op_overflows (wide_int &res, tree type,
  				const wide_int &, const wide_int &) const;
  private:
*************** operator_div::wi_op_overflows (wide_int
*** 1251,1264 ****
    return overflow;
  }
  
! value_range
! operator_div::wi_fold (tree type,
  		       const wide_int &lh_lb, const wide_int &lh_ub,
  		       const wide_int &rh_lb, const wide_int &rh_ub) const
  {
    // If we know we will divide by zero, return undefined.
    if (rh_lb == 0 && rh_ub == 0)
!     return value_range ();
  
    const wide_int dividend_min = lh_lb;
    const wide_int dividend_max = lh_ub;
--- 1248,1264 ----
    return overflow;
  }
  
! void
! operator_div::wi_fold (value_range &r, tree type,
  		       const wide_int &lh_lb, const wide_int &lh_ub,
  		       const wide_int &rh_lb, const wide_int &rh_ub) const
  {
    // If we know we will divide by zero, return undefined.
    if (rh_lb == 0 && rh_ub == 0)
!     {
!       r = value_range ();
!       return;
!     }
  
    const wide_int dividend_min = lh_lb;
    const wide_int dividend_max = lh_ub;
*************** operator_div::wi_fold (tree type,
*** 1270,1307 ****
  
    // If we know we won't divide by zero, just do the division.
    if (!wi_includes_zero_p (type, divisor_min, divisor_max))
!     return wi_cross_product (type, dividend_min, dividend_max,
! 			     divisor_min, divisor_max);
  
    // If flag_non_call_exceptions, we must not eliminate a division by zero.
    if (cfun->can_throw_non_call_exceptions)
!     return value_range (type);
  
    // If we're definitely dividing by zero, there's nothing to do.
    if (wi_zero_p (type, divisor_min, divisor_max))
!     return value_range ();
  
    // 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.
-   value_range r;
    if (wi::neg_p (divisor_min, sign))
!     r = wi_cross_product (type, dividend_min, dividend_max,
! 			  divisor_min, wi::minus_one (prec));
    // Then divide by the non-zero positive numbers, if any.
    if (wi::gt_p (divisor_max, wi::zero (prec), sign))
      {
        value_range tmp;
!       tmp = wi_cross_product (type, dividend_min, dividend_max,
! 			      wi::one (prec), divisor_max);
        r.union_ (tmp);
      }
!   return r;
  }
  
  operator_div op_trunc_div (TRUNC_DIV_EXPR);
! operator_div op_floor_div(FLOOR_DIV_EXPR);
  operator_div op_round_div (ROUND_DIV_EXPR);
  operator_div op_ceil_div (CEIL_DIV_EXPR);
  
--- 1270,1319 ----
  
    // If we know we won't divide by zero, just do the division.
    if (!wi_includes_zero_p (type, divisor_min, divisor_max))
!     {
!       wi_cross_product (r, type, dividend_min, dividend_max,
! 		       divisor_min, divisor_max);
!       return;
!     }
  
    // If flag_non_call_exceptions, we must not eliminate a division by zero.
    if (cfun->can_throw_non_call_exceptions)
!     {
!       r = value_range (type);
!       return;
!     }
  
    // If we're definitely dividing by zero, there's nothing to do.
    if (wi_zero_p (type, divisor_min, divisor_max))
!     {
!       r = value_range ();
!       return;
!     }
  
    // 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))
!     wi_cross_product (r, type, dividend_min, dividend_max,
! 		      divisor_min, wi::minus_one (prec));
!   else
!     r = value_range ();
! 
    // Then divide by the non-zero positive numbers, if any.
    if (wi::gt_p (divisor_max, wi::zero (prec), sign))
      {
        value_range tmp;
!       wi_cross_product (tmp, type, dividend_min, dividend_max,
! 			wi::one (prec), divisor_max);
        r.union_ (tmp);
      }
!   // We shouldn't still have undefined here.
!   gcc_checking_assert (!r.undefined_p ());
  }
  
  operator_div op_trunc_div (TRUNC_DIV_EXPR);
! operator_div op_floor_div (FLOOR_DIV_EXPR);
  operator_div op_round_div (ROUND_DIV_EXPR);
  operator_div op_ceil_div (CEIL_DIV_EXPR);
  
*************** operator_exact_divide::op1_range (value_
*** 1331,1337 ****
    if (op2.singleton_p (&offset)
        && !integer_zerop (offset))
      {
!       r = range_op_handler (MULT_EXPR, type)->fold_range (type, lhs, op2);
        return true;
      }
    return false;
--- 1343,1349 ----
    if (op2.singleton_p (&offset)
        && !integer_zerop (offset))
      {
!       range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2);
        return true;
      }
    return false;
*************** operator_exact_divide::op1_range (value_
*** 1341,1367 ****
  class operator_lshift : public cross_product_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
  
!   virtual value_range wi_fold (tree type,
! 			  const wide_int &lh_lb, const wide_int &lh_ub,
! 			  const wide_int &rh_lb, const wide_int &rh_ub) const;
    virtual bool wi_op_overflows (wide_int &res,
  				tree type,
  				const wide_int &,
  				const wide_int &) const;
  } op_lshift;
  
! value_range
! operator_lshift::fold_range (tree type,
  			     const value_range &op1,
  			     const value_range &op2) const
  {
-   value_range r;
    if (undefined_shift_range_check (r, type, op2))
!     return r;
  
    // Transform left shifts by constants into multiplies.
    if (op2.singleton_p ())
--- 1353,1378 ----
  class operator_lshift : public cross_product_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
  
!   virtual void wi_fold (value_range &r, tree type,
! 			const wide_int &lh_lb, const wide_int &lh_ub,
! 			const wide_int &rh_lb, const wide_int &rh_ub) const;
    virtual bool wi_op_overflows (wide_int &res,
  				tree type,
  				const wide_int &,
  				const wide_int &) const;
  } op_lshift;
  
! void
! operator_lshift::fold_range (value_range &r, tree type,
  			     const value_range &op1,
  			     const value_range &op2) const
  {
    if (undefined_shift_range_check (r, type, op2))
!     return;
  
    // Transform left shifts by constants into multiplies.
    if (op2.singleton_p ())
*************** operator_lshift::fold_range (tree type,
*** 1375,1392 ****
        bool saved_flag_wrapv_pointer = flag_wrapv_pointer;
        flag_wrapv = 1;
        flag_wrapv_pointer = 1;
!       r = range_op_handler (MULT_EXPR, type)->fold_range (type, op1, mult);
        flag_wrapv = saved_flag_wrapv;
        flag_wrapv_pointer = saved_flag_wrapv_pointer;
!       return r;
      }
  
    // Otherwise, invoke the generic fold routine.
!   return range_operator::fold_range (type, op1, op2);
  }
  
! value_range
! operator_lshift::wi_fold (tree type,
  			  const wide_int &lh_lb, const wide_int &lh_ub,
  			  const wide_int &rh_lb, const wide_int &rh_ub) const
  {
--- 1386,1403 ----
        bool saved_flag_wrapv_pointer = flag_wrapv_pointer;
        flag_wrapv = 1;
        flag_wrapv_pointer = 1;
!       range_op_handler (MULT_EXPR, type)->fold_range (r, type, op1, mult);
        flag_wrapv = saved_flag_wrapv;
        flag_wrapv_pointer = saved_flag_wrapv_pointer;
!       return;
      }
  
    // Otherwise, invoke the generic fold routine.
!   range_operator::fold_range (r, type, op1, op2);
  }
  
! void
! operator_lshift::wi_fold (value_range &r, tree type,
  			  const wide_int &lh_lb, const wide_int &lh_ub,
  			  const wide_int &rh_lb, const wide_int &rh_ub) const
  {
*************** operator_lshift::wi_fold (tree type,
*** 1440,1448 ****
      }
  
    if (in_bounds)
!     return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub);
! 
!   return value_range (type);
  }
  
  bool
--- 1451,1459 ----
      }
  
    if (in_bounds)
!     wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
!   else
!    r = value_range (type);
  }
  
  bool
*************** operator_lshift::wi_op_overflows (wide_i
*** 1466,1479 ****
  class operator_rshift : public cross_product_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
    virtual bool wi_op_overflows (wide_int &res,
  				tree type,
  				const wide_int &w0,
--- 1477,1490 ----
  class operator_rshift : public cross_product_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
    virtual bool wi_op_overflows (wide_int &res,
  				tree type,
  				const wide_int &w0,
*************** operator_rshift::wi_op_overflows (wide_i
*** 1499,1547 ****
    return false;
  }
  
! value_range
! operator_rshift::fold_range (tree type,
  			     const value_range &op1,
  			     const value_range &op2) const
  {
-   value_range r;
    if (undefined_shift_range_check (r, type, op2))
!     return r;
  
    // Otherwise, invoke the generic fold routine.
!   return range_operator::fold_range (type, op1, op2);
  }
  
! value_range
! operator_rshift::wi_fold (tree type,
  			  const wide_int &lh_lb, const wide_int &lh_ub,
  			  const wide_int &rh_lb, const wide_int &rh_ub) const
  {
!   return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub);
  }
  
  
  class operator_cast: public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  
  } op_convert;
  
! value_range
! operator_cast::fold_range (tree type ATTRIBUTE_UNUSED,
  			   const value_range &lh,
  			   const value_range &rh) const
  {
-   value_range r;
    if (empty_range_check (r, lh, rh))
!     return r;
! 
    tree inner = lh.type ();
    tree outer = rh.type ();
    gcc_checking_assert (rh.varying_p ());
--- 1510,1556 ----
    return false;
  }
  
! void
! operator_rshift::fold_range (value_range &r, tree type,
  			     const value_range &op1,
  			     const value_range &op2) const
  {
    if (undefined_shift_range_check (r, type, op2))
!     return;
  
    // Otherwise, invoke the generic fold routine.
!   range_operator::fold_range (r, type, op1, op2);
  }
  
! void
! operator_rshift::wi_fold (value_range &r, tree type,
  			  const wide_int &lh_lb, const wide_int &lh_ub,
  			  const wide_int &rh_lb, const wide_int &rh_ub) const
  {
!   wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
  }
  
  
  class operator_cast: public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  
  } op_convert;
  
! void
! operator_cast::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
  			   const value_range &lh,
  			   const value_range &rh) const
  {
    if (empty_range_check (r, lh, rh))
!     return;
!   
    tree inner = lh.type ();
    tree outer = rh.type ();
    gcc_checking_assert (rh.varying_p ());
*************** operator_cast::fold_range (tree type ATT
*** 1551,1556 ****
--- 1560,1567 ----
    unsigned inner_prec = TYPE_PRECISION (inner);
    unsigned outer_prec = TYPE_PRECISION (outer);
  
+   // Start with an empty range and add subranges.
+   r = value_range ();
    for (unsigned x = 0; x < lh.num_pairs (); ++x)
      {
        wide_int lh_lb = lh.lower_bound (x);
*************** operator_cast::fold_range (tree type ATT
*** 1572,1585 ****
  	      || !wi::eq_p (max, wi::max_value (outer_prec, outer_sign)))
  	    {
  	      value_range tmp;
! 	      tmp = create_possibly_reversed_range (type, min, max);
  	      r.union_ (tmp);
  	      continue;
  	    }
  	}
!       return value_range (type);
      }
-   return r;
  }
  
  bool
--- 1583,1596 ----
  	      || !wi::eq_p (max, wi::max_value (outer_prec, outer_sign)))
  	    {
  	      value_range tmp;
! 	      create_possibly_reversed_range (tmp, type, min, max);
  	      r.union_ (tmp);
  	      continue;
  	    }
  	}
!       r = value_range (type);
!       return;
      }
  }
  
  bool
*************** operator_cast::op1_range (value_range &r
*** 1588,1593 ****
--- 1599,1605 ----
  			  const value_range &op2) const
  {
    tree lhs_type = lhs.type ();
+   value_range tmp;
    gcc_checking_assert (types_compatible_p (op2.type(), type));
  
    // If the precision of the LHS is smaller than the precision of the
*************** operator_cast::op1_range (value_range &r
*** 1598,1612 ****
        // If we've been passed an actual value for the RHS rather than
        // the type, see if it fits the LHS, and if so, then we can allow
        // it.
!       r = op2;
!       r = fold_range (lhs_type, r, value_range (lhs_type));
!       r = fold_range (type, r, value_range (type));
!       if (r == op2)
          {
  	  // We know the value of the RHS fits in the LHS type, so
  	  // convert the LHS and remove any values that arent in OP2.
! 	  r = lhs;
! 	  r = fold_range (type, r, value_range (type));
  	  r.intersect (op2);
  	  return true;
  	}
--- 1610,1622 ----
        // If we've been passed an actual value for the RHS rather than
        // the type, see if it fits the LHS, and if so, then we can allow
        // it.
!       fold_range (r, lhs_type, op2, value_range (lhs_type));
!       fold_range (tmp, type, r, value_range (type));
!       if (tmp == op2)
          {
  	  // We know the value of the RHS fits in the LHS type, so
  	  // convert the LHS and remove any values that arent in OP2.
! 	  fold_range (r, type, lhs, value_range (type));
  	  r.intersect (op2);
  	  return true;
  	}
*************** operator_cast::op1_range (value_range &r
*** 1646,1662 ****
    if (TYPE_PRECISION (lhs_type) > TYPE_PRECISION (type))
      {
        // Cast the range of the RHS to the type of the LHS.
!       value_range op_type (type);
!       op_type = fold_range (lhs_type, op_type, value_range (lhs_type));
! 
!       // Intersect this with the LHS range will produce the RHS range.
!       r = range_intersect (lhs, op_type);
      }
    else
!     r = lhs;
  
    // Cast the calculated range to the type of the RHS.
!   r = fold_range (type, r, value_range (type));
    return true;
  }
  
--- 1656,1671 ----
    if (TYPE_PRECISION (lhs_type) > TYPE_PRECISION (type))
      {
        // Cast the range of the RHS to the type of the LHS.
!       fold_range (tmp, lhs_type, value_range (type), value_range (lhs_type));
!       // Intersect this with the LHS range will produce the range, which
!       // will be cast to the RHS type before returning.
!       tmp.intersect (lhs);
      }
    else
!     tmp = lhs;
  
    // Cast the calculated range to the type of the RHS.
!   fold_range (r, type, tmp, value_range (type));
    return true;
  }
  
*************** operator_cast::op1_range (value_range &r
*** 1664,1672 ****
  class operator_logical_and : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &lh,
! 				  const value_range &rh) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
--- 1673,1681 ----
  class operator_logical_and : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &lh,
! 			   const value_range &rh) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
*************** public:
*** 1676,1702 ****
  } op_logical_and;
  
  
! value_range
! operator_logical_and::fold_range (tree type,
  				  const value_range &lh,
  				  const value_range &rh) const
  {
-   value_range r;
    if (empty_range_check (r, lh, rh))
!     return r;
  
    // 0 && anything is 0.
    if ((wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (lh.upper_bound (), 0))
        || (wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (rh.upper_bound (), 0)))
!     return range_false (type);
! 
!   // To reach this point, there must be a logical 1 on each side, and
!   // the only remaining question is whether there is a zero or not.
!   if (lh.contains_p (build_zero_cst (lh.type ()))
!       || rh.contains_p (build_zero_cst (rh.type ())))
!     return range_true_and_false (type);
! 
!   return range_true (type);
  }
  
  bool
--- 1685,1709 ----
  } op_logical_and;
  
  
! void
! operator_logical_and::fold_range (value_range &r, tree type,
  				  const value_range &lh,
  				  const value_range &rh) const
  {
    if (empty_range_check (r, lh, rh))
!     return;
  
    // 0 && anything is 0.
    if ((wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (lh.upper_bound (), 0))
        || (wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (rh.upper_bound (), 0)))
!     r = range_false (type);
!   else if (lh.contains_p (build_zero_cst (lh.type ()))
! 	   || rh.contains_p (build_zero_cst (rh.type ())))
!     // To reach this point, there must be a logical 1 on each side, and
!     // the only remaining question is whether there is a zero or not.
!     r = range_true_and_false (type);
!   else
!     r = range_true (type);
  }
  
  bool
*************** public:
*** 1738,1748 ****
    virtual bool op2_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op1) const;
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_bitwise_and;
  
  // Optimize BIT_AND_EXPR and BIT_IOR_EXPR in terms of a mask if
--- 1745,1755 ----
    virtual bool op2_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op1) const;
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_bitwise_and;
  
  // Optimize BIT_AND_EXPR and BIT_IOR_EXPR in terms of a mask if
*************** wi_optimize_and_or (value_range &r,
*** 1820,1826 ****
      }
    else
      gcc_unreachable ();
!   r = value_range_with_overflow (type, res_lb, res_ub);
    return true;
  }
  
--- 1827,1833 ----
      }
    else
      gcc_unreachable ();
!   value_range_with_overflow (r, type, res_lb, res_ub);
    return true;
  }
  
*************** wi_set_zero_nonzero_bits (tree type,
*** 1864,1879 ****
      }
  }
  
! value_range
! operator_bitwise_and::wi_fold (tree type,
  			       const wide_int &lh_lb,
  			       const wide_int &lh_ub,
  			       const wide_int &rh_lb,
  			       const wide_int &rh_ub) const
  {
-   value_range r;
    if (wi_optimize_and_or (r, BIT_AND_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
!     return r;
  
    wide_int maybe_nonzero_lh, mustbe_nonzero_lh;
    wide_int maybe_nonzero_rh, mustbe_nonzero_rh;
--- 1871,1885 ----
      }
  }
  
! void
! operator_bitwise_and::wi_fold (value_range &r, tree type,
  			       const wide_int &lh_lb,
  			       const wide_int &lh_ub,
  			       const wide_int &rh_lb,
  			       const wide_int &rh_ub) const
  {
    if (wi_optimize_and_or (r, BIT_AND_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
!     return;
  
    wide_int maybe_nonzero_lh, mustbe_nonzero_lh;
    wide_int maybe_nonzero_rh, mustbe_nonzero_rh;
*************** operator_bitwise_and::wi_fold (tree type
*** 1918,1926 ****
      }
    // If the limits got swapped around, return varying.
    if (wi::gt_p (new_lb, new_ub,sign))
!     return value_range (type);
! 
!   return value_range_with_overflow (type, new_lb, new_ub);
  }
  
  bool
--- 1924,1932 ----
      }
    // If the limits got swapped around, return varying.
    if (wi::gt_p (new_lb, new_ub,sign))
!     r = value_range (type);
!   else
!     value_range_with_overflow (r, type, new_lb, new_ub);
  }
  
  bool
*************** operator_bitwise_and::op2_range (value_r
*** 1949,1957 ****
  class operator_logical_or : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &lh,
! 				  const value_range &rh) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
--- 1955,1963 ----
  class operator_logical_or : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &lh,
! 			   const value_range &rh) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
*************** public:
*** 1960,1975 ****
  			  const value_range &op1) const;
  } op_logical_or;
  
! value_range
! operator_logical_or::fold_range (tree type ATTRIBUTE_UNUSED,
  				 const value_range &lh,
  				 const value_range &rh) const
  {
-   value_range r;
    if (empty_range_check (r, lh, rh))
!     return r;
  
!   return range_union (lh, rh);
  }
  
  bool
--- 1966,1980 ----
  			  const value_range &op1) const;
  } op_logical_or;
  
! void
! operator_logical_or::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
  				 const value_range &lh,
  				 const value_range &rh) const
  {
    if (empty_range_check (r, lh, rh))
!     return;
  
!   r = range_union (lh, rh);
  }
  
  bool
*************** public:
*** 2011,2033 ****
    virtual bool op2_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op1) const;
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_bitwise_or;
  
! value_range
! operator_bitwise_or::wi_fold (tree type,
  			      const wide_int &lh_lb,
  			      const wide_int &lh_ub,
  			      const wide_int &rh_lb,
  			      const wide_int &rh_ub) const
  {
-   value_range r;
    if (wi_optimize_and_or (r, BIT_IOR_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
!     return r;
  
    wide_int maybe_nonzero_lh, mustbe_nonzero_lh;
    wide_int maybe_nonzero_rh, mustbe_nonzero_rh;
--- 2016,2037 ----
    virtual bool op2_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op1) const;
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_bitwise_or;
  
! void
! operator_bitwise_or::wi_fold (value_range &r, tree type,
  			      const wide_int &lh_lb,
  			      const wide_int &lh_ub,
  			      const wide_int &rh_lb,
  			      const wide_int &rh_ub) const
  {
    if (wi_optimize_and_or (r, BIT_IOR_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
!     return;
  
    wide_int maybe_nonzero_lh, mustbe_nonzero_lh;
    wide_int maybe_nonzero_rh, mustbe_nonzero_rh;
*************** operator_bitwise_or::wi_fold (tree type,
*** 2056,2064 ****
      new_lb = wi::max (new_lb, rh_lb, sign);
    // If the limits got swapped around, return varying.
    if (wi::gt_p (new_lb, new_ub,sign))
!     return value_range (type);
! 
!   return value_range_with_overflow (type, new_lb, new_ub);
  }
  
  bool
--- 2060,2068 ----
      new_lb = wi::max (new_lb, rh_lb, sign);
    // If the limits got swapped around, return varying.
    if (wi::gt_p (new_lb, new_ub,sign))
!     r = value_range (type);
!   else
!     value_range_with_overflow (r, type, new_lb, new_ub);
  }
  
  bool
*************** operator_bitwise_or::op2_range (value_ra
*** 2087,2101 ****
  class operator_bitwise_xor : public range_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_bitwise_xor;
  
! value_range
! operator_bitwise_xor::wi_fold (tree type,
  			       const wide_int &lh_lb,
  			       const wide_int &lh_ub,
  			       const wide_int &rh_lb,
--- 2091,2105 ----
  class operator_bitwise_xor : public range_operator
  {
  public:
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_bitwise_xor;
  
! void
! operator_bitwise_xor::wi_fold (value_range &r, tree type,
  			       const wide_int &lh_lb,
  			       const wide_int &lh_ub,
  			       const wide_int &rh_lb,
*************** operator_bitwise_xor::wi_fold (tree type
*** 2120,2143 ****
    // If the range has all positive or all negative values, the result
    // is better than VARYING.
    if (wi::lt_p (new_lb, 0, sign) || wi::ge_p (new_ub, 0, sign))
!     return value_range_with_overflow (type, new_lb, new_ub);
! 
!   return value_range (type);
  }
  
  
  class operator_trunc_mod : public range_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_trunc_mod;
  
! value_range
! operator_trunc_mod::wi_fold (tree type,
  			     const wide_int &lh_lb,
  			     const wide_int &lh_ub,
  			     const wide_int &rh_lb,
--- 2124,2147 ----
    // If the range has all positive or all negative values, the result
    // is better than VARYING.
    if (wi::lt_p (new_lb, 0, sign) || wi::ge_p (new_ub, 0, sign))
!     value_range_with_overflow (r, type, new_lb, new_ub);
!   else
!     r = value_range (type);
  }
  
  
  class operator_trunc_mod : public range_operator
  {
  public:
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_trunc_mod;
  
! void
! operator_trunc_mod::wi_fold (value_range &r, tree type,
  			     const wide_int &lh_lb,
  			     const wide_int &lh_ub,
  			     const wide_int &rh_lb,
*************** operator_trunc_mod::wi_fold (tree type,
*** 2149,2155 ****
  
    // Mod 0 is undefined.  Return undefined.
    if (wi_zero_p (type, rh_lb, rh_ub))
!     return value_range ();
  
    // ABS (A % B) < ABS (B) and either 0 <= A % B <= A or A <= A % B <= 0.
    new_ub = rh_ub - 1;
--- 2153,2162 ----
  
    // Mod 0 is undefined.  Return undefined.
    if (wi_zero_p (type, rh_lb, rh_ub))
!     {
!       r = value_range ();
!       return;
!     }
  
    // ABS (A % B) < ABS (B) and either 0 <= A % B <= A or A <= A % B <= 0.
    new_ub = rh_ub - 1;
*************** operator_trunc_mod::wi_fold (tree type,
*** 2174,2189 ****
      tmp = wi::zero (prec);
    new_ub = wi::min (new_ub, tmp, sign);
  
!   return value_range_with_overflow (type, new_lb, new_ub);
  }
  
  
  class operator_logical_not : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &lh,
! 				  const value_range &rh) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
--- 2181,2196 ----
      tmp = wi::zero (prec);
    new_ub = wi::min (new_ub, tmp, sign);
  
!   value_range_with_overflow (r, type, new_lb, new_ub);
  }
  
  
  class operator_logical_not : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &lh,
! 			   const value_range &rh) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
*************** public:
*** 2203,2223 ****
  // 	 b_2 = x_1 < 20		[0,0] = x_1 < 20,   false, so x_1 == [20, 255]
  //   which is the result we are looking for.. so.. pass it through.
  
! value_range
! operator_logical_not::fold_range (tree type,
  				  const value_range &lh,
  				  const value_range &rh ATTRIBUTE_UNUSED) const
  {
-   value_range r;
    if (empty_range_check (r, lh, rh))
!     return r;
  
    if (lh.varying_p () || lh.undefined_p ())
      r = lh;
    else
      r = range_invert (lh);
    gcc_checking_assert (lh.type() == type);
!   return r;
  }
  
  bool
--- 2210,2229 ----
  // 	 b_2 = x_1 < 20		[0,0] = x_1 < 20,   false, so x_1 == [20, 255]
  //   which is the result we are looking for.. so.. pass it through.
  
! void
! operator_logical_not::fold_range (value_range &r, tree type,
  				  const value_range &lh,
  				  const value_range &rh ATTRIBUTE_UNUSED) const
  {
    if (empty_range_check (r, lh, rh))
!     return;
  
    if (lh.varying_p () || lh.undefined_p ())
      r = lh;
    else
      r = range_invert (lh);
    gcc_checking_assert (lh.type() == type);
!   return;
  }
  
  bool
*************** operator_logical_not::op1_range (value_r
*** 2237,2264 ****
  class operator_bitwise_not : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &lh,
! 				  const value_range &rh) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_bitwise_not;
  
! value_range
! operator_bitwise_not::fold_range (tree type,
  				  const value_range &lh,
  				  const value_range &rh) const
  {
-   value_range r;
    if (empty_range_check (r, lh, rh))
!     return r;
  
    // ~X is simply -1 - X.
    value_range minusone (type, wi::minus_one (TYPE_PRECISION (type)),
  			wi::minus_one (TYPE_PRECISION (type)));
!   r = range_op_handler (MINUS_EXPR, type)->fold_range (type, minusone, lh);
!   return r;
  }
  
  bool
--- 2243,2269 ----
  class operator_bitwise_not : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &lh,
! 			   const value_range &rh) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_bitwise_not;
  
! void
! operator_bitwise_not::fold_range (value_range &r, tree type,
  				  const value_range &lh,
  				  const value_range &rh) const
  {
    if (empty_range_check (r, lh, rh))
!     return;
  
    // ~X is simply -1 - X.
    value_range minusone (type, wi::minus_one (TYPE_PRECISION (type)),
  			wi::minus_one (TYPE_PRECISION (type)));
!   range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone, lh);
!   return;
  }
  
  bool
*************** operator_bitwise_not::op1_range (value_r
*** 2267,2273 ****
  				 const value_range &op2) const
  {
    // ~X is -1 - X and since bitwise NOT is involutary...do it again.
!   r = fold_range (type, lhs, op2);
    return true;
  }
  
--- 2272,2278 ----
  				 const value_range &op2) const
  {
    // ~X is -1 - X and since bitwise NOT is involutary...do it again.
!   fold_range (r, type, lhs, op2);
    return true;
  }
  
*************** operator_bitwise_not::op1_range (value_r
*** 2275,2311 ****
  class operator_cst : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
  } op_integer_cst;
  
! value_range
! operator_cst::fold_range (tree type ATTRIBUTE_UNUSED,
  			  const value_range &lh,
  			  const value_range &rh ATTRIBUTE_UNUSED) const
  {
!   return lh;
  }
  
  
  class operator_identity : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_identity;
  
! value_range
! operator_identity::fold_range (tree type ATTRIBUTE_UNUSED,
  			       const value_range &lh,
  			       const value_range &rh ATTRIBUTE_UNUSED) const
  {
!   return lh;
  }
  
  bool
--- 2280,2316 ----
  class operator_cst : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
  } op_integer_cst;
  
! void
! operator_cst::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
  			  const value_range &lh,
  			  const value_range &rh ATTRIBUTE_UNUSED) const
  {
!   r = lh;
  }
  
  
  class operator_identity : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_identity;
  
! void
! operator_identity::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
  			       const value_range &lh,
  			       const value_range &rh ATTRIBUTE_UNUSED) const
  {
!   r = lh;
  }
  
  bool
*************** operator_identity::op1_range (value_rang
*** 2321,2338 ****
  class operator_abs : public range_operator
  {
   public:
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_abs;
  
! value_range
! operator_abs::wi_fold (tree type,
  		       const wide_int &lh_lb, const wide_int &lh_ub,
  		       const wide_int &rh_lb ATTRIBUTE_UNUSED,
  		       const wide_int &rh_ub ATTRIBUTE_UNUSED) const
--- 2326,2343 ----
  class operator_abs : public range_operator
  {
   public:
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_abs;
  
! void
! operator_abs::wi_fold (value_range &r, tree type,
  		       const wide_int &lh_lb, const wide_int &lh_ub,
  		       const wide_int &rh_lb ATTRIBUTE_UNUSED,
  		       const wide_int &rh_ub ATTRIBUTE_UNUSED) const
*************** operator_abs::wi_fold (tree type,
*** 2343,2356 ****
  
    // Pass through LH for the easy cases.
    if (sign == UNSIGNED || wi::ge_p (lh_lb, 0, sign))
!     return value_range (type, lh_lb, lh_ub);
  
    // -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 (!TYPE_OVERFLOW_UNDEFINED (type) && wi::eq_p (lh_lb, min_value))
!     return value_range (type);
  
    // ABS_EXPR may flip the range around, if the original range
    // included negative values.
--- 2348,2367 ----
  
    // Pass through LH for the easy cases.
    if (sign == UNSIGNED || wi::ge_p (lh_lb, 0, sign))
!     {
!       r = value_range (type, lh_lb, lh_ub);
!       return;
!     }
  
    // -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 (!TYPE_OVERFLOW_UNDEFINED (type) && wi::eq_p (lh_lb, min_value))
!     {
!       r = value_range (type, lh_lb, lh_ub);
!       return;
!     }
  
    // ABS_EXPR may flip the range around, if the original range
    // included negative values.
*************** operator_abs::wi_fold (tree type,
*** 2386,2392 ****
        min = wi::zero (prec);
        max = max_value;
      }
!   return value_range (type, min, max);
  }
  
  bool
--- 2397,2403 ----
        min = wi::zero (prec);
        max = max_value;
      }
!   r = value_range (type, min, max);
  }
  
  bool
*************** operator_abs::op1_range (value_range &r,
*** 2418,2430 ****
  class operator_absu : public range_operator
  {
   public:
!   virtual value_range wi_fold (tree type,
! 			  const wide_int &lh_lb, const wide_int &lh_ub,
! 			  const wide_int &rh_lb, const wide_int &rh_ub) const;
  } op_absu;
  
! value_range
! operator_absu::wi_fold (tree type,
  			const wide_int &lh_lb, const wide_int &lh_ub,
  			const wide_int &rh_lb ATTRIBUTE_UNUSED,
  			const wide_int &rh_ub ATTRIBUTE_UNUSED) const
--- 2429,2441 ----
  class operator_absu : public range_operator
  {
   public:
!   virtual void wi_fold (value_range &r, tree type,
! 			const wide_int &lh_lb, const wide_int &lh_ub,
! 			const wide_int &rh_lb, const wide_int &rh_ub) const;
  } op_absu;
  
! void
! operator_absu::wi_fold (value_range &r, tree type,
  			const wide_int &lh_lb, const wide_int &lh_ub,
  			const wide_int &rh_lb ATTRIBUTE_UNUSED,
  			const wide_int &rh_ub ATTRIBUTE_UNUSED) const
*************** operator_absu::wi_fold (tree type,
*** 2455,2487 ****
      }
  
    gcc_checking_assert (TYPE_UNSIGNED (type));
!   return value_range (type, new_lb, new_ub);
  }
  
  
  class operator_negate : public range_operator
  {
   public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_negate;
  
! value_range
! operator_negate::fold_range (tree type,
  			     const value_range &lh,
  			     const value_range &rh) const
  {
-   value_range r;
    if (empty_range_check (r, lh, rh))
!     return r;
    // -X is simply 0 - X.
!   return
!     range_op_handler (MINUS_EXPR, type)->fold_range (type,
! 						     range_zero (type), lh);
  }
  
  bool
--- 2466,2496 ----
      }
  
    gcc_checking_assert (TYPE_UNSIGNED (type));
!   r = value_range (type, new_lb, new_ub);
  }
  
  
  class operator_negate : public range_operator
  {
   public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_negate;
  
! void
! operator_negate::fold_range (value_range &r, tree type,
  			     const value_range &lh,
  			     const value_range &rh) const
  {
    if (empty_range_check (r, lh, rh))
!     return;
    // -X is simply 0 - X.
!   range_op_handler (MINUS_EXPR, type)->fold_range (r, type,
! 						   range_zero (type), lh);
  }
  
  bool
*************** operator_negate::op1_range (value_range
*** 2490,2496 ****
  			    const value_range &op2) const
  {
    // NEGATE is involutory.
!   r = fold_range (type, lhs, op2);
    return true;
  }
  
--- 2499,2505 ----
  			    const value_range &op2) const
  {
    // NEGATE is involutory.
!   fold_range (r, type, lhs, op2);
    return true;
  }
  
*************** operator_negate::op1_range (value_range
*** 2498,2526 ****
  class operator_addr_expr : public range_operator
  {
  public:
!   virtual value_range fold_range (tree type,
! 				  const value_range &op1,
! 				  const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_addr;
  
! value_range
! operator_addr_expr::fold_range (tree type,
  				const value_range &lh,
  				const value_range &rh) const
  {
-   value_range r;
    if (empty_range_check (r, lh, rh))
!     return r;
  
    // Return a non-null pointer of the LHS type (passed in op2).
    if (lh.zero_p ())
!     return range_zero (type);
!   if (!lh.contains_p (build_zero_cst (lh.type ())))
!     return range_nonzero (type);
!   return value_range (type);
  }
  
  bool
--- 2507,2535 ----
  class operator_addr_expr : public range_operator
  {
  public:
!   virtual void fold_range (value_range &r, tree type,
! 			   const value_range &op1,
! 			   const value_range &op2) const;
    virtual bool op1_range (value_range &r, tree type,
  			  const value_range &lhs,
  			  const value_range &op2) const;
  } op_addr;
  
! void
! operator_addr_expr::fold_range (value_range &r, tree type,
  				const value_range &lh,
  				const value_range &rh) const
  {
    if (empty_range_check (r, lh, rh))
!     return;
  
    // Return a non-null pointer of the LHS type (passed in op2).
    if (lh.zero_p ())
!     r = range_zero (type);
!   else if (!lh.contains_p (build_zero_cst (lh.type ())))
!     r = range_nonzero (type);
!   else
!     r = value_range (type);
  }
  
  bool
*************** operator_addr_expr::op1_range (value_ran
*** 2528,2534 ****
  			       const value_range &lhs,
  			       const value_range &op2) const
  {
!   r = operator_addr_expr::fold_range (type, lhs, op2);
    return true;
  }
  
--- 2537,2543 ----
  			       const value_range &lhs,
  			       const value_range &op2) const
  {
!   operator_addr_expr::fold_range (r, type, lhs, op2);
    return true;
  }
  
*************** operator_addr_expr::op1_range (value_ran
*** 2536,2550 ****
  class pointer_plus_operator : public range_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
! 			       const wide_int &lh_lb,
! 			       const wide_int &lh_ub,
! 			       const wide_int &rh_lb,
! 			       const wide_int &rh_ub) const;
  } op_pointer_plus;
  
! value_range
! pointer_plus_operator::wi_fold (tree type,
  				const wide_int &lh_lb,
  				const wide_int &lh_ub,
  				const wide_int &rh_lb,
--- 2545,2559 ----
  class pointer_plus_operator : public range_operator
  {
  public:
!   virtual void wi_fold (value_range &r, tree type,
! 		        const wide_int &lh_lb,
! 		        const wide_int &lh_ub,
! 		        const wide_int &rh_lb,
! 		        const wide_int &rh_ub) const;
  } op_pointer_plus;
  
! void
! pointer_plus_operator::wi_fold (value_range &r, tree type,
  				const wide_int &lh_lb,
  				const wide_int &lh_ub,
  				const wide_int &rh_lb,
*************** pointer_plus_operator::wi_fold (tree typ
*** 2571,2594 ****
        && !TYPE_OVERFLOW_WRAPS (type)
        && (flag_delete_null_pointer_checks
  	  || !wi::sign_mask (rh_ub)))
!     return range_nonzero (type);
!   if (lh_lb == lh_ub && lh_lb == 0
!       && rh_lb == rh_ub && rh_lb == 0)
!     return range_zero (type);
!   return value_range (type);
  }
  
  
  class pointer_min_max_operator : public range_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
!                           const wide_int &lh_lb, const wide_int &lh_ub,
!                           const wide_int &rh_lb, const wide_int &rh_ub) const;
  } op_ptr_min_max;
  
! value_range
! pointer_min_max_operator::wi_fold (tree type,
  				   const wide_int &lh_lb,
  				   const wide_int &lh_ub,
  				   const wide_int &rh_lb,
--- 2580,2604 ----
        && !TYPE_OVERFLOW_WRAPS (type)
        && (flag_delete_null_pointer_checks
  	  || !wi::sign_mask (rh_ub)))
!     r = range_nonzero (type);
!   else if (lh_lb == lh_ub && lh_lb == 0
! 	   && rh_lb == rh_ub && rh_lb == 0)
!     r = range_zero (type);
!   else
!    r = value_range (type);
  }
  
  
  class pointer_min_max_operator : public range_operator
  {
  public:
!   virtual void wi_fold (value_range & r, tree type,
! 			const wide_int &lh_lb, const wide_int &lh_ub,
! 			const wide_int &rh_lb, const wide_int &rh_ub) const;
  } op_ptr_min_max;
  
! void
! pointer_min_max_operator::wi_fold (value_range &r, tree type,
  				   const wide_int &lh_lb,
  				   const wide_int &lh_ub,
  				   const wide_int &rh_lb,
*************** pointer_min_max_operator::wi_fold (tree
*** 2600,2622 ****
    // are varying.
    if (!wi_includes_zero_p (type, lh_lb, lh_ub)
        && !wi_includes_zero_p (type, rh_lb, rh_ub))
!     return range_nonzero (type);
!   if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub))
!     return range_zero (type);
!   return value_range (type);
  }
  
  
  class pointer_and_operator : public range_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
! 			  const wide_int &lh_lb, const wide_int &lh_ub,
! 			  const wide_int &rh_lb, const wide_int &rh_ub) const;
  } op_pointer_and;
  
! value_range
! pointer_and_operator::wi_fold (tree type,
  			       const wide_int &lh_lb,
  			       const wide_int &lh_ub,
  			       const wide_int &rh_lb ATTRIBUTE_UNUSED,
--- 2610,2633 ----
    // are varying.
    if (!wi_includes_zero_p (type, lh_lb, lh_ub)
        && !wi_includes_zero_p (type, rh_lb, rh_ub))
!     r = range_nonzero (type);
!   else if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub))
!     r = range_zero (type);
!   else
!     r = value_range (type);
  }
  
  
  class pointer_and_operator : public range_operator
  {
  public:
!   virtual void wi_fold (value_range &r, tree type,
! 			const wide_int &lh_lb, const wide_int &lh_ub,
! 			const wide_int &rh_lb, const wide_int &rh_ub) const;
  } op_pointer_and;
  
! void
! pointer_and_operator::wi_fold (value_range &r, tree type,
  			       const wide_int &lh_lb,
  			       const wide_int &lh_ub,
  			       const wide_int &rh_lb ATTRIBUTE_UNUSED,
*************** pointer_and_operator::wi_fold (tree type
*** 2625,2646 ****
    // For pointer types, we are really only interested in asserting
    // whether the expression evaluates to non-NULL.
    if (wi_zero_p (type, lh_lb, lh_ub) || wi_zero_p (type, lh_lb, lh_ub))
!     return range_zero (type);
! 
!   return value_range (type);
  }
  
  
  class pointer_or_operator : public range_operator
  {
  public:
!   virtual value_range wi_fold (tree type,
! 			  const wide_int &lh_lb, const wide_int &lh_ub,
! 			  const wide_int &rh_lb, const wide_int &rh_ub) const;
  } op_pointer_or;
  
! value_range
! pointer_or_operator::wi_fold (tree type,
  			      const wide_int &lh_lb,
  			      const wide_int &lh_ub,
  			      const wide_int &rh_lb,
--- 2636,2657 ----
    // For pointer types, we are really only interested in asserting
    // whether the expression evaluates to non-NULL.
    if (wi_zero_p (type, lh_lb, lh_ub) || wi_zero_p (type, lh_lb, lh_ub))
!     r = range_zero (type);
!   else 
!     r = value_range (type);
  }
  
  
  class pointer_or_operator : public range_operator
  {
  public:
!   virtual void wi_fold (value_range &r, tree type,
! 			const wide_int &lh_lb, const wide_int &lh_ub,
! 			const wide_int &rh_lb, const wide_int &rh_ub) const;
  } op_pointer_or;
  
! void
! pointer_or_operator::wi_fold (value_range &r, tree type,
  			      const wide_int &lh_lb,
  			      const wide_int &lh_ub,
  			      const wide_int &rh_lb,
*************** pointer_or_operator::wi_fold (tree type,
*** 2650,2659 ****
    // whether the expression evaluates to non-NULL.
    if (!wi_includes_zero_p (type, lh_lb, lh_ub)
        && !wi_includes_zero_p (type, rh_lb, rh_ub))
!     return range_nonzero (type);
!   if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub))
!     return range_zero (type);
!   return value_range (type);
  }
  
  // This implements the range operator tables as local objects in this file.
--- 2661,2671 ----
    // whether the expression evaluates to non-NULL.
    if (!wi_includes_zero_p (type, lh_lb, lh_ub)
        && !wi_includes_zero_p (type, rh_lb, rh_ub))
!     r = range_nonzero (type);
!   else if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub))
!     r = range_zero (type);
!   else
!     r = value_range (type);
  }
  
  // This implements the range operator tables as local objects in this file.
*************** range_op_handler (enum tree_code code, t
*** 2782,2789 ****
  void
  range_cast (value_range &r, tree type)
  {
    range_operator *op = range_op_handler (CONVERT_EXPR, type);
!   r = op->fold_range (type, r, value_range (type));
  }
  
  #if CHECKING_P
--- 2794,2802 ----
  void
  range_cast (value_range &r, tree type)
  {
+   value_range tmp = r;
    range_operator *op = range_op_handler (CONVERT_EXPR, type);
!   op->fold_range (r, type, tmp, value_range (type));
  }
  
  #if CHECKING_P
Index: tree-vrp.c
===================================================================
*** tree-vrp.c	(revision 277853)
--- tree-vrp.c	(working copy)
*************** range_fold_binary_symbolics_p (value_ran
*** 1781,1789 ****
  	  return true;
  	}
        const range_operator *op = get_range_op_handler (vr, code, expr_type);
!       *vr = op->fold_range (expr_type,
! 			    vr0->normalize_symbolics (),
! 			    vr1->normalize_symbolics ());
        return true;
      }
    return false;
--- 1781,1788 ----
  	  return true;
  	}
        const range_operator *op = get_range_op_handler (vr, code, expr_type);
!       op->fold_range (*vr, expr_type, vr0->normalize_symbolics (),
! 		      vr1->normalize_symbolics ());
        return true;
      }
    return false;
*************** range_fold_unary_symbolics_p (value_rang
*** 1817,1825 ****
  	  return true;
  	}
        const range_operator *op = get_range_op_handler (vr, code, expr_type);
!       *vr = op->fold_range (expr_type,
! 			    vr0->normalize_symbolics (),
! 			    value_range (expr_type));
        return true;
      }
    return false;
--- 1816,1823 ----
  	  return true;
  	}
        const range_operator *op = get_range_op_handler (vr, code, expr_type);
!       op->fold_range (*vr, expr_type, vr0->normalize_symbolics (),
! 		      value_range (expr_type));
        return true;
      }
    return false;
*************** range_fold_binary_expr (value_range *vr,
*** 1846,1854 ****
    if (range_fold_binary_symbolics_p (vr, code, expr_type, &vr0, &vr1))
      return;
  
!   *vr = op->fold_range (expr_type,
! 			vr0.normalize_addresses (),
! 			vr1.normalize_addresses ());
  }
  
  /* Perform a unary operation on a range.  */
--- 1844,1851 ----
    if (range_fold_binary_symbolics_p (vr, code, expr_type, &vr0, &vr1))
      return;
  
!   op->fold_range (*vr, expr_type, vr0.normalize_addresses (),
! 		  vr1.normalize_addresses ());
  }
  
  /* Perform a unary operation on a range.  */
*************** range_fold_unary_expr (value_range *vr,
*** 1869,1877 ****
    if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0))
      return;
  
!   *vr = op->fold_range (expr_type,
! 			vr0->normalize_addresses (),
! 			value_range (expr_type));
  }
  
  /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V,
--- 1866,1873 ----
    if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0))
      return;
  
!   op->fold_range (*vr, expr_type, vr0->normalize_addresses (),
! 		  value_range (expr_type));
  }
  
  /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V,

Reply via email to