Index: tree-vrp.c
===================================================================
--- tree-vrp.c	(revision 189779)
+++ tree-vrp.c	(working copy)
@@ -2345,157 +2345,194 @@ extract_range_from_binary_expr_1 (value_
 	    set_value_range_to_varying (vr);
 	}
       else
 	set_value_range_to_varying (vr);
 
       return;
     }
 
   /* For integer ranges, apply the operation to each end of the
      range and see what we end up with.  */
-  if (code == PLUS_EXPR)
+  if (code == PLUS_EXPR || code == MINUS_EXPR)
     {
       /* If we have a PLUS_EXPR with two VR_RANGE integer constant
          ranges compute the precise range for such case if possible.  */
       if (range_int_cst_p (&vr0)
 	  && range_int_cst_p (&vr1)
-	  /* We attempt to do infinite precision signed integer arithmetic,
-	     thus we need two more bits than the possibly unsigned inputs.  */
-	  && TYPE_PRECISION (expr_type) < HOST_BITS_PER_DOUBLE_INT - 1)
+	  /* We need as many bits as the possibly unsigned inputs.  */
+	  && TYPE_PRECISION (expr_type) <= HOST_BITS_PER_DOUBLE_INT)
 	{
 	  double_int min0 = tree_to_double_int (vr0.min);
 	  double_int max0 = tree_to_double_int (vr0.max);
 	  double_int min1 = tree_to_double_int (vr1.min);
 	  double_int max1 = tree_to_double_int (vr1.max);
 	  bool uns = TYPE_UNSIGNED (expr_type);
 	  double_int type_min
 	    = double_int_min_value (TYPE_PRECISION (expr_type), uns);
 	  double_int type_max
 	    = double_int_max_value (TYPE_PRECISION (expr_type), uns);
 	  double_int dmin, dmax;
+	  int min_ovf = 0;
+	  int max_ovf = 0;
 
-	  dmin = double_int_add (min0, min1);
-	  dmax = double_int_add (max0, max1);
+	  if (code == PLUS_EXPR)
+	    {
+	      dmin = double_int_add (min0, min1);
+	      dmax = double_int_add (max0, max1);
+
+	      /* Check for overflow in double_int.  */
+	      if (double_int_cmp (min1, double_int_zero, uns)
+		  != double_int_cmp (dmin, min0, uns))
+		min_ovf = double_int_cmp (min0, dmin, uns);
+	      if (double_int_cmp (max1, double_int_zero, uns)
+		  != double_int_cmp (dmax, max0, uns))
+		max_ovf = double_int_cmp (max0, dmax, uns);
+	    }
+	  else /* if (code == MINUS_EXPR) */
+	    {
+	      dmin = double_int_sub (min0, max1);
+	      dmax = double_int_sub (max0, min1);
+
+	      if (double_int_cmp (double_int_zero, max1, uns)
+		  != double_int_cmp (dmin, min0, uns))
+		min_ovf = double_int_cmp (min0, max1, uns);
+	      if (double_int_cmp (double_int_zero, min1, uns)
+		  != double_int_cmp (dmax, max0, uns))
+		max_ovf = double_int_cmp (max0, min1, uns);
+	    }
+
+	  /* For non-wrapping arithmetic look at possibly smaller
+	     value-ranges of the type.  */
+	  if (!TYPE_OVERFLOW_WRAPS (expr_type))
+	    {
+	      if (vrp_val_min (expr_type))
+		type_min = tree_to_double_int (vrp_val_min (expr_type));
+	      if (vrp_val_max (expr_type))
+		type_max = tree_to_double_int (vrp_val_max (expr_type));
+	    }
+
+	  /* Check for type overflow.  */
+	  if (min_ovf == 0)
+	    {
+	      if (double_int_cmp (dmin, type_min, uns) == -1)
+		min_ovf = -1;
+	      else if (double_int_cmp (dmin, type_max, uns) == 1)
+		min_ovf = 1;
+	    }
+	  if (max_ovf == 0)
+	    {
+	      if (double_int_cmp (dmax, type_min, uns) == -1)
+		max_ovf = -1;
+	      else if (double_int_cmp (dmax, type_max, uns) == 1)
+		max_ovf = 1;
+	    }
 
 	  if (TYPE_OVERFLOW_WRAPS (expr_type))
 	    {
 	      /* If overflow wraps, truncate the values and adjust the
 		 range kind and bounds appropriately.  */
 	      double_int tmin
 		= double_int_ext (dmin, TYPE_PRECISION (expr_type), uns);
 	      double_int tmax
 		= double_int_ext (dmax, TYPE_PRECISION (expr_type), uns);
-	      gcc_assert (double_int_scmp (dmin, dmax) <= 0);
-	      if ((double_int_scmp (dmin, type_min) == -1
-		   && double_int_scmp (dmax, type_min) == -1)
-		  || (double_int_scmp (dmin, type_max) == 1
-		      && double_int_scmp (dmax, type_max) == 1)
-		  || (double_int_scmp (type_min, dmin) <= 0
-		      && double_int_scmp (dmax, type_max) <= 0))
+	      if (min_ovf == max_ovf)
 		{
 		  /* No overflow or both overflow or underflow.  The
 		     range kind stays VR_RANGE.  */
 		  min = double_int_to_tree (expr_type, tmin);
 		  max = double_int_to_tree (expr_type, tmax);
 		}
-	      else if (double_int_scmp (dmin, type_min) == -1
-		       && double_int_scmp (dmax, type_max) == 1)
+	      else if (min_ovf == -1
+		       && max_ovf == 1)
 		{
 		  /* Underflow and overflow, drop to VR_VARYING.  */
 		  set_value_range_to_varying (vr);
 		  return;
 		}
 	      else
 		{
 		  /* Min underflow or max overflow.  The range kind
 		     changes to VR_ANTI_RANGE.  */
 		  double_int tem = tmin;
-		  gcc_assert ((double_int_scmp (dmin, type_min) == -1
-			       && double_int_scmp (dmax, type_min) >= 0
-			       && double_int_scmp (dmax, type_max) <= 0)
-			      || (double_int_scmp (dmax, type_max) == 1
-				  && double_int_scmp (dmin, type_min) >= 0
-				  && double_int_scmp (dmin, type_max) <= 0));
+		  gcc_assert ((min_ovf == -1 && max_ovf == 0)
+			      || (max_ovf == 1 && min_ovf == 0));
 		  type = VR_ANTI_RANGE;
 		  tmin = double_int_add (tmax, double_int_one);
 		  tmax = double_int_add (tem, double_int_minus_one);
 		  /* If the anti-range would cover nothing, drop to varying.
 		     Likewise if the anti-range bounds are outside of the
 		     types values.  */
 		  if (double_int_cmp (tmin, tmax, uns) > 0
 		      || double_int_cmp (tmin, type_min, uns) < 0
 		      || double_int_cmp (tmax, type_max, uns) > 0)
 		    {
 		      set_value_range_to_varying (vr);
 		      return;
 		    }
 		  min = double_int_to_tree (expr_type, tmin);
 		  max = double_int_to_tree (expr_type, tmax);
 		}
 	    }
 	  else
 	    {
-	      /* For non-wrapping arithmetic look at possibly smaller
-		 value-ranges of the type.  */
-	      if (vrp_val_min (expr_type))
-		type_min = tree_to_double_int (vrp_val_min (expr_type));
-	      if (vrp_val_max (expr_type))
-		type_max = tree_to_double_int (vrp_val_max (expr_type));
-
 	      /* If overflow does not wrap, saturate to the types min/max
 	         value.  */
-	      if (double_int_scmp (dmin, type_min) == -1)
+	      if (min_ovf == -1)
 		{
 		  if (needs_overflow_infinity (expr_type)
 		      && supports_overflow_infinity (expr_type))
 		    min = negative_overflow_infinity (expr_type);
 		  else
 		    min = double_int_to_tree (expr_type, type_min);
 		}
-	      else if (double_int_scmp (dmin, type_max) == 1)
+	      else if (min_ovf == 1)
 		{
 		  if (needs_overflow_infinity (expr_type)
 		      && supports_overflow_infinity (expr_type))
 		    min = positive_overflow_infinity (expr_type);
 		  else
 		    min = double_int_to_tree (expr_type, type_max);
 		}
 	      else
 		min = double_int_to_tree (expr_type, dmin);
 
-	      if (double_int_scmp (dmax, type_min) == -1)
+	      if (max_ovf == -1)
 		{
 		  if (needs_overflow_infinity (expr_type)
 		      && supports_overflow_infinity (expr_type))
 		    max = negative_overflow_infinity (expr_type);
 		  else
 		    max = double_int_to_tree (expr_type, type_min);
 		}
-	      else if (double_int_scmp (dmax, type_max) == 1)
+	      else if (max_ovf == 1)
 		{
 		  if (needs_overflow_infinity (expr_type)
 		      && supports_overflow_infinity (expr_type))
 		    max = positive_overflow_infinity (expr_type);
 		  else
 		    max = double_int_to_tree (expr_type, type_max);
 		}
 	      else
 		max = double_int_to_tree (expr_type, dmax);
 	    }
 	  if (needs_overflow_infinity (expr_type)
 	      && supports_overflow_infinity (expr_type))
 	    {
 	      if (is_negative_overflow_infinity (vr0.min)
-		  || is_negative_overflow_infinity (vr1.min))
+		  || (code == PLUS_EXPR
+		      ? is_negative_overflow_infinity (vr1.min)
+		      : is_positive_overflow_infinity (vr1.max)))
 		min = negative_overflow_infinity (expr_type);
 	      if (is_positive_overflow_infinity (vr0.max)
-		  || is_positive_overflow_infinity (vr1.max))
+		  || (code == PLUS_EXPR
+		      ? is_positive_overflow_infinity (vr1.max)
+		      : is_negative_overflow_infinity (vr1.min)))
 		max = positive_overflow_infinity (expr_type);
 	    }
 	}
       else
 	{
 	  /* For other cases, for example if we have a PLUS_EXPR with two
 	     VR_ANTI_RANGEs, drop to VR_VARYING.  It would take more effort
 	     to compute a precise range for such a case.
 	     ???  General even mixed range kind operations can be expressed
 	     by for example transforming ~[3, 5] + [1, 2] to range-only
@@ -2710,40 +2747,20 @@ extract_range_from_binary_expr_1 (value_
 	max = vr1.max;
       max = int_const_binop (MINUS_EXPR, max, integer_one_node);
       /* If the dividend is non-negative the modulus will be
 	 non-negative as well.  */
       if (TYPE_UNSIGNED (expr_type)
 	  || value_range_nonnegative_p (&vr0))
 	min = build_int_cst (TREE_TYPE (max), 0);
       else
 	min = fold_unary_to_constant (NEGATE_EXPR, expr_type, max);
     }
