OSDN Git Service

Backported from mainline
[pf3gnuchains/gcc-fork.git] / gcc / tree-vrp.c
index c975a5d..1bb1775 100644 (file)
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-propagate.h"
 #include "tree-chrec.h"
 #include "gimple-fold.h"
+#include "expr.h"
+#include "optabs.h"
 
 
 /* Type of value ranges.  See value_range_d for a description of these
@@ -138,7 +140,9 @@ static assert_locus_t *asserts_for;
 
 /* Value range array.  After propagation, VR_VALUE[I] holds the range
    of values that SSA name N_I may take.  */
+static unsigned num_vr_values;
 static value_range_t **vr_value;
+static bool values_propagated;
 
 /* For a PHI node which sets SSA name N_I, VR_COUNTS[I] holds the
    number of executable edges we saw the last time we visited the
@@ -658,6 +662,8 @@ abs_extent_range (value_range_t *vr, tree min, tree max)
 static value_range_t *
 get_value_range (const_tree var)
 {
+  static const struct value_range_d vr_const_varying
+    = { VR_VARYING, NULL_TREE, NULL_TREE, NULL };
   value_range_t *vr;
   tree sym;
   unsigned ver = SSA_NAME_VERSION (var);
@@ -666,30 +672,45 @@ get_value_range (const_tree var)
   if (! vr_value)
     return NULL;
 
+  /* If we query the range for a new SSA name return an unmodifiable VARYING.
+     We should get here at most from the substitute-and-fold stage which
+     will never try to change values.  */
+  if (ver >= num_vr_values)
+    return CONST_CAST (value_range_t *, &vr_const_varying);
+
   vr = vr_value[ver];
   if (vr)
     return vr;
 
+  /* After propagation finished do not allocate new value-ranges.  */
+  if (values_propagated)
+    return CONST_CAST (value_range_t *, &vr_const_varying);
+
   /* Create a default value range.  */
   vr_value[ver] = vr = XCNEW (value_range_t);
 
   /* Defer allocating the equivalence set.  */
   vr->equiv = NULL;
 
-  /* If VAR is a default definition, the variable can take any value
-     in VAR's type.  */
+  /* If VAR is a default definition of a parameter, the variable can
+     take any value in VAR's type.  */
   sym = SSA_NAME_VAR (var);
   if (SSA_NAME_IS_DEFAULT_DEF (var))
     {
-      /* Try to use the "nonnull" attribute to create ~[0, 0]
-        anti-ranges for pointers.  Note that this is only valid with
-        default definitions of PARM_DECLs.  */
-      if (TREE_CODE (sym) == PARM_DECL
-         && POINTER_TYPE_P (TREE_TYPE (sym))
-         && nonnull_arg_p (sym))
+      if (TREE_CODE (sym) == PARM_DECL)
+       {
+         /* Try to use the "nonnull" attribute to create ~[0, 0]
+            anti-ranges for pointers.  Note that this is only valid with
+            default definitions of PARM_DECLs.  */
+         if (POINTER_TYPE_P (TREE_TYPE (sym))
+             && nonnull_arg_p (sym))
+           set_value_range_to_nonnull (vr, TREE_TYPE (sym));
+         else
+           set_value_range_to_varying (vr);
+       }
+      else if (TREE_CODE (sym) == RESULT_DECL
+              && DECL_BY_REFERENCE (sym))
        set_value_range_to_nonnull (vr, TREE_TYPE (sym));
-      else
-       set_value_range_to_varying (vr);
     }
 
   return vr;
@@ -859,17 +880,6 @@ usable_range_p (value_range_t *vr, bool *strict_overflow_p)
 }
 
 
-/* Like tree_expr_nonnegative_warnv_p, but this function uses value
-   ranges obtained so far.  */
-
-static bool
-vrp_expr_computes_nonnegative (tree expr, bool *strict_overflow_p)
-{
-  return (tree_expr_nonnegative_warnv_p (expr, strict_overflow_p)
-         || (TREE_CODE (expr) == SSA_NAME
-             && ssa_name_nonnegative_p (expr)));
-}
-
 /* Return true if the result of assignment STMT is know to be non-negative.
    If the return value is based on the assumption that signed overflow is
    undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
@@ -1306,41 +1316,25 @@ compare_values (tree val1, tree val2)
 }
 
 
-/* Return 1 if VAL is inside value range VR (VR->MIN <= VAL <= VR->MAX),
-          0 if VAL is not inside VR,
+/* Return 1 if VAL is inside value range MIN <= VAL <= MAX,
+          0 if VAL is not inside [MIN, MAX],
         -2 if we cannot tell either way.
 
-   FIXME, the current semantics of this functions are a bit quirky
-         when taken in the context of VRP.  In here we do not care
-         about VR's type.  If VR is the anti-range ~[3, 5] the call
-         value_inside_range (4, VR) will return 1.
-
-         This is counter-intuitive in a strict sense, but the callers
-         currently expect this.  They are calling the function
-         merely to determine whether VR->MIN <= VAL <= VR->MAX.  The
-         callers are applying the VR_RANGE/VR_ANTI_RANGE semantics
-         themselves.
-
-         This also applies to value_ranges_intersect_p and
-         range_includes_zero_p.  The semantics of VR_RANGE and
-         VR_ANTI_RANGE should be encoded here, but that also means
-         adapting the users of these functions to the new semantics.
-
    Benchmark compile/20001226-1.c compilation time after changing this
    function.  */
 
 static inline int
-value_inside_range (tree val, value_range_t * vr)
+value_inside_range (tree val, tree min, tree max)
 {
   int cmp1, cmp2;
 
-  cmp1 = operand_less_p (val, vr->min);
+  cmp1 = operand_less_p (val, min);
   if (cmp1 == -2)
     return -2;
   if (cmp1 == 1)
     return 0;
 
-  cmp2 = operand_less_p (vr->max, val);
+  cmp2 = operand_less_p (max, val);
   if (cmp2 == -2)
     return -2;
 
@@ -1369,23 +1363,31 @@ value_ranges_intersect_p (value_range_t *vr0, value_range_t *vr1)
 }
 
 
-/* Return true if VR includes the value zero, false otherwise.  FIXME,
-   currently this will return false for an anti-range like ~[-4, 3].
-   This will be wrong when the semantics of value_inside_range are
-   modified (currently the users of this function expect these
-   semantics).  */
+/* Return 1 if [MIN, MAX] includes the value zero, 0 if it does not
+   include the value zero, -2 if we cannot tell.  */
 
-static inline bool
-range_includes_zero_p (value_range_t *vr)
+static inline int
+range_includes_zero_p (tree min, tree max)
 {
-  tree zero;
+  tree zero = build_int_cst (TREE_TYPE (min), 0);
+  return value_inside_range (zero, min, max);
+}
+
+/* Return true if *VR is know to only contain nonnegative values.  */
 
-  gcc_assert (vr->type != VR_UNDEFINED
-              && vr->type != VR_VARYING
-             && !symbolic_range_p (vr));
+static inline bool
+value_range_nonnegative_p (value_range_t *vr)
+{
+  /* Testing for VR_ANTI_RANGE is not useful here as any anti-range
+     which would return a useful value should be encoded as a 
+     VR_RANGE.  */
+  if (vr->type == VR_RANGE)
+    {
+      int result = compare_values (vr->min, integer_zero_node);
+      return (result == 0 || result == 1);
+    }
 
-  zero = build_int_cst (TREE_TYPE (vr->min), 0);
-  return (value_inside_range (zero, vr) == 1);
+  return false;
 }
 
 /* Return true if T, an SSA_NAME, is known to be nonnegative.  Return
@@ -1403,15 +1405,21 @@ ssa_name_nonnegative_p (const_tree t)
   if (!vr)
     return false;
 
-  /* Testing for VR_ANTI_RANGE is not useful here as any anti-range
-     which would return a useful value should be encoded as a VR_RANGE.  */
-  if (vr->type == VR_RANGE)
-    {
-      int result = compare_values (vr->min, integer_zero_node);
+  return value_range_nonnegative_p (vr);
+}
 
-      return (result == 0 || result == 1);
-    }
-  return false;
+/* If *VR has a value rante that is a single constant value return that,
+   otherwise return NULL_TREE.  */
+
+static tree
+value_range_constant_singleton (value_range_t *vr)
+{
+  if (vr->type == VR_RANGE
+      && operand_equal_p (vr->min, vr->max, 0)
+      && is_gimple_min_invariant (vr->min))
+    return vr->min;
+
+  return NULL_TREE;
 }
 
 /* If OP has a value range with a single constant value return that,
@@ -1421,23 +1429,37 @@ ssa_name_nonnegative_p (const_tree t)
 static tree
 op_with_constant_singleton_value_range (tree op)
 {
-  value_range_t *vr;
-
   if (is_gimple_min_invariant (op))
     return op;
 
   if (TREE_CODE (op) != SSA_NAME)
     return NULL_TREE;
 
-  vr = get_value_range (op);
-  if (vr->type == VR_RANGE
-      && operand_equal_p (vr->min, vr->max, 0)
-      && is_gimple_min_invariant (vr->min))
-    return vr->min;
-
-  return NULL_TREE;
+  return value_range_constant_singleton (get_value_range (op));
 }
 
+/* Return true if op is in a boolean [0, 1] value-range.  */
+
+static bool
+op_with_boolean_value_range_p (tree op)
+{
+  value_range_t *vr;
+
+  if (TYPE_PRECISION (TREE_TYPE (op)) == 1)
+    return true;
+
+  if (integer_zerop (op)
+      || integer_onep (op))
+    return true;
+
+  if (TREE_CODE (op) != SSA_NAME)
+    return false;
+
+  vr = get_value_range (op);
+  return (vr->type == VR_RANGE
+         && integer_zerop (vr->min)
+         && integer_onep (vr->max));
+}
 
 /* Extract value range information from an ASSERT_EXPR EXPR and store
    it in *VR_P.  */
@@ -1477,7 +1499,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
 
   limit = avoid_overflow_infinity (limit);
 
-  type = TREE_TYPE (limit);
+  type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
   /* For pointer arithmetic, we only keep track of pointer equality
@@ -1651,8 +1673,13 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
          /* For LT_EXPR, we create the range [MIN, MAX - 1].  */
          if (cond_code == LT_EXPR)
            {
-             tree one = build_int_cst (type, 1);
-             max = fold_build2 (MINUS_EXPR, type, max, one);
+             if (TYPE_PRECISION (TREE_TYPE (max)) == 1
+                 && !TYPE_UNSIGNED (TREE_TYPE (max)))
+               max = fold_build2 (PLUS_EXPR, TREE_TYPE (max), max,
+                                  build_int_cst (TREE_TYPE (max), -1));
+             else
+               max = fold_build2 (MINUS_EXPR, TREE_TYPE (max), max,
+                                  build_int_cst (TREE_TYPE (max), 1));
              if (EXPR_P (max))
                TREE_NO_WARNING (max) = 1;
            }
@@ -1686,8 +1713,13 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
          /* For GT_EXPR, we create the range [MIN + 1, MAX].  */
          if (cond_code == GT_EXPR)
            {
-             tree one = build_int_cst (type, 1);
-             min = fold_build2 (PLUS_EXPR, type, min, one);
+             if (TYPE_PRECISION (TREE_TYPE (min)) == 1
+                 && !TYPE_UNSIGNED (TREE_TYPE (min)))
+               min = fold_build2 (MINUS_EXPR, TREE_TYPE (min), min,
+                                  build_int_cst (TREE_TYPE (min), -1));
+             else
+               min = fold_build2 (PLUS_EXPR, TREE_TYPE (min), min,
+                                  build_int_cst (TREE_TYPE (min), 1));
              if (EXPR_P (min))
                TREE_NO_WARNING (min) = 1;
            }
@@ -1873,12 +1905,21 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
                  min = positive_overflow_infinity (TREE_TYPE (var_vr->min));
                }
              else if (!POINTER_TYPE_P (TREE_TYPE (var_vr->min)))