-  else if (code == MINUS_EXPR)
-    {
-      /* If we have a MINUS_EXPR with two VR_ANTI_RANGEs, drop to
-	 VR_VARYING.  It would take more effort to compute a precise
-	 range for such a case.  For example, if we have op0 == 1 and
-	 op1 == 1 with their ranges both being ~[0,0], we would have
-	 op0 - op1 == 0, so we cannot claim that the difference is in
-	 ~[0,0].  Note that we are guaranteed to have
-	 vr0.type == vr1.type at this point.  */
-      if (vr0.type == VR_ANTI_RANGE)
-	{
-	  set_value_range_to_varying (vr);
-	  return;
-	}
-
-      /* For MINUS_EXPR, apply the operation to the opposite ends of
-	 each range.  */
-      min = vrp_int_const_binop (code, vr0.min, vr1.max);
-      max = vrp_int_const_binop (code, vr0.max, vr1.min);
-    }
   else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR)
     {
       bool int_cst_range0, int_cst_range1;
       double_int may_be_nonzero0, may_be_nonzero1;
       double_int must_be_nonzero0, must_be_nonzero1;
 
       int_cst_range0 = zero_nonzero_bits_from_vr (&vr0, &may_be_nonzero0,
 						  &must_be_nonzero0);
       int_cst_range1 = zero_nonzero_bits_from_vr (&vr1, &may_be_nonzero1,
 						  &must_be_nonzero1);