-               min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
-                                  anti_max,
-                                  build_int_cst (TREE_TYPE (var_vr->min), 1));
+               {
+                 if (TYPE_PRECISION (TREE_TYPE (var_vr->min)) == 1
+                     && !TYPE_UNSIGNED (TREE_TYPE (var_vr->min)))
+                   min = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+                                      anti_max,
+                                      build_int_cst (TREE_TYPE (var_vr->min),
+                                                     -1));
+                 else
+                   min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+                                      anti_max,
+                                      build_int_cst (TREE_TYPE (var_vr->min),
+                                                     1));
+               }
              else
-               min = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (var_vr->min),
-                                  anti_max, size_int (1));
+               min = fold_build_pointer_plus_hwi (anti_max, 1);
              max = real_max;
              set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
            }
@@ -1901,13 +1942,21 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
                  max = negative_overflow_infinity (TREE_TYPE (var_vr->min));
                }
              else if (!POINTER_TYPE_P (TREE_TYPE (var_vr->min)))
-               max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
-                                  anti_min,
-                                  build_int_cst (TREE_TYPE (var_vr->min), 1));
+               {
+                 if (TYPE_PRECISION (TREE_TYPE (var_vr->min)) == 1
+                     && !TYPE_UNSIGNED (TREE_TYPE (var_vr->min)))
+                   max = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+                                      anti_min,
+                                      build_int_cst (TREE_TYPE (var_vr->min),
+                                                     -1));
+                 else
+                   max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+                                      anti_min,
+                                      build_int_cst (TREE_TYPE (var_vr->min),
+                                                     1));
+               }
              else
-               max = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (var_vr->min),
-                                  anti_min,
-                                  size_int (-1));
+               max = fold_build_pointer_plus_hwi (anti_min, -1);
              min = real_min;
              set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
            }
@@ -2097,66 +2146,224 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
    the bit is 1, otherwise it might be 0 or 1.  */
 
 static bool
-zero_nonzero_bits_from_vr (value_range_t *vr, double_int *may_be_nonzero,
+zero_nonzero_bits_from_vr (value_range_t *vr,
+                          double_int *may_be_nonzero,
                           double_int *must_be_nonzero)
 {
-  if (range_int_cst_p (vr))
+  *may_be_nonzero = double_int_minus_one;
+  *must_be_nonzero = double_int_zero;
+  if (!range_int_cst_p (vr))
+    return false;
+
+  if (range_int_cst_singleton_p (vr))
+    {
+      *may_be_nonzero = tree_to_double_int (vr->min);
+      *must_be_nonzero = *may_be_nonzero;
+    }
+  else if (tree_int_cst_sgn (vr->min) >= 0
+          || tree_int_cst_sgn (vr->max) < 0)
     {
-      if (range_int_cst_singleton_p (vr))
+      double_int dmin = tree_to_double_int (vr->min);
+      double_int dmax = tree_to_double_int (vr->max);
+      double_int xor_mask = double_int_xor (dmin, dmax);
+      *may_be_nonzero = double_int_ior (dmin, dmax);
+      *must_be_nonzero = double_int_and (dmin, dmax);
+      if (xor_mask.high != 0)
        {
-         *may_be_nonzero = tree_to_double_int (vr->min);
-         *must_be_nonzero = *may_be_nonzero;
-         return true;
+         unsigned HOST_WIDE_INT mask
+             = ((unsigned HOST_WIDE_INT) 1
+                << floor_log2 (xor_mask.high)) - 1;
+         may_be_nonzero->low = ALL_ONES;
+         may_be_nonzero->high |= mask;
+         must_be_nonzero->low = 0;
+         must_be_nonzero->high &= ~mask;
        }
-      if (tree_int_cst_sgn (vr->min) >= 0)
+      else if (xor_mask.low != 0)
        {
-         double_int dmin = tree_to_double_int (vr->min);
-         double_int dmax = tree_to_double_int (vr->max);
-         double_int xor_mask = double_int_xor (dmin, dmax);
-         *may_be_nonzero = double_int_ior (dmin, dmax);
-         *must_be_nonzero = double_int_and (dmin, dmax);
-         if (xor_mask.high != 0)
-           {
-             unsigned HOST_WIDE_INT mask
-               = ((unsigned HOST_WIDE_INT) 1
-                  << floor_log2 (xor_mask.high)) - 1;
-             may_be_nonzero->low = ALL_ONES;
-             may_be_nonzero->high |= mask;
-             must_be_nonzero->low = 0;
-             must_be_nonzero->high &= ~mask;
-           }
-         else if (xor_mask.low != 0)
+         unsigned HOST_WIDE_INT mask
+             = ((unsigned HOST_WIDE_INT) 1
+                << floor_log2 (xor_mask.low)) - 1;
+         may_be_nonzero->low |= mask;
+         must_be_nonzero->low &= ~mask;
+       }
+    }
+
+  return true;
+}
+
+/* Helper to extract a value-range *VR for a multiplicative operation
+   *VR0 CODE *VR1.  */
+
+static void
+extract_range_from_multiplicative_op_1 (value_range_t *vr,
+                                       enum tree_code code,
+                                       value_range_t *vr0, value_range_t *vr1)
+{
+  enum value_range_type type;
+  tree val[4];
+  size_t i;
+  tree min, max;
+  bool sop;
+  int cmp;
+
+  /* Multiplications, divisions and shifts are a bit tricky to handle,
+     depending on the mix of signs we have in the two ranges, we
+     need to operate on different values to get the minimum and
+     maximum values for the new range.  One approach is to figure
+     out all the variations of range combinations and do the
+     operations.
+
+     However, this involves several calls to compare_values and it
+     is pretty convoluted.  It's simpler to do the 4 operations
+     (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
+     MAX1) and then figure the smallest and largest values to form
+     the new range.  */
+  gcc_assert (code == MULT_EXPR
+             || code == TRUNC_DIV_EXPR
+             || code == FLOOR_DIV_EXPR
+             || code == CEIL_DIV_EXPR
+             || code == EXACT_DIV_EXPR
+             || code == ROUND_DIV_EXPR
+             || code == RSHIFT_EXPR);
+  gcc_assert ((vr0->type == VR_RANGE
+              || (code == MULT_EXPR && vr0->type == VR_ANTI_RANGE))
+             && vr0->type == vr1->type);
+
+  type = vr0->type;
+
+  /* Compute the 4 cross operations.  */
+  sop = false;
+  val[0] = vrp_int_const_binop (code, vr0->min, vr1->min);
+  if (val[0] == NULL_TREE)
+    sop = true;
+
+  if (vr1->max == vr1->min)
+    val[1] = NULL_TREE;
+  else
+    {
+      val[1] = vrp_int_const_binop (code, vr0->min, vr1->max);
+      if (val[1] == NULL_TREE)
+       sop = true;
+    }
+
+  if (vr0->max == vr0->min)
+    val[2] = NULL_TREE;
+  else
+    {
+      val[2] = vrp_int_const_binop (code, vr0->max, vr1->min);
+      if (val[2] == NULL_TREE)
+       sop = true;
+    }
+
+  if (vr0->min == vr0->max || vr1->min == vr1->max)
+    val[3] = NULL_TREE;
+  else
+    {
+      val[3] = vrp_int_const_binop (code, vr0->max, vr1->max);
+      if (val[3] == NULL_TREE)
+       sop = true;
+    }
+
+  if (sop)
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+
+  /* Set MIN to the minimum of VAL[i] and MAX to the maximum
+     of VAL[i].  */
+  min = val[0];
+  max = val[0];
+  for (i = 1; i < 4; i++)
+    {
+      if (!is_gimple_min_invariant (min)
+         || (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
+         || !is_gimple_min_invariant (max)
+         || (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
+       break;
+
+      if (val[i])
+       {
+         if (!is_gimple_min_invariant (val[i])
+             || (TREE_OVERFLOW (val[i])
+                 && !is_overflow_infinity (val[i])))
            {
-             unsigned HOST_WIDE_INT mask
-               = ((unsigned HOST_WIDE_INT) 1
-                  << floor_log2 (xor_mask.low)) - 1;
-             may_be_nonzero->low |= mask;
-             must_be_nonzero->low &= ~mask;
+             /* If we found an overflowed value, set MIN and MAX
+                to it so that we set the resulting range to
+                VARYING.  */
+             min = max = val[i];
+             break;
            }
-         return true;
+
+         if (compare_values (val[i], min) == -1)
+           min = val[i];
+
+         if (compare_values (val[i], max) == 1)
+           max = val[i];
        }
     }
-  may_be_nonzero->low = ALL_ONES;
-  may_be_nonzero->high = ALL_ONES;
-  must_be_nonzero->low = 0;
-  must_be_nonzero->high = 0;
-  return false;
-}
 
+  /* If either MIN or MAX overflowed, then set the resulting range to
+     VARYING.  But we do accept an overflow infinity
+     representation.  */
+  if (min == NULL_TREE
+      || !is_gimple_min_invariant (min)
+      || (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
+      || max == NULL_TREE
+      || !is_gimple_min_invariant (max)
+      || (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+
+  /* We punt if:
+     1) [-INF, +INF]
+     2) [-INF, +-INF(OVF)]
+     3) [+-INF(OVF), +INF]
+     4) [+-INF(OVF), +-INF(OVF)]
+     We learn nothing when we have INF and INF(OVF) on both sides.
+     Note that we do accept [-INF, -INF] and [+INF, +INF] without
+     overflow.  */
+  if ((vrp_val_is_min (min) || is_overflow_infinity (min))
+      && (vrp_val_is_max (max) || is_overflow_infinity (max)))
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
 
-/* Extract range information from a binary expression EXPR based on
-   the ranges of each of its operands and the expression code.  */
+  cmp = compare_values (min, max);
+  if (cmp == -2 || cmp == 1)
+    {
+      /* If the new range has its limits swapped around (MIN > MAX),
+        then the operation caused one of them to wrap around, mark
+        the new range VARYING.  */
+      set_value_range_to_varying (vr);
+    }
+  else
+    set_value_range (vr, type, min, max, NULL);
+}
+
+/* Extract range information from a binary operation CODE based on
+   the ranges of each of its operands, *VR0 and *VR1 with resulting
+   type EXPR_TYPE.  The resulting range is stored in *VR.  */
 
 static void
-extract_range_from_binary_expr (value_range_t *vr,
-                               enum tree_code code,
-                               tree expr_type, tree op0, tree op1)
+extract_range_from_binary_expr_1 (value_range_t *vr,
+                                 enum tree_code code, tree expr_type,
+                                 value_range_t *vr0_, value_range_t *vr1_)
 {
+  value_range_t vr0 = *vr0_, vr1 = *vr1_;
   enum value_range_type type;
-  tree min, max;
+  tree min = NULL_TREE, max = NULL_TREE;
   int cmp;
-  value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
-  value_range_t vr1 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+
+  if (!INTEGRAL_TYPE_P (expr_type)
+      && !POINTER_TYPE_P (expr_type))
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
 
   /* Not all binary expressions can be applied to ranges in a
      meaningful way.  Handle only arithmetic operations.  */
@@ -2175,51 +2382,26 @@ extract_range_from_binary_expr (value_range_t *vr,
       && code != MAX_EXPR
       && code != BIT_AND_EXPR
       && code != BIT_IOR_EXPR
-      && code != TRUTH_AND_EXPR
-      && code != TRUTH_OR_EXPR)
-    {
-      /* We can still do constant propagation here.  */
-      tree const_op0 = op_with_constant_singleton_value_range (op0);
-      tree const_op1 = op_with_constant_singleton_value_range (op1);
-      if (const_op0 || const_op1)
-       {
-         tree tem = fold_binary (code, expr_type,
-                                 const_op0 ? const_op0 : op0,
-                                 const_op1 ? const_op1 : op1);
-         if (tem
-             && is_gimple_min_invariant (tem)
-             && !is_overflow_infinity (tem))
-           {
-             set_value_range (vr, VR_RANGE, tem, tem, NULL);
-             return;
-           }
-       }
+      && code != BIT_XOR_EXPR)
+    {
       set_value_range_to_varying (vr);
       return;
     }
 
-  /* Get value ranges for each operand.  For constant operands, create
-     a new value range with the operand to simplify processing.  */
-  if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *(get_value_range (op0));
-  else if (is_gimple_min_invariant (op0))
-    set_value_range_to_value (&vr0, op0, NULL);
-  else
-    set_value_range_to_varying (&vr0);
-
-  if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *(get_value_range (op1));
-  else if (is_gimple_min_invariant (op1))
-    set_value_range_to_value (&vr1, op1, NULL);
-  else
-    set_value_range_to_varying (&vr1);
-
-  /* If either range is UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED || vr1.type == VR_UNDEFINED)
+  /* If both ranges are UNDEFINED, so is the result.  */
+  if (vr0.type == VR_UNDEFINED && vr1.type == VR_UNDEFINED)
     {
       set_value_range_to_undefined (vr);
       return;
     }
+  /* If one of the ranges is UNDEFINED drop it to VARYING for the following
+     code.  At some point we may want to special-case operations that
+     have UNDEFINED result for all or some value-ranges of the not UNDEFINED
+     operand.  */
+  else if (vr0.type == VR_UNDEFINED)
+    set_value_range_to_varying (&vr0);
+  else if (vr1.type == VR_UNDEFINED)
+    set_value_range_to_varying (&vr1);
 
   /* The type of the resulting value range defaults to VR0.TYPE.  */
   type = vr0.type;
@@ -2231,8 +2413,7 @@ extract_range_from_binary_expr (value_range_t *vr,
      divisions.  TODO, we may be able to derive anti-ranges in
      some cases.  */
   if (code != BIT_AND_EXPR
-      && code != TRUTH_AND_EXPR
-      && code != TRUTH_OR_EXPR
+      && code != BIT_IOR_EXPR
       && code != TRUNC_DIV_EXPR
       && code != FLOOR_DIV_EXPR
       && code != CEIL_DIV_EXPR
@@ -2250,9 +2431,7 @@ extract_range_from_binary_expr (value_range_t *vr,
     }
 
   /* Now evaluate the expression to determine the new range.  */
-  if (POINTER_TYPE_P (expr_type)
-      || POINTER_TYPE_P (TREE_TYPE (op0))
-      || POINTER_TYPE_P (TREE_TYPE (op1)))
+  if (POINTER_TYPE_P (expr_type))
     {
       if (code == MIN_EXPR || code == MAX_EXPR)
        {
@@ -2266,10 +2445,8 @@ extract_range_from_binary_expr (value_range_t *vr,
            set_value_range_to_null (vr, expr_type);
          else
            set_value_range_to_varying (vr);
-
-         return;
        }
-      if (code == POINTER_PLUS_EXPR)
+      else if (code == POINTER_PLUS_EXPR)
        {
          /* For pointer types, we are really only interested in asserting
             whether the expression evaluates to non-NULL.  */
@@ -2292,64 +2469,14 @@ extract_range_from_binary_expr (value_range_t *vr,
            set_value_range_to_varying (vr);
        }
       else
-       gcc_unreachable ();
+       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 == TRUTH_AND_EXPR
-      || code == TRUTH_OR_EXPR)
-    {
-      /* If one of the operands is zero, we know that the whole
-        expression evaluates zero.  */
-      if (code == TRUTH_AND_EXPR
-         && ((vr0.type == VR_RANGE
-              && integer_zerop (vr0.min)
-              && integer_zerop (vr0.max))
-             || (vr1.type == VR_RANGE
-                 && integer_zerop (vr1.min)
-                 && integer_zerop (vr1.max))))
-       {
-         type = VR_RANGE;
-         min = max = build_int_cst (expr_type, 0);
-       }
-      /* If one of the operands is one, we know that the whole
-        expression evaluates one.  */
-      else if (code == TRUTH_OR_EXPR
-              && ((vr0.type == VR_RANGE
-                   && integer_onep (vr0.min)
-                   && integer_onep (vr0.max))
-                  || (vr1.type == VR_RANGE
-                      && integer_onep (vr1.min)
-                      && integer_onep (vr1.max))))
-       {
-         type = VR_RANGE;
-         min = max = build_int_cst (expr_type, 1);
-       }
-      else if (vr0.type != VR_VARYING
-              && vr1.type != VR_VARYING
-              && vr0.type == vr1.type
-              && !symbolic_range_p (&vr0)
-              && !overflow_infinity_range_p (&vr0)
-              && !symbolic_range_p (&vr1)
-              && !overflow_infinity_range_p (&vr1))
-       {
-         /* Boolean expressions cannot be folded with int_const_binop.  */
-         min = fold_binary (code, expr_type, vr0.min, vr1.min);
-         max = fold_binary (code, expr_type, vr0.max, vr1.max);
-       }
-      else
-       {
-         /* The result of a TRUTH_*_EXPR is always true or false.  */
-         set_value_range_to_truthvalue (vr, expr_type);
-         return;
-       }
-    }
-  else if (code == PLUS_EXPR
-          || code == MIN_EXPR
-          || code == MAX_EXPR)
+  if (code == PLUS_EXPR)
     {
       /* If we have a PLUS_EXPR with two VR_ANTI_RANGEs, drop to
         VR_VARYING.  It would take more effort to compute a precise
@@ -2360,32 +2487,21 @@ extract_range_from_binary_expr (value_range_t *vr,
         this point.  */
       if (vr0.type == VR_ANTI_RANGE)
        {
-         if (code == PLUS_EXPR)
-           {
-             set_value_range_to_varying (vr);
-             return;
-           }
-         /* For MIN_EXPR and MAX_EXPR with two VR_ANTI_RANGEs,
-            the resulting VR_ANTI_RANGE is the same - intersection
-            of the two ranges.  */
-         min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
-         max = vrp_int_const_binop (MIN_EXPR, vr0.max, vr1.max);
-       }
-      else
-       {
-         /* For operations that make the resulting range directly
-            proportional to the original ranges, apply the operation to
-            the same end of each range.  */
-         min = vrp_int_const_binop (code, vr0.min, vr1.min);
-         max = vrp_int_const_binop (code, vr0.max, vr1.max);
+         set_value_range_to_varying (vr);
+         return;
        }
 
+      /* For operations that make the resulting range directly
+        proportional to the original ranges, apply the operation to
+        the same end of each range.  */
+      min = vrp_int_const_binop (code, vr0.min, vr1.min);
+      max = vrp_int_const_binop (code, vr0.max, vr1.max);
+
       /* If both additions overflowed the range kind is still correct.
         This happens regularly with subtracting something in unsigned
         arithmetic.
          ???  See PR30318 for all the cases we do not handle.  */
-      if (code == PLUS_EXPR
-         && (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
+      if ((TREE_OVERFLOW (min) && !is_overflow_infinity (min))
          && (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
        {
          min = build_int_cst_wide (TREE_TYPE (min),
@@ -2396,18 +2512,28 @@ extract_range_from_binary_expr (value_range_t *vr,
                                    TREE_INT_CST_HIGH (max));
        }
     }
-  else if (code == MULT_EXPR
-          || code == TRUNC_DIV_EXPR
-          || code == FLOOR_DIV_EXPR
-          || code == CEIL_DIV_EXPR
-          || code == EXACT_DIV_EXPR
-          || code == ROUND_DIV_EXPR
-          || code == RSHIFT_EXPR)
+  else if (code == MIN_EXPR
+          || code == MAX_EXPR)
+    {
+      if (vr0.type == VR_ANTI_RANGE)
+       {
+         /* For MIN_EXPR and MAX_EXPR with two VR_ANTI_RANGEs,
+            the resulting VR_ANTI_RANGE is the same - intersection
+            of the two ranges.  */
+         min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
+         max = vrp_int_const_binop (MIN_EXPR, vr0.max, vr1.max);
+       }
+      else
+       {
+         /* For operations that make the resulting range directly
+            proportional to the original ranges, apply the operation to
+            the same end of each range.  */
+         min = vrp_int_const_binop (code, vr0.min, vr1.min);
+         max = vrp_int_const_binop (code, vr0.max, vr1.max);
+       }
+    }
+  else if (code == MULT_EXPR)
     {
-      tree val[4];
-      size_t i;
-      bool sop;
-
       /* If we have an unsigned MULT_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
@@ -2416,50 +2542,53 @@ extract_range_from_binary_expr (value_range_t *vr,
         we cannot claim that the product is in ~[0,0].  Note that we
         are guaranteed to have vr0.type == vr1.type at this
         point.  */
-      if (code == MULT_EXPR
-         && vr0.type == VR_ANTI_RANGE
-         && !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0)))
+      if (vr0.type == VR_ANTI_RANGE
+         && !TYPE_OVERFLOW_UNDEFINED (expr_type))
        {
          set_value_range_to_varying (vr);
          return;
        }
 
+      extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+      return;
+    }
+  else if (code == RSHIFT_EXPR)
+    {
       /* If we have a RSHIFT_EXPR with any shift values outside [0..prec-1],
         then drop to VR_VARYING.  Outside of this range we get undefined
         behavior from the shift operation.  We cannot even trust
         SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl
         shifts, and the operation at the tree level may be widened.  */
-      if (code == RSHIFT_EXPR)
-       {
-         if (vr1.type == VR_ANTI_RANGE
-             || !vrp_expr_computes_nonnegative (op1, &sop)
-             || (operand_less_p
-                 (build_int_cst (TREE_TYPE (vr1.max),
-                                 TYPE_PRECISION (expr_type) - 1),
-                  vr1.max) != 0))
-           {
-             set_value_range_to_varying (vr);
-             return;
-           }
+      if (vr1.type != VR_RANGE
+         || !value_range_nonnegative_p (&vr1)
+         || TREE_CODE (vr1.max) != INTEGER_CST
+         || compare_tree_int (vr1.max, TYPE_PRECISION (expr_type) - 1) == 1)
+       {
+         set_value_range_to_varying (vr);
+         return;
        }
 
-      else if ((code == TRUNC_DIV_EXPR
-               || code == FLOOR_DIV_EXPR
-               || code == CEIL_DIV_EXPR
-               || code == EXACT_DIV_EXPR
-               || code == ROUND_DIV_EXPR)
-              && (vr0.type != VR_RANGE || symbolic_range_p (&vr0)))
+      extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+      return;
+    }
+  else if (code == TRUNC_DIV_EXPR
+          || code == FLOOR_DIV_EXPR
+          || code == CEIL_DIV_EXPR
+          || code == EXACT_DIV_EXPR
+          || code == ROUND_DIV_EXPR)
+    {
+      if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
        {
          /* For division, if op1 has VR_RANGE but op0 does not, something
             can be deduced just from that range.  Say [min, max] / [4, max]
             gives [min / 4, max / 4] range.  */
          if (vr1.type == VR_RANGE
              && !symbolic_range_p (&vr1)
-             && !range_includes_zero_p (&vr1))
+             && range_includes_zero_p (vr1.min, vr1.max) == 0)
            {
              vr0.type = type = VR_RANGE;
-             vr0.min = vrp_val_min (TREE_TYPE (op0));
-             vr0.max = vrp_val_max (TREE_TYPE (op1));
+             vr0.min = vrp_val_min (expr_type);
+             vr0.max = vrp_val_max (expr_type);
            }
          else
            {
@@ -2470,15 +2599,9 @@ extract_range_from_binary_expr (value_range_t *vr,
 
       /* For divisions, if flag_non_call_exceptions is true, we must
         not eliminate a division by zero.  */
-      if ((code == TRUNC_DIV_EXPR
-          || code == FLOOR_DIV_EXPR
-          || code == CEIL_DIV_EXPR
-          || code == EXACT_DIV_EXPR
-          || code == ROUND_DIV_EXPR)
-         && cfun->can_throw_non_call_exceptions
+      if (cfun->can_throw_non_call_exceptions
          && (vr1.type != VR_RANGE
-             || symbolic_range_p (&vr1)
-             || range_includes_zero_p (&vr1)))
+             || range_includes_zero_p (vr1.min, vr1.max) != 0))
        {
          set_value_range_to_varying (vr);
          return;
@@ -2487,23 +2610,17 @@ extract_range_from_binary_expr (value_range_t *vr,
       /* For divisions, if op0 is VR_RANGE, we can deduce a range
         even if op1 is VR_VARYING, VR_ANTI_RANGE, symbolic or can
         include 0.  */
-      if ((code == TRUNC_DIV_EXPR
-          || code == FLOOR_DIV_EXPR
-          || code == CEIL_DIV_EXPR
-          || code == EXACT_DIV_EXPR
-          || code == ROUND_DIV_EXPR)
-         && vr0.type == VR_RANGE
+      if (vr0.type == VR_RANGE
          && (vr1.type != VR_RANGE
-             || symbolic_range_p (&vr1)
-             || range_includes_zero_p (&vr1)))
+             || range_includes_zero_p (vr1.min, vr1.max) != 0))
        {
          tree zero = build_int_cst (TREE_TYPE (vr0.min), 0);
          int cmp;
 
-         sop = false;
          min = NULL_TREE;
          max = NULL_TREE;
-         if (vrp_expr_computes_nonnegative (op1, &sop) && !sop)
+         if (TYPE_UNSIGNED (expr_type)
+             || value_range_nonnegative_p (&vr1))
            {
              /* For unsigned division or when divisor is known
                 to be non-negative, the range has to cover
@@ -2538,104 +2655,16 @@ extract_range_from_binary_expr (value_range_t *vr,
              return;
            }
        }
-
-      /* Multiplications and divisions are a bit tricky to handle,
-        depending on the mix of signs we have in the two ranges, we
-        need to operate on different values to get the minimum and
-        maximum values for the new range.  One approach is to figure
-        out all the variations of range combinations and do the
-        operations.
-
-        However, this involves several calls to compare_values and it
-        is pretty convoluted.  It's simpler to do the 4 operations
-        (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
-        MAX1) and then figure the smallest and largest values to form
-        the new range.  */
       else
        {
-         gcc_assert ((vr0.type == VR_RANGE
-                      || (code == MULT_EXPR && vr0.type == VR_ANTI_RANGE))
-                     && vr0.type == vr1.type);
-
-         /* Compute the 4 cross operations.  */
-         sop = false;
-         val[0] = vrp_int_const_binop (code, vr0.min, vr1.min);
-         if (val[0] == NULL_TREE)
-           sop = true;
-
-         if (vr1.max == vr1.min)
-           val[1] = NULL_TREE;
-         else
-           {
-             val[1] = vrp_int_const_binop (code, vr0.min, vr1.max);
-             if (val[1] == NULL_TREE)
-               sop = true;
-           }
-
-         if (vr0.max == vr0.min)
-           val[2] = NULL_TREE;
-         else
-           {
-             val[2] = vrp_int_const_binop (code, vr0.max, vr1.min);
-             if (val[2] == NULL_TREE)
-               sop = true;
-           }
-
-         if (vr0.min == vr0.max || vr1.min == vr1.max)
-           val[3] = NULL_TREE;
-         else
-           {
-             val[3] = vrp_int_const_binop (code, vr0.max, vr1.max);
-             if (val[3] == NULL_TREE)
-               sop = true;
-           }
-
-         if (sop)
-           {
-             set_value_range_to_varying (vr);
-             return;
-           }
-
-         /* Set MIN to the minimum of VAL[i] and MAX to the maximum
-            of VAL[i].  */
-         min = val[0];
-         max = val[0];
-         for (i = 1; i < 4; i++)
-           {
-             if (!is_gimple_min_invariant (min)
-                 || (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
-                 || !is_gimple_min_invariant (max)
-                 || (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
-               break;
-
-             if (val[i])
-               {
-                 if (!is_gimple_min_invariant (val[i])
-                     || (TREE_OVERFLOW (val[i])
-                         && !is_overflow_infinity (val[i])))
-                   {
-                     /* If we found an overflowed value, set MIN and MAX
-                        to it so that we set the resulting range to
-                        VARYING.  */
-                     min = max = val[i];
-                     break;
-                   }
-
-                 if (compare_values (val[i], min) == -1)
-                   min = val[i];
-
-                 if (compare_values (val[i], max) == 1)
-                   max = val[i];
-               }
-           }
+         extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+         return;
        }
     }
   else if (code == TRUNC_MOD_EXPR)
     {
-      bool sop = false;
       if (vr1.type != VR_RANGE
-         || symbolic_range_p (&vr1)
-         || range_includes_zero_p (&vr1)
+         || range_includes_zero_p (vr1.min, vr1.max) != 0
          || vrp_val_is_min (vr1.min))
        {
          set_value_range_to_varying (vr);
@@ -2643,17 +2672,17 @@ extract_range_from_binary_expr (value_range_t *vr,
        }
       type = VR_RANGE;
       /* Compute MAX <|vr1.min|, |vr1.max|> - 1.  */
-      max = fold_unary_to_constant (ABS_EXPR, TREE_TYPE (vr1.min), vr1.min);
+      max = fold_unary_to_constant (ABS_EXPR, expr_type, vr1.min);
       if (tree_int_cst_lt (max, vr1.max))
        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 (TREE_TYPE (max))
-         || (vrp_expr_computes_nonnegative (op0, &sop) && !sop))
+      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, TREE_TYPE (max), max);
+       min = fold_unary_to_constant (NEGATE_EXPR, expr_type, max);
     }
   else if (code == MINUS_EXPR)
     {
@@ -2675,78 +2704,104 @@ extract_range_from_binary_expr (value_range_t *vr,
       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)
+  else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR)
     {
-      bool vr0_int_cst_singleton_p, vr1_int_cst_singleton_p;
       bool int_cst_range0, int_cst_range1;
       double_int may_be_nonzero0, may_be_nonzero1;
       double_int must_be_nonzero0, must_be_nonzero1;
 
-      vr0_int_cst_singleton_p = range_int_cst_singleton_p (&vr0);
-      vr1_int_cst_singleton_p = range_int_cst_singleton_p (&vr1);
       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);
 
       type = VR_RANGE;
-      if (vr0_int_cst_singleton_p && vr1_int_cst_singleton_p)
-       min = max = int_const_binop (code, vr0.max, vr1.max);
-      else if (!int_cst_range0 && !int_cst_range1)
-       {
-         set_value_range_to_varying (vr);
-         return;
-       }
-      else if (code == BIT_AND_EXPR)
+      if (code == BIT_AND_EXPR)
        {
+         double_int dmax;
          min = double_int_to_tree (expr_type,
                                    double_int_and (must_be_nonzero0,
                                                    must_be_nonzero1));
-         max = double_int_to_tree (expr_type,
-                                   double_int_and (may_be_nonzero0,
-                                                   may_be_nonzero1));
-         if (TREE_OVERFLOW (min) || tree_int_cst_sgn (min) < 0)
-           min = NULL_TREE;
-         if (TREE_OVERFLOW (max) || tree_int_cst_sgn (max) < 0)
-           max = NULL_TREE;
-         if (int_cst_range0 && tree_int_cst_sgn (vr0.min) >= 0)
+         dmax = double_int_and (may_be_nonzero0, may_be_nonzero1);
+         /* If both input ranges contain only negative values we can
+            truncate the result range maximum to the minimum of the
+            input range maxima.  */
+         if (int_cst_range0 && int_cst_range1
+             && tree_int_cst_sgn (vr0.max) < 0
+             && tree_int_cst_sgn (vr1.max) < 0)
            {
-             if (min == NULL_TREE)
-               min = build_int_cst (expr_type, 0);
-             if (max == NULL_TREE || tree_int_cst_lt (vr0.max, max))
-               max = vr0.max;
+             dmax = double_int_min (dmax, tree_to_double_int (vr0.max),
+                                    TYPE_UNSIGNED (expr_type));
+             dmax = double_int_min (dmax, tree_to_double_int (vr1.max),
+                                    TYPE_UNSIGNED (expr_type));
            }
+         /* If either input range contains only non-negative values
+            we can truncate the result range maximum to the respective
+            maximum of the input range.  */
+         if (int_cst_range0 && tree_int_cst_sgn (vr0.min) >= 0)
+           dmax = double_int_min (dmax, tree_to_double_int (vr0.max),
+                                  TYPE_UNSIGNED (expr_type));
          if (int_cst_range1 && tree_int_cst_sgn (vr1.min) >= 0)
-           {
-             if (min == NULL_TREE)
-               min = build_int_cst (expr_type, 0);
-             if (max == NULL_TREE || tree_int_cst_lt (vr1.max, max))
-               max = vr1.max;
-           }
+           dmax = double_int_min (dmax, tree_to_double_int (vr1.max),
+                                  TYPE_UNSIGNED (expr_type));
+         max = double_int_to_tree (expr_type, dmax);
        }
-      else if (!int_cst_range0
-              || !int_cst_range1
-              || tree_int_cst_sgn (vr0.min) < 0
-              || tree_int_cst_sgn (vr1.min) < 0)
+      else if (code == BIT_IOR_EXPR)
        {
-         set_value_range_to_varying (vr);
-         return;
-       }
-      else
-       {
-         min = double_int_to_tree (expr_type,
-                                   double_int_ior (must_be_nonzero0,
-                                                   must_be_nonzero1));
+         double_int dmin;
          max = double_int_to_tree (expr_type,
                                    double_int_ior (may_be_nonzero0,
                                                    may_be_nonzero1));
-         if (TREE_OVERFLOW (min) || tree_int_cst_sgn (min) < 0)
-           min = vr0.min;
+         dmin = double_int_ior (must_be_nonzero0, must_be_nonzero1);
+         /* If the input ranges contain only positive values we can
+            truncate the minimum of the result range to the maximum
+            of the input range minima.  */
+         if (int_cst_range0 && int_cst_range1
+             && tree_int_cst_sgn (vr0.min) >= 0
+             && tree_int_cst_sgn (vr1.min) >= 0)
+           {
+             dmin = double_int_max (dmin, tree_to_double_int (vr0.min),
+                                    TYPE_UNSIGNED (expr_type));
+             dmin = double_int_max (dmin, tree_to_double_int (vr1.min),
+                                    TYPE_UNSIGNED (expr_type));
+           }
+         /* If either input range contains only negative values
+            we can truncate the minimum of the result range to the
+            respective minimum range.  */
+         if (int_cst_range0 && tree_int_cst_sgn (vr0.max) < 0)
+           dmin = double_int_max (dmin, tree_to_double_int (vr0.min),
+                                  TYPE_UNSIGNED (expr_type));
+         if (int_cst_range1 && tree_int_cst_sgn (vr1.max) < 0)
+           dmin = double_int_max (dmin, tree_to_double_int (vr1.min),
+                                  TYPE_UNSIGNED (expr_type));
+         min = double_int_to_tree (expr_type, dmin);
+       }
+      else if (code == BIT_XOR_EXPR)
+       {
+         double_int result_zero_bits, result_one_bits;
+         result_zero_bits
+           = double_int_ior (double_int_and (must_be_nonzero0,
+                                             must_be_nonzero1),
+                             double_int_not
+                               (double_int_ior (may_be_nonzero0,
+                                                may_be_nonzero1)));
+         result_one_bits
+           = double_int_ior (double_int_and
+                               (must_be_nonzero0,
+                                double_int_not (may_be_nonzero1)),
+                             double_int_and
+                               (must_be_nonzero1,
+                                double_int_not (may_be_nonzero0)));
+         max = double_int_to_tree (expr_type,
+                                   double_int_not (result_zero_bits));
+         min = double_int_to_tree (expr_type, result_one_bits);
+         /* If the range has all positive or all negative values the
+            result is better than VARYING.  */
+         if (tree_int_cst_sgn (min) < 0
+             || tree_int_cst_sgn (max) >= 0)
+           ;
          else
-           min = vrp_int_const_binop (MAX_EXPR, min, vr0.min);
-         if (TREE_OVERFLOW (max) || tree_int_cst_sgn (max) < 0)
-           max = NULL_TREE;
-         min = vrp_int_const_binop (MAX_EXPR, min, vr1.min);
+           max = min = NULL_TREE;
        }
     }
   else
@@ -2793,42 +2848,19 @@ extract_range_from_binary_expr (value_range_t *vr,
     set_value_range (vr, type, min, max, NULL);
 }
 
-
-/* Extract range information from a unary expression EXPR based on
-   the range of its operand and the expression code.  */
+/* Extract range information from a binary expression OP0 CODE OP1 based on
+   the ranges of each of its operands with resulting type EXPR_TYPE.
+   The resulting range is stored in *VR.  */
 
 static void
-extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
-                              tree type, tree op0)
-{
-  tree min, max;
-  int cmp;
-  value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
-
-  /* Refuse to operate on certain unary expressions for which we
-     cannot easily determine a resulting range.  */
-  if (code == FIX_TRUNC_EXPR
-      || code == FLOAT_EXPR
-      || code == BIT_NOT_EXPR
-      || code == CONJ_EXPR)
-    {
-      /* We can still do constant propagation here.  */
-      if ((op0 = op_with_constant_singleton_value_range (op0)) != NULL_TREE)
-       {
-         tree tem = fold_unary (code, type, op0);
-         if (tem
-             && is_gimple_min_invariant (tem)
-             && !is_overflow_infinity (tem))
-           {
-             set_value_range (vr, VR_RANGE, tem, tem, NULL);
-             return;
-           }
-       }
-      set_value_range_to_varying (vr);
-      return;
-    }
+extract_range_from_binary_expr (value_range_t *vr,
+                               enum tree_code code,
+                               tree expr_type, tree op0, tree op1)
+{
+  value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+  value_range_t vr1 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
 
-  /* Get value ranges for the operand.  For constant operands, create
+  /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *(get_value_range (op0));
@@ -2837,54 +2869,66 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
   else
     set_value_range_to_varying (&vr0);
 
-  /* If VR0 is UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED)
-    {
-      set_value_range_to_undefined (vr);
-      return;
-    }
+  if (TREE_CODE (op1) == SSA_NAME)
+    vr1 = *(get_value_range (op1));
+  else if (is_gimple_min_invariant (op1))
+    set_value_range_to_value (&vr1, op1, NULL);
+  else
+    set_value_range_to_varying (&vr1);
+
+  extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
+}
+
+/* Extract range information from a unary operation CODE based on
+   the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE.
+   The The resulting range is stored in *VR.  */
+
+static void
+extract_range_from_unary_expr_1 (value_range_t *vr,
+                                enum tree_code code, tree type,
+                                value_range_t *vr0_, tree op0_type)
+{
+  value_range_t vr0 = *vr0_;
 
-  /* Refuse to operate on symbolic ranges, or if neither operand is
-     a pointer or integral type.  */
-  if ((!INTEGRAL_TYPE_P (TREE_TYPE (op0))
-       && !POINTER_TYPE_P (TREE_TYPE (op0)))
-      || (vr0.type != VR_VARYING
-         && symbolic_range_p (&vr0)))
+  /* VRP only operates on integral and pointer types.  */
+  if (!(INTEGRAL_TYPE_P (op0_type)
+       || POINTER_TYPE_P (op0_type))
+      || !(INTEGRAL_TYPE_P (type)
+          || POINTER_TYPE_P (type)))
     {
       set_value_range_to_varying (vr);
       return;
     }
 
-  /* If the expression involves pointers, we are only interested in
-     determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]).  */
-  if (POINTER_TYPE_P (type) || POINTER_TYPE_P (TREE_TYPE (op0)))
+  /* If VR0 is UNDEFINED, so is the result.  */
+  if (vr0.type == VR_UNDEFINED)
     {
-      bool sop;
-
-      sop = false;
-      if (range_is_nonnull (&vr0)
-         || (tree_unary_nonzero_warnv_p (code, type, op0, &sop)
-             && !sop))
-       set_value_range_to_nonnull (vr, type);
-      else if (range_is_null (&vr0))
-       set_value_range_to_null (vr, type);
-      else
-       set_value_range_to_varying (vr);
-
+      set_value_range_to_undefined (vr);
       return;
     }
 
-  /* Handle unary expressions on integer ranges.  */
-  if (CONVERT_EXPR_CODE_P (code)
-      && INTEGRAL_TYPE_P (type)
-      && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
+  if (CONVERT_EXPR_CODE_P (code))
     {
-      tree inner_type = TREE_TYPE (op0);
+      tree inner_type = op0_type;
       tree outer_type = type;
 
+      /* If the expression evaluates to a pointer, we are only interested in
+        determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]).  */
+      if (POINTER_TYPE_P (type))
+       {
+         if (range_is_nonnull (&vr0))
+           set_value_range_to_nonnull (vr, type);
+         else if (range_is_null (&vr0))
+           set_value_range_to_null (vr, type);
+         else
+           set_value_range_to_varying (vr);
+         return;
+       }
+
       /* If VR0 is varying and we increase the type precision, assume
         a full range for the following transformation.  */
       if (vr0.type == VR_VARYING
+         && INTEGRAL_TYPE_P (inner_type)
          && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
        {
          vr0.type = VR_RANGE;
@@ -2919,16 +2963,18 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
                         size_int (TYPE_PRECISION (outer_type)))))))
        {
          tree new_min, new_max;
-         new_min = force_fit_type_double (outer_type,
-                                          tree_to_double_int (vr0.min),
-                                          0, false);
-         new_max = force_fit_type_double (outer_type,
-                                          tree_to_double_int (vr0.max),
-                                          0, false);
          if (is_overflow_infinity (vr0.min))
            new_min = negative_overflow_infinity (outer_type);
+         else
+           new_min = force_fit_type_double (outer_type,
+                                            tree_to_double_int (vr0.min),
+                                            0, false);
          if (is_overflow_infinity (vr0.max))
            new_max = positive_overflow_infinity (outer_type);
+         else
+           new_max = force_fit_type_double (outer_type,
+                                            tree_to_double_int (vr0.max),
+                                            0, false);
          set_and_canonicalize_value_range (vr, vr0.type,
                                            new_min, new_max, NULL);
          return;
@@ -2937,92 +2983,44 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
       set_value_range_to_varying (vr);
       return;
     }
-
-  /* Conversion of a VR_VARYING value to a wider type can result
-     in a usable range.  So wait until after we've handled conversions
-     before dropping the result to VR_VARYING if we had a source
-     operand that is VR_VARYING.  */
-  if (vr0.type == VR_VARYING)
+  else if (code == NEGATE_EXPR)
     {
-      set_value_range_to_varying (vr);
+      /* -X is simply 0 - X, so re-use existing code that also handles
+         anti-ranges fine.  */
+      value_range_t zero = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+      set_value_range_to_value (&zero, build_int_cst (type, 0), NULL);
+      extract_range_from_binary_expr_1 (vr, MINUS_EXPR, type, &zero, &vr0);
       return;
     }
-
-  /* Apply the operation to each end of the range and see what we end
-     up with.  */
-  if (code == NEGATE_EXPR
-      && !TYPE_UNSIGNED (type))
+  else if (code == ABS_EXPR)
     {
-      /* NEGATE_EXPR flips the range around.  We need to treat
-        TYPE_MIN_VALUE specially.  */
-      if (is_positive_overflow_infinity (vr0.max))
-       min = negative_overflow_infinity (type);
-      else if (is_negative_overflow_infinity (vr0.max))
-       min = positive_overflow_infinity (type);
-      else if (!vrp_val_is_min (vr0.max))
-       min = fold_unary_to_constant (code, type, vr0.max);
-      else if (needs_overflow_infinity (type))
-       {
-         if (supports_overflow_infinity (type)
-             && !is_overflow_infinity (vr0.min)
-             && !vrp_val_is_min (vr0.min))
-           min = positive_overflow_infinity (type);
-         else
-           {
-             set_value_range_to_varying (vr);
-             return;
-           }
-       }
-      else
-       min = TYPE_MIN_VALUE (type);
+      tree min, max;
+      int cmp;
 
-      if (is_positive_overflow_infinity (vr0.min))
-       max = negative_overflow_infinity (type);
-      else if (is_negative_overflow_infinity (vr0.min))
-       max = positive_overflow_infinity (type);
-      else if (!vrp_val_is_min (vr0.min))
-       max = fold_unary_to_constant (code, type, vr0.min);
-      else if (needs_overflow_infinity (type))
-       {
-         if (supports_overflow_infinity (type))
-           max = positive_overflow_infinity (type);
-         else
-           {
-             set_value_range_to_varying (vr);
-             return;
-           }
-       }
-      else
-       max = TYPE_MIN_VALUE (type);
-    }
-  else if (code == NEGATE_EXPR
-          && TYPE_UNSIGNED (type))
-    {
-      if (!range_includes_zero_p (&vr0))
+      /* Pass through vr0 in the easy cases.  */
+      if (TYPE_UNSIGNED (type)
+         || value_range_nonnegative_p (&vr0))
        {
-         max = fold_unary_to_constant (code, type, vr0.min);
-         min = fold_unary_to_constant (code, type, vr0.max);
+         copy_value_range (vr, &vr0);
+         return;
        }
-      else
+
+      /* For the remaining varying or symbolic ranges we can't do anything
+        useful.  */
+      if (vr0.type == VR_VARYING
+         || symbolic_range_p (&vr0))
        {
-         if (range_is_null (&vr0))
-           set_value_range_to_null (vr, type);
-         else
-           set_value_range_to_varying (vr);
+         set_value_range_to_varying (vr);
          return;
        }
-    }
-  else if (code == ABS_EXPR
-           && !TYPE_UNSIGNED (type))
-    {
+
       /* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a
          useful range.  */
       if (!TYPE_OVERFLOW_UNDEFINED (type)
          && ((vr0.type == VR_RANGE
               && vrp_val_is_min (vr0.min))
              || (vr0.type == VR_ANTI_RANGE
-                 && !vrp_val_is_min (vr0.min)
-                 && !range_includes_zero_p (&vr0))))
+                 && !vrp_val_is_min (vr0.min))))
        {
          set_value_range_to_varying (vr);
          return;
@@ -3067,7 +3065,7 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
         ~[-INF, min(MIN, MAX)].  */
       if (vr0.type == VR_ANTI_RANGE)
        {
-         if (range_includes_zero_p (&vr0))
+         if (range_includes_zero_p (vr0.min, vr0.max) == 1)
            {
              /* Take the lower of the two values.  */
              if (cmp != 1)
@@ -3118,7 +3116,7 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
 
       /* If the range contains zero then we know that the minimum value in the
          range will be zero.  */
-      else if (range_includes_zero_p (&vr0))
+      else if (range_includes_zero_p (vr0.min, vr0.max) == 1)
        {
          if (cmp == 1)
            max = min;
@@ -3134,78 +3132,69 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
              max = t;
            }
        }
+
+      cmp = compare_values (min, max);
+      if (cmp == -2 || cmp == 1)
+       {
+         /* If the new range has its limits swapped around (MIN > MAX),
+            then the operation caused one of them to wrap around, mark
+            the new range VARYING.  */
+         set_value_range_to_varying (vr);
+       }
+      else
+       set_value_range (vr, vr0.type, min, max, NULL);
+      return;
     }
-  else
+  else if (code == BIT_NOT_EXPR)
     {
-      /* Otherwise, operate on each end of the range.  */
-      min = fold_unary_to_constant (code, type, vr0.min);
-      max = fold_unary_to_constant (code, type, vr0.max);
+      /* ~X is simply -1 - X, so re-use existing code that also handles
+         anti-ranges fine.  */
+      value_range_t minusone = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+      set_value_range_to_value (&minusone, build_int_cst (type, -1), NULL);
+      extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
+                                       type, &minusone, &vr0);
+      return;
+    }
+  else if (code == PAREN_EXPR)
+    {
+      copy_value_range (vr, &vr0);
+      return;
+    }
 
-      if (needs_overflow_infinity (type))
-       {
-         gcc_assert (code != NEGATE_EXPR && code != ABS_EXPR);
+  /* For unhandled operations fall back to varying.  */
+  set_value_range_to_varying (vr);
+  return;
+}
 
-         /* If both sides have overflowed, we don't know
-            anything.  */
-         if ((is_overflow_infinity (vr0.min)
-              || TREE_OVERFLOW (min))
-             && (is_overflow_infinity (vr0.max)
-                 || TREE_OVERFLOW (max)))
-           {
-             set_value_range_to_varying (vr);
-             return;
-           }
 
-         if (is_overflow_infinity (vr0.min))
-           min = vr0.min;
-         else if (TREE_OVERFLOW (min))
-           {
-             if (supports_overflow_infinity (type))
-               min = (tree_int_cst_sgn (min) >= 0
-                      ? positive_overflow_infinity (TREE_TYPE (min))
-                      : negative_overflow_infinity (TREE_TYPE (min)));
-             else
-               {
-                 set_value_range_to_varying (vr);
-                 return;
-               }
-           }
+/* Extract range information from a unary expression CODE OP0 based on
+   the range of its operand with resulting type TYPE.
+   The resulting range is stored in *VR.  */
 
-         if (is_overflow_infinity (vr0.max))
-           max = vr0.max;
-         else if (TREE_OVERFLOW (max))
-           {
-             if (supports_overflow_infinity (type))
-               max = (tree_int_cst_sgn (max) >= 0
-                      ? positive_overflow_infinity (TREE_TYPE (max))
-                      : negative_overflow_infinity (TREE_TYPE (max)));
-             else
-               {
-                 set_value_range_to_varying (vr);
-                 return;
-               }
-           }
-       }
-    }
+static void
+extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
+                              tree type, tree op0)
+{
+  value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
 
-  cmp = compare_values (min, max);
-  if (cmp == -2 || cmp == 1)
-    {
-      /* If the new range has its limits swapped around (MIN > MAX),
-        then the operation caused one of them to wrap around, mark
-        the new range VARYING.  */
-      set_value_range_to_varying (vr);
-    }
+  /* Get value ranges for the operand.  For constant operands, create
+     a new value range with the operand to simplify processing.  */
+  if (TREE_CODE (op0) == SSA_NAME)
+    vr0 = *(get_value_range (op0));
+  else if (is_gimple_min_invariant (op0))
+    set_value_range_to_value (&vr0, op0, NULL);
   else
-    set_value_range (vr, vr0.type, min, max, NULL);
+    set_value_range_to_varying (&vr0);
+
+  extract_range_from_unary_expr_1 (vr, code, type, &vr0, TREE_TYPE (op0));
 }
 
 
-/* Extract range information from a conditional expression EXPR based on
+/* Extract range information from a conditional expression STMT based on
    the ranges of each of its operands and the expression code.  */
 
 static void
-extract_range_from_cond_expr (value_range_t *vr, tree expr)
+extract_range_from_cond_expr (value_range_t *vr, gimple stmt)
 {
   tree op0, op1;
   value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
@@ -3213,7 +3202,7 @@ extract_range_from_cond_expr (value_range_t *vr, tree expr)
 
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
-  op0 = COND_EXPR_THEN (expr);
+  op0 = gimple_assign_rhs2 (stmt);
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *(get_value_range (op0));
   else if (is_gimple_min_invariant (op0))
@@ -3221,7 +3210,7 @@ extract_range_from_cond_expr (value_range_t *vr, tree expr)
   else
     set_value_range_to_varying (&vr0);
 
-  op1 = COND_EXPR_ELSE (expr);
+  op1 = gimple_assign_rhs3 (stmt);
   if (TREE_CODE (op1) == SSA_NAME)
     vr1 = *(get_value_range (op1));
   else if (is_gimple_min_invariant (op1))
@@ -3230,8 +3219,8 @@ extract_range_from_cond_expr (value_range_t *vr, tree expr)
     set_value_range_to_varying (&vr1);
 
   /* The resulting value range is the union of the operand ranges */
-  vrp_meet (&vr0, &vr1);
   copy_value_range (vr, &vr0);
+  vrp_meet (vr, &vr1);
 }
 
 
@@ -3279,8 +3268,20 @@ extract_range_basic (value_range_t *vr, gimple stmt)
   bool sop = false;
   tree type = gimple_expr_type (stmt);
 
-  if (INTEGRAL_TYPE_P (type)
-      && gimple_stmt_nonnegative_warnv_p (stmt, &sop))
+  /* If the call is __builtin_constant_p and the argument is a
+     function parameter resolve it to false.  This avoids bogus
+     array bound warnings.
+     ???  We could do this as early as inlining is finished.  */
+  if (gimple_call_builtin_p (stmt, BUILT_IN_CONSTANT_P))
+    {
+      tree arg = gimple_call_arg (stmt, 0);
+      if (TREE_CODE (arg) == SSA_NAME
+         && SSA_NAME_IS_DEFAULT_DEF (arg)
+         && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
+       set_value_range_to_null (vr, type);
+    }
+  else if (INTEGRAL_TYPE_P (type)
+          && gimple_stmt_nonnegative_warnv_p (stmt, &sop))
     set_value_range_to_nonnegative (vr, type,
                                    sop || stmt_overflow_infinity (stmt));
   else if (vrp_stmt_computes_nonzero (stmt, &sop)
@@ -3303,10 +3304,7 @@ extract_range_from_assignment (value_range_t *vr, gimple stmt)
     extract_range_from_assert (vr, gimple_assign_rhs1 (stmt));
   else if (code == SSA_NAME)
     extract_range_from_ssa_name (vr, gimple_assign_rhs1 (stmt));
-  else if (TREE_CODE_CLASS (code) == tcc_binary
-          || code == TRUTH_AND_EXPR
-          || code == TRUTH_OR_EXPR
-          || code == TRUTH_XOR_EXPR)
+  else if (TREE_CODE_CLASS (code) == tcc_binary)
     extract_range_from_binary_expr (vr, gimple_assign_rhs_code (stmt),
                                    gimple_expr_type (stmt),
                                    gimple_assign_rhs1 (stmt),
@@ -3316,7 +3314,7 @@ extract_range_from_assignment (value_range_t *vr, gimple stmt)
                                   gimple_expr_type (stmt),
                                   gimple_assign_rhs1 (stmt));
   else if (code == COND_EXPR)
-    extract_range_from_cond_expr (vr, gimple_assign_rhs1 (stmt));
+    extract_range_from_cond_expr (vr, stmt);
   else if (TREE_CODE_CLASS (code) == tcc_comparison)
     extract_range_from_comparison (vr, gimple_assign_rhs_code (stmt),
                                   gimple_expr_type (stmt),
@@ -3745,7 +3743,7 @@ compare_range_with_value (enum tree_code comp, value_range_t *vr, tree val,
        return NULL_TREE;
 
       /* ~[VAL_1, VAL_2] OP VAL is known if VAL_1 <= VAL <= VAL_2.  */
-      if (value_inside_range (val, vr) == 1)
+      if (value_inside_range (val, vr->min, vr->max) == 1)
        return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
 
       return NULL_TREE;
@@ -3934,7 +3932,7 @@ dump_all_value_ranges (FILE *file)
 {
   size_t i;
 
-  for (i = 0; i < num_ssa_names; i++)
+  for (i = 0; i < num_vr_values; i++)
     {
       if (vr_value[i])
        {
@@ -3976,13 +3974,6 @@ build_assert_expr_for (tree cond, tree v)
       tree a = build2 (ASSERT_EXPR, TREE_TYPE (v), v, cond);
       assertion = gimple_build_assign (n, a);
     }
-  else if (TREE_CODE (cond) == TRUTH_NOT_EXPR)
-    {
-      /* Given !V, build the assignment N = false.  */
-      tree op0 = TREE_OPERAND (cond, 0);
-      gcc_assert (op0 == v);
-      assertion = gimple_build_assign (n, boolean_false_node);
-    }
   else if (TREE_CODE (cond) == SSA_NAME)
     {
       /* Given V, build the assignment N = true.  */
@@ -4519,11 +4510,9 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
                                              invert);
     }
   else if ((code == NE_EXPR
-           && (gimple_assign_rhs_code (op_def) == TRUTH_AND_EXPR
-               || gimple_assign_rhs_code (op_def) == BIT_AND_EXPR))
+           && gimple_assign_rhs_code (op_def) == BIT_AND_EXPR)
           || (code == EQ_EXPR
-              && (gimple_assign_rhs_code (op_def) == TRUTH_OR_EXPR
-                  || gimple_assign_rhs_code (op_def) == BIT_IOR_EXPR)))
+              && gimple_assign_rhs_code (op_def) == BIT_IOR_EXPR))
     {
       /* Recurse on each operand.  */
       retval |= register_edge_assert_for_1 (gimple_assign_rhs1 (op_def),
@@ -4531,7 +4520,8 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
       retval |= register_edge_assert_for_1 (gimple_assign_rhs2 (op_def),
                                            code, e, bsi);
     }
-  else if (gimple_assign_rhs_code (op_def) == TRUTH_NOT_EXPR)
+  else if (gimple_assign_rhs_code (op_def) == BIT_NOT_EXPR
+          && TYPE_PRECISION (TREE_TYPE (gimple_assign_lhs (op_def))) == 1)
     {
       /* Recurse, flipping CODE.  */
       code = invert_tree_comparison (code, false);
@@ -4546,9 +4536,13 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
     }
   else if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (op_def)))
     {
-      /* Recurse through the type conversion.  */
-      retval |= register_edge_assert_for_1 (gimple_assign_rhs1 (op_def),
-                                           code, e, bsi);
+      /* Recurse through the type conversion, unless it is a narrowing
+        conversion or conversion from non-integral type.  */
+      tree rhs = gimple_assign_rhs1 (op_def);
+      if (INTEGRAL_TYPE_P (TREE_TYPE (rhs))
+         && (TYPE_PRECISION (TREE_TYPE (rhs))
+             <= TYPE_PRECISION (TREE_TYPE (op))))
+       retval |= register_edge_assert_for_1 (rhs, code, e, bsi);
     }
 
   return retval;
@@ -4588,8 +4582,8 @@ register_edge_assert_for (tree name, edge e, gimple_stmt_iterator si,
      the value zero or one, then we may be able to assert values
      for SSA_NAMEs which flow into COND.  */
 
-  /* In the case of NAME == 1 or NAME != 0, for TRUTH_AND_EXPR defining
-     statement of NAME we can assert both operands of the TRUTH_AND_EXPR
+  /* In the case of NAME == 1 or NAME != 0, for BIT_AND_EXPR defining
+     statement of NAME we can assert both operands of the BIT_AND_EXPR
      have nonzero value.  */
   if (((comp_code == EQ_EXPR && integer_onep (val))
        || (comp_code == NE_EXPR && integer_zerop (val))))
@@ -4597,8 +4591,7 @@ register_edge_assert_for (tree name, edge e, gimple_stmt_iterator si,
       gimple def_stmt = SSA_NAME_DEF_STMT (name);
 
       if (is_gimple_assign (def_stmt)
-         && (gimple_assign_rhs_code (def_stmt) == TRUTH_AND_EXPR
-             || gimple_assign_rhs_code (def_stmt) == BIT_AND_EXPR))
+         && gimple_assign_rhs_code (def_stmt) == BIT_AND_EXPR)
        {
          tree op0 = gimple_assign_rhs1 (def_stmt);
          tree op1 = gimple_assign_rhs2 (def_stmt);
@@ -4607,20 +4600,20 @@ register_edge_assert_for (tree name, edge e, gimple_stmt_iterator si,
        }
     }
 
-  /* In the case of NAME == 0 or NAME != 1, for TRUTH_OR_EXPR defining
-     statement of NAME we can assert both operands of the TRUTH_OR_EXPR
+  /* In the case of NAME == 0 or NAME != 1, for BIT_IOR_EXPR defining
+     statement of NAME we can assert both operands of the BIT_IOR_EXPR
      have zero value.  */
   if (((comp_code == EQ_EXPR && integer_zerop (val))
        || (comp_code == NE_EXPR && integer_onep (val))))
     {
       gimple def_stmt = SSA_NAME_DEF_STMT (name);
 
+      /* For BIT_IOR_EXPR only if NAME == 0 both operands have
+        necessarily zero value, or if type-precision is one.  */
       if (is_gimple_assign (def_stmt)
-         && (gimple_assign_rhs_code (def_stmt) == TRUTH_OR_EXPR
-             /* For BIT_IOR_EXPR only if NAME == 0 both operands have
-                necessarily zero value.  */
-             || (comp_code == EQ_EXPR
-                 && (gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR))))
+         && (gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR
+             && (TYPE_PRECISION (TREE_TYPE (name)) == 1
+                 || comp_code == EQ_EXPR)))
        {
          tree op0 = gimple_assign_rhs1 (def_stmt);
          tree op1 = gimple_assign_rhs2 (def_stmt);
@@ -5577,7 +5570,7 @@ stmt_interesting_for_vrp (gimple stmt)
              || POINTER_TYPE_P (TREE_TYPE (lhs)))
          && ((is_gimple_call (stmt)
               && gimple_call_fndecl (stmt) != NULL_TREE
-              && DECL_IS_BUILTIN (gimple_call_fndecl (stmt)))
+              && DECL_BUILT_IN (gimple_call_fndecl (stmt)))
              || !gimple_vuse (stmt)))
        return true;
     }
@@ -5596,7 +5589,9 @@ vrp_initialize (void)
 {
   basic_block bb;
 
-  vr_value = XCNEWVEC (value_range_t *, num_ssa_names);
+  values_propagated = false;
+  num_vr_values = num_ssa_names;
+  vr_value = XCNEWVEC (value_range_t *, num_vr_values);
   vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
 
   FOR_EACH_BB (bb)
@@ -5723,7 +5718,7 @@ vrp_visit_assignment_or_call (gimple stmt, tree *output_p)
 static inline value_range_t
 get_vr_for_comparison (int i)
 {
-  value_range_t vr = *(vr_value[i]);
+  value_range_t vr = *get_value_range (ssa_name (i));
 
   /* If name N_i does not have a valid range, use N_i as its own
      range.  This allows us to compare against names that may
@@ -6413,7 +6408,7 @@ vrp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p)
         builtin functions.  */
       if ((is_gimple_call (stmt)
           && gimple_call_fndecl (stmt) != NULL_TREE
-          && DECL_IS_BUILTIN (gimple_call_fndecl (stmt)))
+          && DECL_BUILT_IN (gimple_call_fndecl (stmt)))
          || !gimple_vuse (stmt))
        return vrp_visit_assignment_or_call (stmt, output_p);
     }
@@ -6440,13 +6435,17 @@ vrp_meet (value_range_t *vr0, value_range_t *vr1)
 {
   if (vr0->type == VR_UNDEFINED)
     {
-      copy_value_range (vr0, vr1);
+      /* Drop equivalences.  See PR53465.  */
+      set_value_range (vr0, vr1->type, vr1->min, vr1->max, NULL);
       return;
     }
 
   if (vr1->type == VR_UNDEFINED)
     {
-      /* Nothing to do.  VR0 already has the resulting range.  */
+      /* VR0 already has the resulting range, just drop equivalences.
+        See PR53465.  */
+      if (vr0->equiv)
+       bitmap_clear (vr0->equiv);
       return;
     }
 
@@ -6559,11 +6558,15 @@ give_up:
      anti-ranges from ranges is necessary because of the odd
      semantics of range_includes_zero_p and friends.  */
   if (!symbolic_range_p (vr0)
-      && ((vr0->type == VR_RANGE && !range_includes_zero_p (vr0))
-         || (vr0->type == VR_ANTI_RANGE && range_includes_zero_p (vr0)))
+      && ((vr0->type == VR_RANGE
+          && range_includes_zero_p (vr0->min, vr0->max) == 0)
+         || (vr0->type == VR_ANTI_RANGE
+             && range_includes_zero_p (vr0->min, vr0->max) == 1))
       && !symbolic_range_p (vr1)
-      && ((vr1->type == VR_RANGE && !range_includes_zero_p (vr1))
-         || (vr1->type == VR_ANTI_RANGE && range_includes_zero_p (vr1))))
+      && ((vr1->type == VR_RANGE
+          && range_includes_zero_p (vr1->min, vr1->max) == 0)
+         || (vr1->type == VR_ANTI_RANGE
+             && range_includes_zero_p (vr1->min, vr1->max) == 1)))
     {
       set_value_range_to_nonnull (vr0, TREE_TYPE (vr0->min));
 
@@ -6588,6 +6591,7 @@ vrp_visit_phi_node (gimple phi)
   tree lhs = PHI_RESULT (phi);
   value_range_t *lhs_vr = get_value_range (lhs);
   value_range_t vr_result = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+  bool first = true;
   int edges, old_edges;
   struct loop *l;
 
@@ -6620,6 +6624,20 @@ vrp_visit_phi_node (gimple phi)
          if (TREE_CODE (arg) == SSA_NAME)
            {
              vr_arg = *(get_value_range (arg));
+             /* Do not allow equivalences or symbolic ranges to leak in from
+                backedges.  That creates invalid equivalencies.  */
+             if (e->flags & EDGE_DFS_BACK
+                 && (vr_arg.type == VR_RANGE
+                     || vr_arg.type == VR_ANTI_RANGE))
+               {
+                 vr_arg.equiv = NULL;
+                 if (symbolic_range_p (&vr_arg))
+                   {
+                     vr_arg.type = VR_VARYING;
+                     vr_arg.min = NULL_TREE;
+                     vr_arg.max = NULL_TREE;
+                   }
+               }
            }
          else
            {
@@ -6644,7 +6662,11 @@ vrp_visit_phi_node (gimple phi)
              fprintf (dump_file, "\n");
            }
 
-         vrp_meet (&vr_result, &vr_arg);
+         if (first)
+           copy_value_range (&vr_result, &vr_arg);
+         else
+           vrp_meet (&vr_result, &vr_arg);
+         first = false;
 
          if (vr_result.type == VR_VARYING)
            break;
@@ -6653,6 +6675,8 @@ vrp_visit_phi_node (gimple phi)
 
   if (vr_result.type == VR_VARYING)
     goto varying;
+  else if (vr_result.type == VR_UNDEFINED)
+    goto update_range;
 
   old_edges = vr_phi_edge_counts[SSA_NAME_VERSION (lhs)];
   vr_phi_edge_counts[SSA_NAME_VERSION (lhs)] = edges;
@@ -6724,6 +6748,7 @@ vrp_visit_phi_node (gimple phi)
 
   /* If the new range is different than the previous value, keep
      iterating.  */
+update_range:
   if (update_value_range (lhs, &vr_result))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -6753,137 +6778,64 @@ static bool
 simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
 {
   enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
-  tree val = NULL;
-  tree op0, op1;
-  value_range_t *vr;
-  bool sop = false;
+  tree lhs, op0, op1;
   bool need_conversion;
 
-  op0 = gimple_assign_rhs1 (stmt);
-  if (TYPE_PRECISION (TREE_TYPE (op0)) != 1)
-    {
-      if (TREE_CODE (op0) != SSA_NAME)
-       return false;
-      vr = get_value_range (op0);
-
-      val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
-      if (!val || !integer_onep (val))
-        return false;
-
-      val = compare_range_with_value (LE_EXPR, vr, integer_one_node, &sop);
-      if (!val || !integer_onep (val))
-        return false;
-    }
-
-  if (rhs_code == TRUTH_NOT_EXPR)
-    {
-      rhs_code = NE_EXPR;
-      op1 = build_int_cst (TREE_TYPE (op0), 1);
-    }
-  else
-    {
-      op1 = gimple_assign_rhs2 (stmt);
-
-      /* Reduce number of cases to handle.  */
-      if (is_gimple_min_invariant (op1))
-       {
-          /* Exclude anything that should have been already folded.  */
-         if (rhs_code != EQ_EXPR
-             && rhs_code != NE_EXPR
-             && rhs_code != TRUTH_XOR_EXPR)
-           return false;
-
-         if (!integer_zerop (op1)
-             && !integer_onep (op1)
-             && !integer_all_onesp (op1))
-           return false;
+  /* We handle only !=/== case here.  */
+  gcc_assert (rhs_code == EQ_EXPR || rhs_code == NE_EXPR);
 
-         /* Limit the number of cases we have to consider.  */
-         if (rhs_code == EQ_EXPR)
-           {
-             rhs_code = NE_EXPR;
-             op1 = fold_unary (TRUTH_NOT_EXPR, TREE_TYPE (op1), op1);
-           }
-       }
-      else
-       {
-         /* Punt on A == B as there is no BIT_XNOR_EXPR.  */
-         if (rhs_code == EQ_EXPR)
-           return false;
+  op0 = gimple_assign_rhs1 (stmt);
+  if (!op_with_boolean_value_range_p (op0))
+    return false;
 
-         if (TYPE_PRECISION (TREE_TYPE (op1)) != 1)
-           {
-             vr = get_value_range (op1);
-             val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
-             if (!val || !integer_onep (val))
-               return false;
-
-             val = compare_range_with_value (LE_EXPR, vr, integer_one_node, &sop);
-             if (!val || !integer_onep (val))
-               return false;
-           }
-       }
-    }
+  op1 = gimple_assign_rhs2 (stmt);
+  if (!op_with_boolean_value_range_p (op1))
+    return false;
 
-  if (sop && issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_MISC))
+  /* Reduce number of cases to handle to NE_EXPR.  As there is no
+     BIT_XNOR_EXPR we cannot replace A == B with a single statement.  */
+  if (rhs_code == EQ_EXPR)
     {
-      location_t location;
-
-      if (!gimple_has_location (stmt))
-       location = input_location;
-      else
-       location = gimple_location (stmt);
-
-      if (rhs_code == TRUTH_AND_EXPR || rhs_code == TRUTH_OR_EXPR)
-        warning_at (location, OPT_Wstrict_overflow,
-                   _("assuming signed overflow does not occur when "
-                     "simplifying && or || to & or |"));
+      if (TREE_CODE (op1) == INTEGER_CST)
+       op1 = int_const_binop (BIT_XOR_EXPR, op1, integer_one_node);
       else
-        warning_at (location, OPT_Wstrict_overflow,
-                   _("assuming signed overflow does not occur when "
-                     "simplifying ==, != or ! to identity or ^"));
+       return false;
     }
 
-  need_conversion =
-    !useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (stmt)),
-                               TREE_TYPE (op0));
+  lhs = gimple_assign_lhs (stmt);
+  need_conversion
+    = !useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (op0));
 
-  /* Make sure to not sign-extend -1 as a boolean value.  */
+  /* Make sure to not sign-extend a 1-bit 1 when converting the result.  */
   if (need_conversion
       && !TYPE_UNSIGNED (TREE_TYPE (op0))
-      && TYPE_PRECISION (TREE_TYPE (op0)) == 1)
-    return false;
-
-  switch (rhs_code)
-    {
-    case TRUTH_AND_EXPR:
-      rhs_code = BIT_AND_EXPR;
-      break;
-    case TRUTH_OR_EXPR:
-      rhs_code = BIT_IOR_EXPR;
-      break;
-    case TRUTH_XOR_EXPR:
-    case NE_EXPR:
-      if (integer_zerop (op1))
-       {
-         gimple_assign_set_rhs_with_ops (gsi,
-                                         need_conversion ? NOP_EXPR : SSA_NAME,
-                                         op0, NULL);
-         update_stmt (gsi_stmt (*gsi));
-         return true;
-       }
-
-      rhs_code = BIT_XOR_EXPR;
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  if (need_conversion)
+      && TYPE_PRECISION (TREE_TYPE (op0)) == 1
+      && TYPE_PRECISION (TREE_TYPE (lhs)) > 1)
     return false;
 
-  gimple_assign_set_rhs_with_ops (gsi, rhs_code, op0, op1);
+  /* For A != 0 we can substitute A itself.  */
+  if (integer_zerop (op1))
+    gimple_assign_set_rhs_with_ops (gsi,
+                                   need_conversion
+                                   ? NOP_EXPR : TREE_CODE (op0),
+                                   op0, NULL_TREE);
+  /* For A != B we substitute A ^ B.  Either with conversion.  */
+  else if (need_conversion)
+    {
+      gimple newop;
+      tree tem = create_tmp_reg (TREE_TYPE (op0), NULL);
+      newop = gimple_build_assign_with_ops (BIT_XOR_EXPR, tem, op0, op1);
+      tem = make_ssa_name (tem, newop);
+      gimple_assign_set_lhs (newop, tem);
+      gsi_insert_before (gsi, newop, GSI_SAME_STMT);
+      update_stmt (newop);
+      gimple_assign_set_rhs_with_ops (gsi, NOP_EXPR, tem, NULL_TREE);
+    }
+  /* Or without.  */
+  else
+    gimple_assign_set_rhs_with_ops (gsi, BIT_XOR_EXPR, op0, op1);
   update_stmt (gsi_stmt (*gsi));
+
   return true;
 }
 
@@ -7350,9 +7302,13 @@ simplify_conversion_using_ranges (gimple stmt)
   tree innerop, middleop, finaltype;
   gimple def_stmt;
   value_range_t *innervr;
-  double_int innermin, innermax, middlemin, middlemax;
+  bool inner_unsigned_p, middle_unsigned_p, final_unsigned_p;
+  unsigned inner_prec, middle_prec, final_prec;
+  double_int innermin, innermed, innermax, middlemin, middlemed, middlemax;
 
   finaltype = TREE_TYPE (gimple_assign_lhs (stmt));
+  if (!INTEGRAL_TYPE_P (finaltype))
+    return false;
   middleop = gimple_assign_rhs1 (stmt);
   def_stmt = SSA_NAME_DEF_STMT (middleop);
   if (!is_gimple_assign (def_stmt)
@@ -7373,26 +7329,49 @@ simplify_conversion_using_ranges (gimple stmt)
      the middle conversion is removed.  */
   innermin = tree_to_double_int (innervr->min);
   innermax = tree_to_double_int (innervr->max);
-  middlemin = double_int_ext (innermin, TYPE_PRECISION (TREE_TYPE (middleop)),
-                             TYPE_UNSIGNED (TREE_TYPE (middleop)));
-  middlemax = double_int_ext (innermax, TYPE_PRECISION (TREE_TYPE (middleop)),
-                             TYPE_UNSIGNED (TREE_TYPE (middleop)));
-  /* If the middle values do not represent a proper range fail.  */
-  if (double_int_cmp (middlemin, middlemax,
-                     TYPE_UNSIGNED (TREE_TYPE (middleop))) > 0)
+
+  inner_prec = TYPE_PRECISION (TREE_TYPE (innerop));
+  middle_prec = TYPE_PRECISION (TREE_TYPE (middleop));
+  final_prec = TYPE_PRECISION (finaltype);
+
+  /* If the first conversion is not injective, the second must not
+     be widening.  */
+  if (double_int_cmp (double_int_sub (innermax, innermin),
+                     double_int_mask (middle_prec), true) > 0
+      && middle_prec < final_prec)
     return false;
+  /* We also want a medium value so that we can track the effect that
+     narrowing conversions with sign change have.  */
+  inner_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (innerop));
+  if (inner_unsigned_p)
+    innermed = double_int_rshift (double_int_mask (inner_prec),
+                                 1, inner_prec, false);
+  else
+    innermed = double_int_zero;
+  if (double_int_cmp (innermin, innermed, inner_unsigned_p) >= 0
+      || double_int_cmp (innermed, innermax, inner_unsigned_p) >= 0)
+    innermed = innermin;
+
+  middle_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (middleop));
+  middlemin = double_int_ext (innermin, middle_prec, middle_unsigned_p);
+  middlemed = double_int_ext (innermed, middle_prec, middle_unsigned_p);
+  middlemax = double_int_ext (innermax, middle_prec, middle_unsigned_p);
+
+  /* Require that the final conversion applied to both the original
+     and the intermediate range produces the same result.  */
+  final_unsigned_p = TYPE_UNSIGNED (finaltype);
   if (!double_int_equal_p (double_int_ext (middlemin,
-                                          TYPE_PRECISION (finaltype),
-                                          TYPE_UNSIGNED (finaltype)),
+                                          final_prec, final_unsigned_p),
                           double_int_ext (innermin,
-                                          TYPE_PRECISION (finaltype),
-                                          TYPE_UNSIGNED (finaltype)))
+                                          final_prec, final_unsigned_p))
+      || !double_int_equal_p (double_int_ext (middlemed,
+                                             final_prec, final_unsigned_p),
+                             double_int_ext (innermed,
+                                             final_prec, final_unsigned_p))
       || !double_int_equal_p (double_int_ext (middlemax,
-                                             TYPE_PRECISION (finaltype),
-                                             TYPE_UNSIGNED (finaltype)),
+                                             final_prec, final_unsigned_p),
                              double_int_ext (innermax,
-                                             TYPE_PRECISION (finaltype),
-                                             TYPE_UNSIGNED (finaltype))))
+                                             final_prec, final_unsigned_p)))
     return false;
 
   gimple_assign_set_rhs1 (stmt, innerop);
@@ -7400,6 +7379,121 @@ simplify_conversion_using_ranges (gimple stmt)
   return true;
 }
 
+/* Return whether the value range *VR fits in an integer type specified
+   by PRECISION and UNSIGNED_P.  */
+
+static bool
+range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p)
+{
+  tree src_type;
+  unsigned src_precision;
+  double_int tem;
+
+  /* We can only handle integral and pointer types.  */
+  src_type = TREE_TYPE (vr->min);
+  if (!INTEGRAL_TYPE_P (src_type)
+      && !POINTER_TYPE_P (src_type))
+    return false;
+
+  /* An extension is always fine, so is an identity transform.  */
+  src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
+  if (src_precision < precision
+      || (src_precision == precision
+         && TYPE_UNSIGNED (src_type) == unsigned_p))
+    return true;
+
+  /* Now we can only handle ranges with constant bounds.  */
+  if (vr->type != VR_RANGE
+      || TREE_CODE (vr->min) != INTEGER_CST
+      || TREE_CODE (vr->max) != INTEGER_CST)
+    return false;
+
+  /* For precision-preserving sign-changes the MSB of the double-int
+     has to be clear.  */
+  if (src_precision == precision
+      && (TREE_INT_CST_HIGH (vr->min) | TREE_INT_CST_HIGH (vr->max)) < 0)
+    return false;
+
+  /* Then we can perform the conversion on both ends and compare
+     the result for equality.  */
+  tem = double_int_ext (tree_to_double_int (vr->min), precision, unsigned_p);
+  if (!double_int_equal_p (tree_to_double_int (vr->min), tem))
+    return false;
+  tem = double_int_ext (tree_to_double_int (vr->max), precision, unsigned_p);
+  if (!double_int_equal_p (tree_to_double_int (vr->max), tem))
+    return false;
+
+  return true;
+}
+
+/* Simplify a conversion from integral SSA name to float in STMT.  */
+
+static bool
+simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+{
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  value_range_t *vr = get_value_range (rhs1);
+  enum machine_mode fltmode = TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt)));
+  enum machine_mode mode;
+  tree tem;
+  gimple conv;
+
+  /* We can only handle constant ranges.  */
+  if (vr->type != VR_RANGE
+      || TREE_CODE (vr->min) != INTEGER_CST
+      || TREE_CODE (vr->max) != INTEGER_CST)
+    return false;
+
+  /* First check if we can use a signed type in place of an unsigned.  */
+  if (TYPE_UNSIGNED (TREE_TYPE (rhs1))
+      && (can_float_p (fltmode, TYPE_MODE (TREE_TYPE (rhs1)), 0)
+         != CODE_FOR_nothing)
+      && range_fits_type_p (vr, GET_MODE_PRECISION
+                                 (TYPE_MODE (TREE_TYPE (rhs1))), 0))
+    mode = TYPE_MODE (TREE_TYPE (rhs1));
+  /* If we can do the conversion in the current input mode do nothing.  */
+  else if (can_float_p (fltmode, TYPE_MODE (TREE_TYPE (rhs1)),
+                       TYPE_UNSIGNED (TREE_TYPE (rhs1))))
+    return false;
+  /* Otherwise search for a mode we can use, starting from the narrowest
+     integer mode available.  */
+  else
+    {
+      mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+      do
+       {
+         /* If we cannot do a signed conversion to float from mode
+            or if the value-range does not fit in the signed type
+            try with a wider mode.  */
+         if (can_float_p (fltmode, mode, 0) != CODE_FOR_nothing
+             && range_fits_type_p (vr, GET_MODE_PRECISION (mode), 0))
+           break;
+
+         mode = GET_MODE_WIDER_MODE (mode);
+         /* But do not widen the input.  Instead leave that to the
+            optabs expansion code.  */
+         if (GET_MODE_PRECISION (mode) > TYPE_PRECISION (TREE_TYPE (rhs1)))
+           return false;
+       }
+      while (mode != VOIDmode);
+      if (mode == VOIDmode)
+       return false;
+    }
+
+  /* It works, insert a truncation or sign-change before the
+     float conversion.  */
+  tem = create_tmp_var (build_nonstandard_integer_type
+                         (GET_MODE_PRECISION (mode), 0), NULL);
+  conv = gimple_build_assign_with_ops (NOP_EXPR, tem, rhs1, NULL_TREE);
+  tem = make_ssa_name (tem, conv);
+  gimple_assign_set_lhs (conv, tem);
+  gsi_insert_before (gsi, conv, GSI_SAME_STMT);
+  gimple_assign_set_rhs1 (stmt, tem);
+  update_stmt (stmt);
+
+  return true;
+}
+
 /* Simplify STMT using ranges if possible.  */
 
 static bool
@@ -7415,14 +7509,9 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
        {
        case EQ_EXPR:
        case NE_EXPR:
-       case TRUTH_NOT_EXPR:
-       case TRUTH_AND_EXPR:
-       case TRUTH_OR_EXPR:
-        case TRUTH_XOR_EXPR:
-          /* Transform EQ_EXPR, NE_EXPR, TRUTH_NOT_EXPR into BIT_XOR_EXPR
-            or identity if the RHS is zero or one, and the LHS are known
-            to be boolean values.  Transform all TRUTH_*_EXPR into
-             BIT_*_EXPR if both arguments are known to be boolean values.  */
+          /* Transform EQ_EXPR, NE_EXPR into BIT_XOR_EXPR or identity
+            if the RHS is zero or one, and the LHS are known to be boolean
+            values.  */
          if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
            return simplify_truth_ops_using_ranges (gsi, stmt);
          break;
@@ -7459,6 +7548,12 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
            return simplify_conversion_using_ranges (stmt);
          break;
 
+       case FLOAT_EXPR:
+         if (TREE_CODE (rhs1) == SSA_NAME
+             && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
+           return simplify_float_conversion_using_ranges (gsi, stmt);
+         break;
+
        default:
          break;
        }
@@ -7701,7 +7796,8 @@ static void
 vrp_finalize (void)
 {
   size_t i;
-  unsigned num = num_ssa_names;
+
+  values_propagated = true;
 
   if (dump_file)
     {
@@ -7721,7 +7817,7 @@ vrp_finalize (void)
   identify_jump_threads ();
 
   /* Free allocated memory.  */
-  for (i = 0; i < num; i++)
+  for (i = 0; i < num_vr_values; i++)
     if (vr_value[i])
       {
        BITMAP_FREE (vr_value[i]->equiv);
@@ -7793,6 +7889,9 @@ execute_vrp (void)
   rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
   scev_initialize ();
 
+  /* ???  This ends up using stale EDGE_DFS_BACK for liveness computation.
+     Inserting assertions may split edges which will invalidate
+     EDGE_DFS_BACK.  */
   insert_range_assertions ();
 
   /* Estimate number of iterations - but do not use undefined behavior
@@ -7805,6 +7904,9 @@ execute_vrp (void)
   to_update_switch_stmts = VEC_alloc (switch_update, heap, 5);
   threadedge_initialize_values ();
 
+  /* For visiting PHI nodes we need EDGE_DFS_BACK computed.  */
+  mark_dfs_back_edges ();
+
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
   vrp_finalize ();