OSDN Git Service

PR tree-optimization/23744
[pf3gnuchains/gcc-fork.git] / gcc / tree-vrp.c
index 1167e38..b55480e 100644 (file)
@@ -1,5 +1,5 @@
 /* Support routines for Value Range Propagation (VRP).
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>.
 
 This file is part of GCC.
@@ -41,10 +41,6 @@ Boston, MA 02110-1301, USA.  */
    sub-graph in find_assert_locations.  */
 static sbitmap found_in_subgraph;
 
-/* Loop structure of the program.  Used to analyze scalar evolutions
-   inside adjust_range_with_scev.  */
-static struct loops *cfg_loops;
-
 /* Local functions.  */
 static int compare_values (tree val1, tree val2);
 
@@ -95,36 +91,6 @@ static sbitmap blocks_visited;
 static value_range_t **vr_value;
 
 
-/* Return true if EXPR computes a non-zero value.  */
-
-bool
-expr_computes_nonzero (tree expr)
-{
-  /* Type casts won't change anything, so just strip them.  */
-  STRIP_NOPS (expr);
-
-  /* Calling alloca, guarantees that the value is non-NULL.  */
-  if (alloca_call_p (expr))
-    return true;
-
-  /* The address of a non-weak symbol is never NULL, unless the user
-     has requested not to remove NULL pointer checks.  */
-  if (flag_delete_null_pointer_checks
-      && TREE_CODE (expr) == ADDR_EXPR
-      && DECL_P (TREE_OPERAND (expr, 0))
-      && !DECL_WEAK (TREE_OPERAND (expr, 0)))
-    return true;
-
-  /* IOR of any value with a nonzero value will result in a nonzero
-     value.  */
-  if (TREE_CODE (expr) == BIT_IOR_EXPR
-      && integer_nonzerop (TREE_OPERAND (expr, 1)))
-    return true;
-
-  return false;
-}
-
-
 /* Return true if ARG is marked with the nonnull attribute in the
    current function signature.  */
 
@@ -225,6 +191,14 @@ copy_value_range (value_range_t *to, value_range_t *from)
   set_value_range (to, from->type, from->min, from->max, from->equiv);
 }
 
+/* Set value range VR to a non-negative range of type TYPE.  */
+
+static inline void
+set_value_range_to_nonnegative (value_range_t *vr, tree type)
+{
+  tree zero = build_int_cst (type, 0);
+  set_value_range (vr, VR_RANGE, zero, TYPE_MAX_VALUE (type), vr->equiv);
+}
 
 /* Set value range VR to a non-NULL range of type TYPE.  */
 
@@ -270,8 +244,10 @@ set_value_range_to_undefined (value_range_t *vr)
 }
 
 
-/* Return value range information for VAR.  Create an empty range
-   if none existed.  */
+/* Return value range information for VAR.  
+
+   If we have no values ranges recorded (ie, VRP is not running), then
+   return NULL.  Otherwise create an empty range if none existed for VAR.  */
 
 static value_range_t *
 get_value_range (tree var)
@@ -280,13 +256,16 @@ get_value_range (tree var)
   tree sym;
   unsigned ver = SSA_NAME_VERSION (var);
 
+  /* If we have no recorded ranges, then return NULL.  */
+  if (! vr_value)
+    return NULL;
+
   vr = vr_value[ver];
   if (vr)
     return vr;
 
   /* Create a default value range.  */
-  vr_value[ver] = vr = xmalloc (sizeof (*vr));
-  memset (vr, 0, sizeof (*vr));
+  vr_value[ver] = vr = XCNEW (value_range_t);
 
   /* Allocate an equivalence set.  */
   vr->equiv = BITMAP_ALLOC (NULL);
@@ -294,7 +273,7 @@ get_value_range (tree var)
   /* If VAR is a default definition, the variable can take any value
      in VAR's type.  */
   sym = SSA_NAME_VAR (var);
-  if (var == var_ann (sym)->default_def)
+  if (var == gimple_default_def (cfun, sym))
     {
       /* Try to use the "nonnull" attribute to create ~[0, 0]
         anti-ranges for pointers.  Note that this is only valid with
@@ -310,6 +289,25 @@ get_value_range (tree var)
   return vr;
 }
 
+/* Return true, if VAL1 and VAL2 are equal values for VRP purposes.  */
+
+static inline bool
+vrp_operand_equal_p (tree val1, tree val2)
+{
+  return (val1 == val2
+         || (val1 && val2
+             && operand_equal_p (val1, val2, 0)));
+}
+
+/* Return true, if the bitmaps B1 and B2 are equal.  */
+
+static inline bool
+vrp_bitmap_equal_p (bitmap b1, bitmap b2)
+{
+  return (b1 == b2
+         || (b1 && b2
+             && bitmap_equal_p (b1, b2)));
+}
 
 /* Update the value range and equivalence set for variable VAR to
    NEW_VR.  Return true if NEW_VR is different from VAR's previous
@@ -330,11 +328,9 @@ update_value_range (tree var, value_range_t *new_vr)
   /* Update the value range, if necessary.  */
   old_vr = get_value_range (var);
   is_new = old_vr->type != new_vr->type
-           || old_vr->min != new_vr->min
-          || old_vr->max != new_vr->max
-          || (old_vr->equiv == NULL && new_vr->equiv)
-          || (old_vr->equiv && new_vr->equiv == NULL)
-          || (!bitmap_equal_p (old_vr->equiv, new_vr->equiv));
+          || !vrp_operand_equal_p (old_vr->min, new_vr->min)
+          || !vrp_operand_equal_p (old_vr->max, new_vr->max)
+          || !vrp_bitmap_equal_p (old_vr->equiv, new_vr->equiv);
 
   if (is_new)
     set_value_range (old_vr, new_vr->type, new_vr->min, new_vr->max,
@@ -392,14 +388,22 @@ symbolic_range_p (value_range_t *vr)
           || !is_gimple_min_invariant (vr->max));
 }
 
+/* Like tree_expr_nonnegative_p, but this function uses value ranges
+   obtained so far.  */
+
+static bool
+vrp_expr_computes_nonnegative (tree expr)
+{
+  return tree_expr_nonnegative_p (expr);
+}
 
-/* Like expr_computes_nonzero, but this function uses value ranges
+/* Like tree_expr_nonzero_p, but this function uses value ranges
    obtained so far.  */
 
 static bool
 vrp_expr_computes_nonzero (tree expr)
 {
-  if (expr_computes_nonzero (expr))
+  if (tree_expr_nonzero_p (expr))
     return true;
 
   /* If we have an expression of the form &X->a, then the expression
@@ -421,6 +425,22 @@ vrp_expr_computes_nonzero (tree expr)
   return false;
 }
 
+/* Returns true if EXPR is a valid value (as expected by compare_values) --
+   a gimple invariant, or SSA_NAME +- CST.  */
+
+static bool
+valid_value_p (tree expr)
+{
+  if (TREE_CODE (expr) == SSA_NAME)
+    return true;
+
+  if (TREE_CODE (expr) == PLUS_EXPR
+      || TREE_CODE (expr) == MINUS_EXPR)
+    return (TREE_CODE (TREE_OPERAND (expr, 0)) == SSA_NAME
+           && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST);
+  
+  return is_gimple_min_invariant (expr);
+}
 
 /* Compare two values VAL1 and VAL2.  Return
    
@@ -444,37 +464,6 @@ compare_values (tree val1, tree val2)
   gcc_assert (POINTER_TYPE_P (TREE_TYPE (val1))
              == POINTER_TYPE_P (TREE_TYPE (val2)));
 
-  /* Do some limited symbolic comparisons.  */
-  if (!POINTER_TYPE_P (TREE_TYPE (val1)))
-    {
-      /* We can determine some comparisons against +INF and -INF even
-        if the other value is an expression.  */
-      if (val1 == TYPE_MAX_VALUE (TREE_TYPE (val1))
-         && TREE_CODE (val2) == MINUS_EXPR)
-       {
-         /* +INF > NAME - CST.  */
-         return 1;
-       }
-      else if (val1 == TYPE_MIN_VALUE (TREE_TYPE (val1))
-              && TREE_CODE (val2) == PLUS_EXPR)
-       {
-         /* -INF < NAME + CST.  */
-         return -1;
-       }
-      else if (TREE_CODE (val1) == MINUS_EXPR
-              && val2 == TYPE_MAX_VALUE (TREE_TYPE (val2)))
-       {
-         /* NAME - CST < +INF.  */
-         return -1;
-       }
-      else if (TREE_CODE (val1) == PLUS_EXPR
-              && val2 == TYPE_MIN_VALUE (TREE_TYPE (val2)))
-       {
-         /* NAME + CST > -INF.  */
-         return 1;
-       }
-    }
-
   if ((TREE_CODE (val1) == SSA_NAME
        || TREE_CODE (val1) == PLUS_EXPR
        || TREE_CODE (val1) == MINUS_EXPR)
@@ -483,69 +472,95 @@ compare_values (tree val1, tree val2)
          || TREE_CODE (val2) == MINUS_EXPR))
     {
       tree n1, c1, n2, c2;
+      enum tree_code code1, code2;
   
       /* If VAL1 and VAL2 are of the form 'NAME [+-] CST' or 'NAME',
         return -1 or +1 accordingly.  If VAL1 and VAL2 don't use the
         same name, return -2.  */
       if (TREE_CODE (val1) == SSA_NAME)
        {
+         code1 = SSA_NAME;
          n1 = val1;
          c1 = NULL_TREE;
        }
       else
        {
+         code1 = TREE_CODE (val1);
          n1 = TREE_OPERAND (val1, 0);
          c1 = TREE_OPERAND (val1, 1);
+         if (tree_int_cst_sgn (c1) == -1)
+           {
+             c1 = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (c1), c1);
+             if (!c1)
+               return -2;
+             code1 = code1 == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR;
+           }
        }
 
       if (TREE_CODE (val2) == SSA_NAME)
        {
+         code2 = SSA_NAME;
          n2 = val2;
          c2 = NULL_TREE;
        }
       else
        {
+         code2 = TREE_CODE (val2);
          n2 = TREE_OPERAND (val2, 0);
          c2 = TREE_OPERAND (val2, 1);
+         if (tree_int_cst_sgn (c2) == -1)
+           {
+             c2 = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (c2), c2);
+             if (!c2)
+               return -2;
+             code2 = code2 == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR;
+           }
        }
 
       /* Both values must use the same name.  */
       if (n1 != n2)
        return -2;
 
-      if (TREE_CODE (val1) == SSA_NAME)
+      if (code1 == SSA_NAME
+         && code2 == SSA_NAME)
+       /* NAME == NAME  */
+       return 0;
+
+      /* If overflow is defined we cannot simplify more.  */
+      if (TYPE_UNSIGNED (TREE_TYPE (val1))
+         || flag_wrapv)
+       return -2;
+
+      if (code1 == SSA_NAME)
        {
-         if (TREE_CODE (val2) == SSA_NAME)
-           /* NAME == NAME  */
-           return 0;
-         else if (TREE_CODE (val2) == PLUS_EXPR)
+         if (code2 == PLUS_EXPR)
            /* NAME < NAME + CST  */
            return -1;
-         else if (TREE_CODE (val2) == MINUS_EXPR)
+         else if (code2 == MINUS_EXPR)
            /* NAME > NAME - CST  */
            return 1;
        }
-      else if (TREE_CODE (val1) == PLUS_EXPR)
+      else if (code1 == PLUS_EXPR)
        {
-         if (TREE_CODE (val2) == SSA_NAME)
+         if (code2 == SSA_NAME)
            /* NAME + CST > NAME  */
            return 1;
-         else if (TREE_CODE (val2) == PLUS_EXPR)
+         else if (code2 == PLUS_EXPR)
            /* NAME + CST1 > NAME + CST2, if CST1 > CST2  */
            return compare_values (c1, c2);
-         else if (TREE_CODE (val2) == MINUS_EXPR)
+         else if (code2 == MINUS_EXPR)
            /* NAME + CST1 > NAME - CST2  */
            return 1;
        }
-      else if (TREE_CODE (val1) == MINUS_EXPR)
+      else if (code1 == MINUS_EXPR)
        {
-         if (TREE_CODE (val2) == SSA_NAME)
+         if (code2 == SSA_NAME)
            /* NAME - CST < NAME  */
            return -1;
-         else if (TREE_CODE (val2) == PLUS_EXPR)
+         else if (code2 == PLUS_EXPR)
            /* NAME - CST1 < NAME + CST2  */
            return -1;
-         else if (TREE_CODE (val2) == MINUS_EXPR)
+         else if (code2 == MINUS_EXPR)
            /* NAME - CST1 > NAME - CST2, if CST1 < CST2.  Notice that
               C1 and C2 are swapped in the call to compare_values.  */
            return compare_values (c2, c1);
@@ -558,12 +573,14 @@ compare_values (tree val1, tree val2)
   if (!is_gimple_min_invariant (val1) || !is_gimple_min_invariant (val2))
     return -2;
 
-  /* We cannot compare overflowed values.  */
-  if (TREE_OVERFLOW (val1) || TREE_OVERFLOW (val2))
-    return -2;
-
   if (!POINTER_TYPE_P (TREE_TYPE (val1)))
-    return tree_int_cst_compare (val1, val2);
+    {
+      /* We cannot compare overflowed values.  */
+      if (TREE_OVERFLOW (val1) || TREE_OVERFLOW (val2))
+       return -2;
+
+      return tree_int_cst_compare (val1, val2);
+    }
   else
     {
       tree t;
@@ -594,22 +611,38 @@ 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,
-        -2 if we cannot tell either way.  */
+        -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.  */
 
 static inline int
 value_inside_range (tree val, value_range_t *vr)
 {
-  int cmp1, cmp2;
+  tree cmp1, cmp2;
 
-  cmp1 = compare_values (val, vr->min);
-  if (cmp1 == -2 || cmp1 == 2)
+  cmp1 = fold_binary_to_constant (GE_EXPR, boolean_type_node, val, vr->min);
+  if (!cmp1)
     return -2;
 
-  cmp2 = compare_values (val, vr->max);
-  if (cmp2 == -2 || cmp2 == 2)
+  cmp2 = fold_binary_to_constant (LE_EXPR, boolean_type_node, val, vr->max);
+  if (!cmp2)
     return -2;
 
-  return (cmp1 == 0 || cmp1 == 1) && (cmp2 == -1 || cmp2 == 0);
+  return cmp1 == boolean_true_node && cmp2 == boolean_true_node;
 }
 
 
@@ -626,7 +659,11 @@ value_ranges_intersect_p (value_range_t *vr0, value_range_t *vr1)
 }
 
 
-/* Return true if VR includes the value zero, false otherwise.  */
+/* 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).  */
 
 static inline bool
 range_includes_zero_p (value_range_t *vr)
@@ -641,6 +678,50 @@ range_includes_zero_p (value_range_t *vr)
   return (value_inside_range (zero, vr) == 1);
 }
 
+/* Return true if T, an SSA_NAME, is known to be nonnegative.  Return
+   false otherwise or if no value range information is available.  */
+
+bool
+ssa_name_nonnegative_p (tree t)
+{
+  value_range_t *vr = get_value_range (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 (result == 0 || result == 1);
+    }
+  return false;
+}
+
+/* Return true if T, an SSA_NAME, is known to be nonzero.  Return
+   false otherwise or if no value range information is available.  */
+
+bool
+ssa_name_nonzero_p (tree t)
+{
+  value_range_t *vr = get_value_range (t);
+
+  if (!vr)
+    return false;
+
+  /* A VR_RANGE which does not include zero is a nonzero value.  */
+  if (vr->type == VR_RANGE && !symbolic_range_p (vr))
+    return ! range_includes_zero_p (vr);
+
+  /* A VR_ANTI_RANGE which does include zero is a nonzero value.  */
+  if (vr->type == VR_ANTI_RANGE && !symbolic_range_p (vr))
+    return range_includes_zero_p (vr);
+
+  return false;
+}
+
 
 /* Extract value range information from an ASSERT_EXPR EXPR and store
    it in *VR_P.  */
@@ -697,67 +778,11 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
          || symbolic_range_p (limit_vr)))
     limit_vr = NULL;
 
-  /* Special handling for integral types with super-types.  Some FEs
-     construct integral types derived from other types and restrict
-     the range of values these new types may take.
-
-     It may happen that LIMIT is actually smaller than TYPE's minimum
-     value.  For instance, the Ada FE is generating code like this
-     during bootstrap:
-
-           D.1480_32 = nam_30 - 300000361;
-           if (D.1480_32 <= 1) goto <L112>; else goto <L52>;
-           <L112>:;
-           D.1480_94 = ASSERT_EXPR <D.1480_32, D.1480_32 <= 1>;
-
-     All the names are of type types__name_id___XDLU_300000000__399999999
-     which has min == 300000000 and max == 399999999.  This means that
-     the ASSERT_EXPR would try to create the range [3000000, 1] which
-     is invalid.
-
-     The fact that the type specifies MIN and MAX values does not
-     automatically mean that every variable of that type will always
-     be within that range, so the predicate may well be true at run
-     time.  If we had symbolic -INF and +INF values, we could
-     represent this range, but we currently represent -INF and +INF
-     using the type's min and max values.
-        
-     So, the only sensible thing we can do for now is set the
-     resulting range to VR_VARYING.  TODO, would having symbolic -INF
-     and +INF values be worth the trouble?  */
-  if (TREE_CODE (limit) != SSA_NAME
-      && INTEGRAL_TYPE_P (type)
-      && TREE_TYPE (type))
-    {
-      if (cond_code == LE_EXPR || cond_code == LT_EXPR)
-       {
-         tree type_min = TYPE_MIN_VALUE (type);
-         int cmp = compare_values (limit, type_min);
-
-         /* For < or <= comparisons, if LIMIT is smaller than
-            TYPE_MIN, set the range to VR_VARYING.  */
-         if (cmp == -1 || cmp == 0)
-           {
-             set_value_range_to_varying (vr_p);
-             return;
-           }
-       }
-      else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
-       {
-         tree type_max = TYPE_MIN_VALUE (type);
-         int cmp = compare_values (limit, type_max);
-
-         /* For > or >= comparisons, if LIMIT is bigger than
-            TYPE_MAX, set the range to VR_VARYING.  */
-         if (cmp == 1 || cmp == 0)
-           {
-             set_value_range_to_varying (vr_p);
-             return;
-           }
-       }
-    }
-
-  /* The new range has the same set of equivalences of VAR's range.  */
+  /* Initially, the new range has the same set of equivalences of
+     VAR's range.  This will be revised before returning the final
+     value.  Since assertions may be chained via mutually exclusive
+     predicates, we will need to trim the set of equivalences before
+     we are done.  */
   gcc_assert (vr_p->equiv == NULL);
   vr_p->equiv = BITMAP_ALLOC (NULL);
   add_equivalence (vr_p->equiv, var);
@@ -804,17 +829,32 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
         LIMIT's range was ~[0, 0], the assertion 'VAR != LIMIT' does
         not imply that VAR's range is [0, 0].  So, in the case of
         anti-ranges, we just assert the inequality using LIMIT and
-        not its anti-range.  */
-      if (limit_vr == NULL
-         || limit_vr->type == VR_ANTI_RANGE)
+        not its anti-range.
+
+        If LIMIT_VR is a range, we can only use it to build a new
+        anti-range if LIMIT_VR is a single-valued range.  For
+        instance, if LIMIT_VR is [0, 1], the predicate
+        VAR != [0, 1] does not mean that VAR's range is ~[0, 1].
+        Rather, it means that for value 0 VAR should be ~[0, 0]
+        and for value 1, VAR should be ~[1, 1].  We cannot
+        represent these ranges.
+
+        The only situation in which we can build a valid
+        anti-range is when LIMIT_VR is a single-valued range
+        (i.e., LIMIT_VR->MIN == LIMIT_VR->MAX).  In that case, 
+        build the anti-range ~[LIMIT_VR->MIN, LIMIT_VR->MAX].  */
+      if (limit_vr
+         && limit_vr->type == VR_RANGE
+         && compare_values (limit_vr->min, limit_vr->max) == 0)
        {
-         min = limit;
-         max = limit;
+         min = limit_vr->min;
+         max = limit_vr->max;
        }
       else
        {
-         min = limit_vr->min;
-         max = limit_vr->max;
+         /* In any other case, we cannot use LIMIT's range to build a
+            valid anti-range.  */
+         min = max = limit;
        }
 
       /* If MIN and MAX cover the whole range for their type, then
@@ -840,14 +880,22 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
          max = limit_vr->max;
        }
 
-      /* For LT_EXPR, we create the range [MIN, MAX - 1].  */
-      if (cond_code == LT_EXPR)
+      /* If the maximum value forces us to be out of bounds, simply punt.
+        It would be pointless to try and do anything more since this
+        all should be optimized away above us.  */
+      if (cond_code == LT_EXPR && compare_values (max, min) == 0)
+       set_value_range_to_varying (vr_p);
+      else
        {
-         tree one = build_int_cst (type, 1);
-         max = fold_build2 (MINUS_EXPR, type, max, one);
-       }
+         /* 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);
+           }
 
-      set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+         set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+       }
     }
   else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
     {
@@ -863,41 +911,204 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
          min = limit_vr->min;
        }
 
-      /* For GT_EXPR, we create the range [MIN + 1, MAX].  */
-      if (cond_code == GT_EXPR)
+      /* If the minimum value forces us to be out of bounds, simply punt.
+        It would be pointless to try and do anything more since this
+        all should be optimized away above us.  */
+      if (cond_code == GT_EXPR && compare_values (min, max) == 0)
+       set_value_range_to_varying (vr_p);
+      else
        {
-         tree one = build_int_cst (type, 1);
-         min = fold_build2 (PLUS_EXPR, type, min, one);
-       }
+         /* 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);
+           }
 
-      set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+         set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+       }
     }
   else
     gcc_unreachable ();
 
-  /* If VAR already had a known range and the two ranges have a
-     non-empty intersection, we can refine the resulting range.
-     Since the assert expression creates an equivalency and at the
-     same time it asserts a predicate, we can take the intersection of
-     the two ranges to get better precision.  */
+  /* If VAR already had a known range, it may happen that the new
+     range we have computed and VAR's range are not compatible.  For
+     instance,
+
+       if (p_5 == NULL)
+         p_6 = ASSERT_EXPR <p_5, p_5 == NULL>;
+         x_7 = p_6->fld;
+         p_8 = ASSERT_EXPR <p_6, p_6 != NULL>;
+
+     While the above comes from a faulty program, it will cause an ICE
+     later because p_8 and p_6 will have incompatible ranges and at
+     the same time will be considered equivalent.  A similar situation
+     would arise from
+
+       if (i_5 > 10)
+         i_6 = ASSERT_EXPR <i_5, i_5 > 10>;
+         if (i_5 < 5)
+           i_7 = ASSERT_EXPR <i_6, i_6 < 5>;
+
+     Again i_6 and i_7 will have incompatible ranges.  It would be
+     pointless to try and do anything with i_7's range because
+     anything dominated by 'if (i_5 < 5)' will be optimized away.
+     Note, due to the wa in which simulation proceeds, the statement
+     i_7 = ASSERT_EXPR <...> we would never be visited because the
+     conditional 'if (i_5 < 5)' always evaluates to false.  However,
+     this extra check does not hurt and may protect against future
+     changes to VRP that may get into a situation similar to the
+     NULL pointer dereference example.
+
+     Note that these compatibility tests are only needed when dealing
+     with ranges or a mix of range and anti-range.  If VAR_VR and VR_P
+     are both anti-ranges, they will always be compatible, because two
+     anti-ranges will always have a non-empty intersection.  */
+
   var_vr = get_value_range (var);
-  if (var_vr->type == VR_RANGE
-      && vr_p->type == VR_RANGE
-      && value_ranges_intersect_p (var_vr, vr_p))
+
+  /* We may need to make adjustments when VR_P and VAR_VR are numeric
+     ranges or anti-ranges.  */
+  if (vr_p->type == VR_VARYING
+      || vr_p->type == VR_UNDEFINED
+      || var_vr->type == VR_VARYING
+      || var_vr->type == VR_UNDEFINED
+      || symbolic_range_p (vr_p)
+      || symbolic_range_p (var_vr))
+    return;
+
+  if (var_vr->type == VR_RANGE && vr_p->type == VR_RANGE)
     {
-      /* Use the larger of the two minimums.  */
-      if (compare_values (vr_p->min, var_vr->min) == -1)
-       min = var_vr->min;
-      else
-       min = vr_p->min;
+      /* If the two ranges have a non-empty intersection, we can
+        refine the resulting range.  Since the assert expression
+        creates an equivalency and at the same time it asserts a
+        predicate, we can take the intersection of the two ranges to
+        get better precision.  */
+      if (value_ranges_intersect_p (var_vr, vr_p))
+       {
+         /* Use the larger of the two minimums.  */
+         if (compare_values (vr_p->min, var_vr->min) == -1)
+           min = var_vr->min;
+         else
+           min = vr_p->min;
 
-      /* Use the smaller of the two maximums.  */
-      if (compare_values (vr_p->max, var_vr->max) == 1)
-       max = var_vr->max;
+         /* Use the smaller of the two maximums.  */
+         if (compare_values (vr_p->max, var_vr->max) == 1)
+           max = var_vr->max;
+         else
+           max = vr_p->max;
+
+         set_value_range (vr_p, vr_p->type, min, max, vr_p->equiv);
+       }
+      else
+       {
+         /* The two ranges do not intersect, set the new range to
+            VARYING, because we will not be able to do anything
+            meaningful with it.  */
+         set_value_range_to_varying (vr_p);
+       }
+    }
+  else if ((var_vr->type == VR_RANGE && vr_p->type == VR_ANTI_RANGE)
+           || (var_vr->type == VR_ANTI_RANGE && vr_p->type == VR_RANGE))
+    {
+      /* A range and an anti-range will cancel each other only if
+        their ends are the same.  For instance, in the example above,
+        p_8's range ~[0, 0] and p_6's range [0, 0] are incompatible,
+        so VR_P should be set to VR_VARYING.  */
+      if (compare_values (var_vr->min, vr_p->min) == 0
+         && compare_values (var_vr->max, vr_p->max) == 0)
+       set_value_range_to_varying (vr_p);
       else
-       max = vr_p->max;
+       {
+         tree min, max, anti_min, anti_max, real_min, real_max;
+
+         /* We want to compute the logical AND of the two ranges;
+            there are three cases to consider.
 
-      set_value_range (vr_p, vr_p->type, min, max, vr_p->equiv);
+
+            1. The VR_ANTI_RANGE range is completely within the 
+               VR_RANGE and the endpoints of the ranges are
+               different.  In that case the resulting range
+               should be whichever range is more precise.
+               Typically that will be the VR_RANGE.
+
+            2. The VR_ANTI_RANGE is completely disjoint from
+               the VR_RANGE.  In this case the resulting range
+               should be the VR_RANGE.
+
+            3. There is some overlap between the VR_ANTI_RANGE
+               and the VR_RANGE.
+
+               3a. If the high limit of the VR_ANTI_RANGE resides
+                   within the VR_RANGE, then the result is a new
+                   VR_RANGE starting at the high limit of the
+                   the VR_ANTI_RANGE + 1 and extending to the
+                   high limit of the original VR_RANGE.
+
+               3b. If the low limit of the VR_ANTI_RANGE resides
+                   within the VR_RANGE, then the result is a new
+                   VR_RANGE starting at the low limit of the original
+                   VR_RANGE and extending to the low limit of the
+                   VR_ANTI_RANGE - 1.  */
+         if (vr_p->type == VR_ANTI_RANGE)
+           {
+             anti_min = vr_p->min;
+             anti_max = vr_p->max;
+             real_min = var_vr->min;
+             real_max = var_vr->max;
+           }
+         else
+           {
+             anti_min = var_vr->min;
+             anti_max = var_vr->max;
+             real_min = vr_p->min;
+             real_max = vr_p->max;
+           }
+
+
+         /* Case 1, VR_ANTI_RANGE completely within VR_RANGE,
+            not including any endpoints.  */
+         if (compare_values (anti_max, real_max) == -1
+             && compare_values (anti_min, real_min) == 1)
+           {
+             set_value_range (vr_p, VR_RANGE, real_min,
+                              real_max, vr_p->equiv);
+           }
+         /* Case 2, VR_ANTI_RANGE completely disjoint from
+            VR_RANGE.  */
+         else if (compare_values (anti_min, real_max) == 1
+                  || compare_values (anti_max, real_min) == -1)
+           {
+             set_value_range (vr_p, VR_RANGE, real_min,
+                              real_max, vr_p->equiv);
+           }
+         /* Case 3a, the anti-range extends into the low
+            part of the real range.  Thus creating a new
+            low for the real range.  */
+         else if ((compare_values (anti_max, real_min) == 1
+                   || compare_values (anti_max, real_min) == 0)
+                  && compare_values (anti_max, real_max) == -1)
+           {
+             min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+                                anti_max,
+                                build_int_cst (TREE_TYPE (var_vr->min), 1));
+             max = real_max;
+             set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+           }
+         /* Case 3b, the anti-range extends into the high
+            part of the real range.  Thus creating a new
+            higher for the real range.  */
+         else if (compare_values (anti_min, real_min) == 1
+                  && (compare_values (anti_min, real_max) == -1
+                      || compare_values (anti_min, real_max) == 0))
+           {
+             max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+                                anti_min,
+                                build_int_cst (TREE_TYPE (var_vr->min), 1));
+             min = real_min;
+             set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+           }
+       }
     }
 }
 
@@ -938,20 +1149,55 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
 {
   tree res;
 
-  if (flag_wrapv)
-    return int_const_binop (code, val1, val2, 0);
+  res = int_const_binop (code, val1, val2, 0);
 
   /* If we are not using wrapping arithmetic, operate symbolically
      on -INF and +INF.  */
-  res = int_const_binop (code, val1, val2, 0);
+  if (TYPE_UNSIGNED (TREE_TYPE (val1))
+      || flag_wrapv)
+    {
+      int checkz = compare_values (res, val1);
+      bool overflow = false;
+
+      /* Ensure that res = val1 [+*] val2 >= val1
+         or that res = val1 - val2 <= val1.  */
+      if ((code == PLUS_EXPR
+          && !(checkz == 1 || checkz == 0))
+          || (code == MINUS_EXPR
+             && !(checkz == 0 || checkz == -1)))
+       {
+         overflow = true;
+       }
+      /* Checking for multiplication overflow is done by dividing the
+        output of the multiplication by the first input of the
+        multiplication.  If the result of that division operation is
+        not equal to the second input of the multiplication, then the
+        multiplication overflowed.  */
+      else if (code == MULT_EXPR && !integer_zerop (val1))
+       {
+         tree tmp = int_const_binop (TRUNC_DIV_EXPR,
+                                     res,
+                                     val1, 0);
+         int check = compare_values (tmp, val2);
+
+         if (check != 0)
+           overflow = true;
+       }
 
-  /* If the operation overflowed but neither VAL1 nor VAL2 are
-     overflown, return -INF or +INF depending on the operation
-     and the combination of signs of the operands.  */
-  if (TREE_OVERFLOW (res)
-      && !TREE_OVERFLOW (val1)
-      && !TREE_OVERFLOW (val2))
+      if (overflow)
+       {
+         res = copy_node (res);
+         TREE_OVERFLOW (res) = 1;
+       }
+
+    }
+  else if (TREE_OVERFLOW (res)
+          && !TREE_OVERFLOW (val1)
+          && !TREE_OVERFLOW (val2))
     {
+      /* If the operation overflowed but neither VAL1 nor VAL2 are
+        overflown, return -INF or +INF depending on the operation
+        and the combination of signs of the operands.  */
       int sgn1 = tree_int_cst_sgn (val1);
       int sgn2 = tree_int_cst_sgn (val2);
 
@@ -973,8 +1219,10 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
          /* For subtraction, the operands must be of different
             signs to yield an overflow.  Its sign is therefore
             that of the first operand or the opposite of that
-            of the second operand.  */
-         || (code == MINUS_EXPR && sgn1 > 0)
+            of the second operand.  A first operand of 0 counts
+            as positive here, for the corner case 0 - (-INF),
+            which overflows, but must yield +INF.  */
+         || (code == MINUS_EXPR && sgn1 >= 0)
          /* For division, the only case is -INF / -1 = +INF.  */
          || code == TRUNC_DIV_EXPR
          || code == FLOOR_DIV_EXPR
@@ -997,6 +1245,7 @@ static void
 extract_range_from_binary_expr (value_range_t *vr, tree expr)
 {
   enum tree_code code = TREE_CODE (expr);
+  enum value_range_type type;
   tree op0, op1, min, max;
   int cmp;
   value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
@@ -1014,11 +1263,11 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
       && code != ROUND_DIV_EXPR
       && code != MIN_EXPR
       && code != MAX_EXPR
+      && code != BIT_AND_EXPR
       && code != TRUTH_ANDIF_EXPR
       && code != TRUTH_ORIF_EXPR
       && code != TRUTH_AND_EXPR
-      && code != TRUTH_OR_EXPR
-      && code != TRUTH_XOR_EXPR)
+      && code != TRUTH_OR_EXPR)
     {
       set_value_range_to_varying (vr);
       return;
@@ -1049,14 +1298,22 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
       return;
     }
 
+  /* The type of the resulting value range defaults to VR0.TYPE.  */
+  type = vr0.type;
+
   /* Refuse to operate on VARYING ranges, ranges of different kinds
-     and symbolic ranges.  TODO, we may be able to derive anti-ranges
-     in some cases.  */
-  if (vr0.type == VR_VARYING
-      || vr1.type == VR_VARYING
-      || vr0.type != vr1.type
-      || symbolic_range_p (&vr0)
-      || symbolic_range_p (&vr1))
+     and symbolic ranges.  As an exception, we allow BIT_AND_EXPR
+     because we may be able to derive a useful range even if one of
+     the operands is VR_VARYING or symbolic range.  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
+      && (vr0.type == VR_VARYING
+         || vr1.type == VR_VARYING
+         || vr0.type != vr1.type
+         || symbolic_range_p (&vr0)
+         || symbolic_range_p (&vr1)))
     {
       set_value_range_to_varying (vr);
       return;
@@ -1096,12 +1353,49 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
   if (code == TRUTH_ANDIF_EXPR
       || code == TRUTH_ORIF_EXPR
       || code == TRUTH_AND_EXPR
-      || code == TRUTH_OR_EXPR
-      || code == TRUTH_XOR_EXPR)
+      || code == TRUTH_OR_EXPR)
     {
-      /* Boolean expressions cannot be folded with int_const_binop.  */
-      min = fold_binary (code, TREE_TYPE (expr), vr0.min, vr1.min);
-      max = fold_binary (code, TREE_TYPE (expr), vr0.max, vr1.max);
+      /* 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 (TREE_TYPE (expr), 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 (TREE_TYPE (expr), 1);
+       }
+      else if (vr0.type != VR_VARYING
+              && vr1.type != VR_VARYING
+              && vr0.type == vr1.type
+              && !symbolic_range_p (&vr0)
+              && !symbolic_range_p (&vr1))
+       {
+         /* Boolean expressions cannot be folded with int_const_binop.  */
+         min = fold_binary (code, TREE_TYPE (expr), vr0.min, vr1.min);
+         max = fold_binary (code, TREE_TYPE (expr), vr0.max, vr1.max);
+       }
+      else
+       {
+         set_value_range_to_varying (vr);
+         return;
+       }
     }
   else if (code == PLUS_EXPR
           || code == MIN_EXPR
@@ -1166,7 +1460,8 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
         the new range.  */
 
       /* Divisions by zero result in a VARYING value.  */
-      if (code != MULT_EXPR && range_includes_zero_p (&vr1))
+      if (code != MULT_EXPR
+         && (vr0.type == VR_ANTI_RANGE || range_includes_zero_p (&vr1)))
        {
          set_value_range_to_varying (vr);
          return;
@@ -1183,7 +1478,7 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
               ? vrp_int_const_binop (code, vr0.max, vr1.min)
               : NULL_TREE;
 
-      val[3] = (vr0.min != vr1.min && vr0.max != vr1.max)
+      val[3] = (vr0.min != vr0.max && vr1.min != vr1.max)
               ? vrp_int_const_binop (code, vr0.max, vr1.max)
               : NULL_TREE;
 
@@ -1193,12 +1488,13 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
       max = val[0];
       for (i = 1; i < 4; i++)
        {
-         if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max))
+         if (!is_gimple_min_invariant (min) || TREE_OVERFLOW (min)
+             || !is_gimple_min_invariant (max) || TREE_OVERFLOW (max))
            break;
 
          if (val[i])
            {
-             if (TREE_OVERFLOW (val[i]))
+             if (!is_gimple_min_invariant (val[i]) || TREE_OVERFLOW (val[i]))
                {
                  /* If we found an overflowed value, set MIN and MAX
                     to it so that we set the resulting range to
@@ -1235,12 +1531,38 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
       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)
+    {
+      if (vr0.type == VR_RANGE
+         && vr0.min == vr0.max
+         && tree_expr_nonnegative_p (vr0.max)
+         && TREE_CODE (vr0.max) == INTEGER_CST)
+       {
+         min = build_int_cst (TREE_TYPE (expr), 0);
+         max = vr0.max;
+       }
+      else if (vr1.type == VR_RANGE
+         && vr1.min == vr1.max
+         && tree_expr_nonnegative_p (vr1.max)
+         && TREE_CODE (vr1.max) == INTEGER_CST)
+       {
+         type = VR_RANGE;
+         min = build_int_cst (TREE_TYPE (expr), 0);
+         max = vr1.max;
+       }
+      else
+       {
+         set_value_range_to_varying (vr);
+         return;
+       }
+    }
   else
     gcc_unreachable ();
 
   /* If either MIN or MAX overflowed, then set the resulting range to
      VARYING.  */
-  if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max))
+  if (!is_gimple_min_invariant (min) || TREE_OVERFLOW (min)
+      || !is_gimple_min_invariant (max) || TREE_OVERFLOW (max))
     {
       set_value_range_to_varying (vr);
       return;
@@ -1255,7 +1577,7 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
       set_value_range_to_varying (vr);
     }
   else
-    set_value_range (vr, vr0.type, min, max, NULL);
+    set_value_range (vr, type, min, max, NULL);
 }
 
 
@@ -1273,9 +1595,6 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
   /* Refuse to operate on certain unary expressions for which we
      cannot easily determine a resulting range.  */
   if (code == FIX_TRUNC_EXPR
-      || code == FIX_CEIL_EXPR
-      || code == FIX_FLOOR_EXPR
-      || code == FIX_ROUND_EXPR
       || code == FLOAT_EXPR
       || code == BIT_NOT_EXPR
       || code == NON_LVALUE_EXPR
@@ -1302,14 +1621,12 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
       return;
     }
 
-  /* Refuse to operate on varying and symbolic ranges.  Also, if the
-     operand is neither a pointer nor an integral type, set the
-     resulting range to VARYING.  TODO, in some cases we may be able
-     to derive anti-ranges (like non-zero values).  */
-  if (vr0.type == VR_VARYING
-      || (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
-         && !POINTER_TYPE_P (TREE_TYPE (op0)))
-      || symbolic_range_p (&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)))
     {
       set_value_range_to_varying (vr);
       return;
@@ -1319,7 +1636,7 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
      determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]).  */
   if (POINTER_TYPE_P (TREE_TYPE (expr)) || POINTER_TYPE_P (TREE_TYPE (op0)))
     {
-      if (range_is_nonnull (&vr0) || expr_computes_nonzero (expr))
+      if (range_is_nonnull (&vr0) || tree_expr_nonzero_p (expr))
        set_value_range_to_nonnull (vr, TREE_TYPE (expr));
       else if (range_is_null (&vr0))
        set_value_range_to_null (vr, TREE_TYPE (expr));
@@ -1342,22 +1659,38 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
         or equal to the new max, then we can safely use the newly
         computed range for EXPR.  This allows us to compute
         accurate ranges through many casts.  */
-      if (vr0.type == VR_RANGE)
+      if (vr0.type == VR_RANGE
+         || (vr0.type == VR_VARYING
+             && TYPE_PRECISION (outer_type) > TYPE_PRECISION (inner_type)))
        {
-         tree new_min, new_max;
+         tree new_min, new_max, orig_min, orig_max;
 
-         /* Convert VR0's min/max to OUTER_TYPE.  */
-         new_min = fold_convert (outer_type, vr0.min);
-         new_max = fold_convert (outer_type, vr0.max);
+         /* Convert the input operand min/max to OUTER_TYPE.   If
+            the input has no range information, then use the min/max
+            for the input's type.  */
+         if (vr0.type == VR_RANGE)
+           {
+             orig_min = vr0.min;
+             orig_max = vr0.max;
+           }
+         else
+           {
+             orig_min = TYPE_MIN_VALUE (inner_type);
+             orig_max = TYPE_MAX_VALUE (inner_type);
+           }
+
+         new_min = fold_convert (outer_type, orig_min);
+         new_max = fold_convert (outer_type, orig_max);
 
          /* Verify the new min/max values are gimple values and
-            that they compare equal to VR0's min/max values.  */
+            that they compare equal to the original input's
+            min/max values.  */
          if (is_gimple_val (new_min)
              && is_gimple_val (new_max)
-             && tree_int_cst_equal (new_min, vr0.min)
-             && tree_int_cst_equal (new_max, vr0.max)
+             && tree_int_cst_equal (new_min, orig_min)
+             && tree_int_cst_equal (new_max, orig_max)
              && compare_values (new_min, new_max) <= 0
-             && compare_values (new_min, new_max) >= -2)
+             && compare_values (new_min, new_max) >= -1)
            {
              set_value_range (vr, VR_RANGE, new_min, new_max, vr->equiv);
              return;
@@ -1378,32 +1711,71 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
        }
     }
 
+  /* 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)
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+
   /* Apply the operation to each end of the range and see what we end
      up with.  */
   if (code == NEGATE_EXPR
       && !TYPE_UNSIGNED (TREE_TYPE (expr)))
     {
-      /* Negating an anti-range doesn't really do anything to it.  The
-        new range will also not take on the same range of values
-        excluded by the original anti-range.  */
-      if (vr0.type == VR_ANTI_RANGE)
-       {
-         copy_value_range (vr, &vr0);
-         return;
-       }
-
-      /* NEGATE_EXPR flips the range around.  */
-      min = (vr0.max == TYPE_MAX_VALUE (TREE_TYPE (expr)))
+      /* NEGATE_EXPR flips the range around.  We need to treat
+        TYPE_MIN_VALUE specially dependent on wrapping, range type
+        and if it was used as minimum or maximum value:  
+         -~[MIN, MIN] == ~[MIN, MIN]
+         -[MIN, 0] == [0, MAX]  for -fno-wrapv
+         -[MIN, 0] == [0, MIN]  for -fwrapv (will be set to varying later)  */
+      min = vr0.max == TYPE_MIN_VALUE (TREE_TYPE (expr))
            ? TYPE_MIN_VALUE (TREE_TYPE (expr))
            : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
 
-      max = (vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr)))
-           ? TYPE_MAX_VALUE (TREE_TYPE (expr))
+      max = vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr))
+           ? (vr0.type == VR_ANTI_RANGE || flag_wrapv
+              ? TYPE_MIN_VALUE (TREE_TYPE (expr))
+              : TYPE_MAX_VALUE (TREE_TYPE (expr)))
            : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
+
+    }
+  else if (code == NEGATE_EXPR
+          && TYPE_UNSIGNED (TREE_TYPE (expr)))
+    {
+      if (!range_includes_zero_p (&vr0))
+       {
+         max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
+         min = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
+       }
+      else
+       {
+         if (range_is_null (&vr0))
+           set_value_range_to_null (vr, TREE_TYPE (expr));
+         else
+           set_value_range_to_varying (vr);
+         return;
+       }
     }
   else if (code == ABS_EXPR
            && !TYPE_UNSIGNED (TREE_TYPE (expr)))
     {
+      /* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a
+         useful range.  */
+      if (flag_wrapv
+         && ((vr0.type == VR_RANGE
+              && vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr)))
+             || (vr0.type == VR_ANTI_RANGE
+                 && vr0.min != TYPE_MIN_VALUE (TREE_TYPE (expr))
+                 && !range_includes_zero_p (&vr0))))
+       {
+         set_value_range_to_varying (vr);
+         return;
+       }
+       
       /* ABS_EXPR may flip the range around, if the original range
         included negative values.  */
       min = (vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr)))
@@ -1412,12 +1784,58 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
 
       max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
 
-      /* If the range was reversed, swap MIN and MAX.  */
-      if (compare_values (min, max) == 1)
+      cmp = compare_values (min, max);
+
+      /* If a VR_ANTI_RANGEs contains zero, then we have
+        ~[-INF, min(MIN, MAX)].  */
+      if (vr0.type == VR_ANTI_RANGE)
+       { 
+         if (range_includes_zero_p (&vr0))
+           {
+             tree type_min_value = TYPE_MIN_VALUE (TREE_TYPE (expr));
+
+             /* Take the lower of the two values.  */
+             if (cmp != 1)
+               max = min;
+
+             /* Create ~[-INF, min (abs(MIN), abs(MAX))]
+                or ~[-INF + 1, min (abs(MIN), abs(MAX))] when
+                flag_wrapv is set and the original anti-range doesn't include
+                TYPE_MIN_VALUE, remember -TYPE_MIN_VALUE = TYPE_MIN_VALUE.  */
+             min = (flag_wrapv && vr0.min != type_min_value
+                    ? int_const_binop (PLUS_EXPR,
+                                       type_min_value,
+                                       integer_one_node, 0)
+                    : type_min_value);
+           }
+         else
+           {
+             /* All else has failed, so create the range [0, INF], even for
+                flag_wrapv since TYPE_MIN_VALUE is in the original
+                anti-range.  */
+             vr0.type = VR_RANGE;
+             min = build_int_cst (TREE_TYPE (expr), 0);
+             max = TYPE_MAX_VALUE (TREE_TYPE (expr));
+           }
+       }
+
+      /* 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))
        {
-         tree t = min;
-         min = max;
-         max = t;
+         if (cmp == 1)
+           max = min;
+         min = build_int_cst (TREE_TYPE (expr), 0);
+       }
+      else
+       {
+          /* If the range was reversed, swap MIN and MAX.  */
+         if (cmp == 1)
+           {
+             tree t = min;
+             min = max;
+             max = t;
+           }
        }
     }
   else
@@ -1483,12 +1901,23 @@ extract_range_from_expr (value_range_t *vr, tree expr)
     extract_range_from_unary_expr (vr, expr);
   else if (TREE_CODE_CLASS (code) == tcc_comparison)
     extract_range_from_comparison (vr, expr);
-  else if (vrp_expr_computes_nonzero (expr))
-    set_value_range_to_nonnull (vr, TREE_TYPE (expr));
   else if (is_gimple_min_invariant (expr))
     set_value_range (vr, VR_RANGE, expr, expr, NULL);
   else
     set_value_range_to_varying (vr);
+
+  /* If we got a varying range from the tests above, try a final
+     time to derive a nonnegative or nonzero range.  This time
+     relying primarily on generic routines in fold in conjunction
+     with range data.  */
+  if (vr->type == VR_VARYING)
+    {
+      if (INTEGRAL_TYPE_P (TREE_TYPE (expr))
+         && vrp_expr_computes_nonnegative (expr))
+        set_value_range_to_nonnegative (vr, TREE_TYPE (expr));
+      else if (vrp_expr_computes_nonzero (expr))
+        set_value_range_to_nonnull (vr, TREE_TYPE (expr));
+    }
 }
 
 /* Given a range VR, a LOOP and a variable VAR, determine whether it
@@ -1499,50 +1928,78 @@ static void
 adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
                        tree var)
 {
-  tree init, step, chrec;
-  bool init_is_max;
+  tree init, step, chrec, tmin, tmax, min, max, type;
+  enum ev_direction dir;
 
   /* TODO.  Don't adjust anti-ranges.  An anti-range may provide
      better opportunities than a regular range, but I'm not sure.  */
   if (vr->type == VR_ANTI_RANGE)
     return;
 
-  chrec = analyze_scalar_evolution (loop, var);
+  chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
   if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
     return;
 
-  init = CHREC_LEFT (chrec);
-  step = CHREC_RIGHT (chrec);
+  init = initial_condition_in_loop_num (chrec, loop->num);
+  step = evolution_part_in_loop_num (chrec, loop->num);
 
   /* If STEP is symbolic, we can't know whether INIT will be the
-     minimum or maximum value in the range.  */
-  if (!is_gimple_min_invariant (step))
+     minimum or maximum value in the range.  Also, unless INIT is
+     a simple expression, compare_values and possibly other functions
+     in tree-vrp won't be able to handle it.  */
+  if (step == NULL_TREE
+      || !is_gimple_min_invariant (step)
+      || !valid_value_p (init))
     return;
 
-  /* Do not adjust ranges when chrec may wrap.  */
-  if (scev_probably_wraps_p (chrec_type (chrec), init, step, stmt,
-                            cfg_loops->parray[CHREC_VARIABLE (chrec)],
-                            &init_is_max))
+  dir = scev_direction (chrec);
+  if (/* Do not adjust ranges if we do not know whether the iv increases
+        or decreases,  ... */
+      dir == EV_DIR_UNKNOWN
+      /* ... or if it may wrap.  */
+      || scev_probably_wraps_p (init, step, stmt,
+                               current_loops->parray[CHREC_VARIABLE (chrec)],
+                               true))
     return;
 
-  if (!POINTER_TYPE_P (TREE_TYPE (init))
-      && (vr->type == VR_VARYING || vr->type == VR_UNDEFINED))
+  type = TREE_TYPE (var);
+  if (POINTER_TYPE_P (type) || !TYPE_MIN_VALUE (type))
+    tmin = lower_bound_in_type (type, type);
+  else
+    tmin = TYPE_MIN_VALUE (type);
+  if (POINTER_TYPE_P (type) || !TYPE_MAX_VALUE (type))
+    tmax = upper_bound_in_type (type, type);
+  else
+    tmax = TYPE_MAX_VALUE (type);
+
+  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
     {
+      min = tmin;
+      max = tmax;
+
       /* For VARYING or UNDEFINED ranges, just about anything we get
         from scalar evolutions should be better.  */
-      if (init_is_max)
-       set_value_range (vr, VR_RANGE, TYPE_MIN_VALUE (TREE_TYPE (init)),
-                        init, vr->equiv);
+
+      if (dir == EV_DIR_DECREASES)
+       max = init;
       else
-       set_value_range (vr, VR_RANGE, init, TYPE_MAX_VALUE (TREE_TYPE (init)),
-                        vr->equiv);
+       min = init;
+
+      /* If we would create an invalid range, then just assume we
+        know absolutely nothing.  This may be over-conservative,
+        but it's clearly safe, and should happen only in unreachable
+         parts of code, or for invalid programs.  */
+      if (compare_values (min, max) == 1)
+       return;
+
+      set_value_range (vr, VR_RANGE, min, max, vr->equiv);
     }
   else if (vr->type == VR_RANGE)
     {
-      tree min = vr->min;
-      tree max = vr->max;
+      min = vr->min;
+      max = vr->max;
 
-      if (init_is_max)
+      if (dir == EV_DIR_DECREASES)
        {
          /* INIT is the maximum value.  If INIT is lower than VR->MAX
             but no smaller than VR->MIN, set VR->MAX to INIT.  */
@@ -1551,10 +2008,11 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
              max = init;
 
              /* If we just created an invalid range with the minimum
-                greater than the maximum, take the minimum all the
-                way to -INF.  */
+                greater than the maximum, we fail conservatively.
+                This should happen only in unreachable
+                parts of code, or for invalid programs.  */
              if (compare_values (min, max) == 1)
-               min = TYPE_MIN_VALUE (TREE_TYPE (min));
+               return;
            }
        }
       else
@@ -1564,11 +2022,9 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
            {
              min = init;
 
-             /* If we just created an invalid range with the minimum
-                greater than the maximum, take the maximum all the
-                way to +INF.  */
+             /* Again, avoid creating invalid range by failing.  */
              if (compare_values (min, max) == 1)
-               max = TYPE_MAX_VALUE (TREE_TYPE (max));
+               return;
            }
        }
 
@@ -1657,6 +2113,10 @@ compare_ranges (enum tree_code comp, value_range_t *vr0, value_range_t *vr1)
          else if (cmp_min != -2 && cmp_max != -2)
            return boolean_false_node;
        }
+      /* If [V0_MIN, V1_MAX] < [V1_MIN, V1_MAX] then V0 != V1.  */
+      else if (compare_values (vr0->min, vr1->max) == 1
+              || compare_values (vr1->min, vr0->max) == 1)
+       return boolean_false_node;
 
       return NULL_TREE;
     }
@@ -1733,9 +2193,8 @@ compare_range_with_value (enum tree_code comp, value_range_t *vr, tree val)
          || comp == LE_EXPR)
        return NULL_TREE;
 
-      /* ~[VAL, VAL] == VAL is always false.  */
-      if (compare_values (vr->min, val) == 0
-         && compare_values (vr->max, val) == 0)
+      /* ~[VAL_1, VAL_2] OP VAL is known if VAL_1 <= VAL <= VAL_2.  */
+      if (value_inside_range (val, vr) == 1)
        return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
 
       return NULL_TREE;
@@ -1890,6 +2349,7 @@ void
 debug_value_range (value_range_t *vr)
 {
   dump_value_range (stderr, vr);
+  fprintf (stderr, "\n");
 }
 
 
@@ -1938,21 +2398,21 @@ build_assert_expr_for (tree cond, tree v)
 
   if (COMPARISON_CLASS_P (cond))
     {
-      tree a = build (ASSERT_EXPR, TREE_TYPE (v), v, cond); 
-      assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, a);
+      tree a = build2 (ASSERT_EXPR, TREE_TYPE (v), v, cond); 
+      assertion = build2 (MODIFY_EXPR, TREE_TYPE (v), 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 = build (MODIFY_EXPR, TREE_TYPE (v), n, boolean_false_node);
+      assertion = build2 (MODIFY_EXPR, TREE_TYPE (v), n, boolean_false_node);
     }
   else if (TREE_CODE (cond) == SSA_NAME)
     {
       /* Given V, build the assignment N = true.  */
       gcc_assert (v == cond);
-      assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, boolean_true_node);
+      assertion = build2 (MODIFY_EXPR, TREE_TYPE (v), n, boolean_true_node);
     }
   else
     gcc_unreachable ();
@@ -2001,16 +2461,23 @@ infer_value_range (tree stmt, tree op, enum tree_code *comp_code_p, tree *val_p)
   if (tree_could_throw_p (stmt))
     return false;
 
-  if (POINTER_TYPE_P (TREE_TYPE (op)))
+  /* If STMT is the last statement of a basic block with no
+     successors, there is no point inferring anything about any of its
+     operands.  We would not be able to find a proper insertion point
+     for the assertion, anyway.  */
+  if (stmt_ends_bb_p (stmt) && EDGE_COUNT (bb_for_stmt (stmt)->succs) == 0)
+    return false;
+
+  /* We can only assume that a pointer dereference will yield
+     non-NULL if -fdelete-null-pointer-checks is enabled.  */
+  if (flag_delete_null_pointer_checks && POINTER_TYPE_P (TREE_TYPE (op)))
     {
       bool is_store;
       unsigned num_uses, num_derefs;
 
       count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store);
-      if (num_derefs > 0 && flag_delete_null_pointer_checks)
+      if (num_derefs > 0)
        {
-         /* We can only assume that a pointer dereference will yield
-            non-NULL if -fdelete-null-pointer-checks is enabled.  */
          *val_p = build_int_cst (TREE_TYPE (op), 0);
          *comp_code_p = NE_EXPR;
          return true;
@@ -2198,128 +2665,305 @@ register_new_assert_for (tree name,
       loc = loc->next;
     }
 
-  /* If we didn't find an assertion already registered for
-     NAME COMP_CODE VAL, add a new one at the end of the list of
-     assertions associated with NAME.  */
-  n = xmalloc (sizeof (*n));
-  n->bb = dest_bb;
-  n->e = e;
-  n->si = si;
-  n->comp_code = comp_code;
-  n->val = val;
-  n->next = NULL;
+  /* If we didn't find an assertion already registered for
+     NAME COMP_CODE VAL, add a new one at the end of the list of
+     assertions associated with NAME.  */
+  n = XNEW (struct assert_locus_d);
+  n->bb = dest_bb;
+  n->e = e;
+  n->si = si;
+  n->comp_code = comp_code;
+  n->val = val;
+  n->next = NULL;
+
+  if (last_loc)
+    last_loc->next = n;
+  else
+    asserts_for[SSA_NAME_VERSION (name)] = n;
+
+  bitmap_set_bit (need_assert_for, SSA_NAME_VERSION (name));
+}
+
+/* COND is a predicate which uses NAME.  Extract a suitable test code
+   and value and store them into *CODE_P and *VAL_P so the predicate
+   is normalized to NAME *CODE_P *VAL_P.
+
+   If no extraction was possible, return FALSE, otherwise return TRUE.
+
+   If INVERT is true, then we invert the result stored into *CODE_P.  */
+
+static bool
+extract_code_and_val_from_cond (tree name, tree cond, bool invert,
+                               enum tree_code *code_p, tree *val_p)
+{
+  enum tree_code comp_code;
+  tree val;
+
+  /* Predicates may be a single SSA name or NAME OP VAL.  */
+  if (cond == name)
+    {
+      /* If the predicate is a name, it must be NAME, in which
+        case we create the predicate NAME == true or
+        NAME == false accordingly.  */
+      comp_code = EQ_EXPR;
+      val = invert ? boolean_false_node : boolean_true_node;
+    }
+  else
+    {
+      /* Otherwise, we have a comparison of the form NAME COMP VAL
+         or VAL COMP NAME.  */
+      if (name == TREE_OPERAND (cond, 1))
+        {
+         /* If the predicate is of the form VAL COMP NAME, flip
+            COMP around because we need to register NAME as the
+            first operand in the predicate.  */
+         comp_code = swap_tree_comparison (TREE_CODE (cond));
+         val = TREE_OPERAND (cond, 0);
+       }
+      else
+       {
+         /* The comparison is of the form NAME COMP VAL, so the
+            comparison code remains unchanged.  */
+         comp_code = TREE_CODE (cond);
+         val = TREE_OPERAND (cond, 1);
+       }
+
+      /* Invert the comparison code as necessary.  */
+      if (invert)
+       comp_code = invert_tree_comparison (comp_code, 0);
+
+      /* VRP does not handle float types.  */
+      if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)))
+       return false;
+
+      /* Do not register always-false predicates.
+        FIXME:  this works around a limitation in fold() when dealing with
+        enumerations.  Given 'enum { N1, N2 } x;', fold will not
+        fold 'if (x > N2)' to 'if (0)'.  */
+      if ((comp_code == GT_EXPR || comp_code == LT_EXPR)
+         && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+       {
+         tree min = TYPE_MIN_VALUE (TREE_TYPE (val));
+         tree max = TYPE_MAX_VALUE (TREE_TYPE (val));
+
+         if (comp_code == GT_EXPR
+             && (!max
+                 || compare_values (val, max) == 0))
+           return false;
+
+         if (comp_code == LT_EXPR
+             && (!min
+                 || compare_values (val, min) == 0))
+           return false;
+       }
+    }
+  *code_p = comp_code;
+  *val_p = val;
+  return true;
+}
+
+/* OP is an operand of a truth value expression which is known to have
+   a particular value.  Register any asserts for OP and for any
+   operands in OP's defining statement. 
+
+   If CODE is EQ_EXPR, then we want to register OP is zero (false),
+   if CODE is NE_EXPR, then we want to register OP is nonzero (true).   */
+
+static bool
+register_edge_assert_for_1 (tree op, enum tree_code code,
+                           edge e, block_stmt_iterator bsi)
+{
+  bool retval = false;
+  tree op_def, rhs, val;
+
+  /* We only care about SSA_NAMEs.  */
+  if (TREE_CODE (op) != SSA_NAME)
+    return false;
+
+  /* We know that OP will have a zero or nonzero value.  If OP is used
+     more than once go ahead and register an assert for OP. 
+
+     The FOUND_IN_SUBGRAPH support is not helpful in this situation as
+     it will always be set for OP (because OP is used in a COND_EXPR in
+     the subgraph).  */
+  if (!has_single_use (op))
+    {
+      val = build_int_cst (TREE_TYPE (op), 0);
+      register_new_assert_for (op, code, val, NULL, e, bsi);
+      retval = true;
+    }
+
+  /* Now look at how OP is set.  If it's set from a comparison,
+     a truth operation or some bit operations, then we may be able
+     to register information about the operands of that assignment.  */
+  op_def = SSA_NAME_DEF_STMT (op);
+  if (TREE_CODE (op_def) != MODIFY_EXPR)
+    return retval;
 
-  if (last_loc)
-    last_loc->next = n;
-  else
-    asserts_for[SSA_NAME_VERSION (name)] = n;
+  rhs = TREE_OPERAND (op_def, 1);
 
-  bitmap_set_bit (need_assert_for, SSA_NAME_VERSION (name));
-}
+  if (COMPARISON_CLASS_P (rhs))
+    {
+      bool invert = (code == EQ_EXPR ? true : false);
+      tree op0 = TREE_OPERAND (rhs, 0);
+      tree op1 = TREE_OPERAND (rhs, 1);
+
+      /* Conditionally register an assert for each SSA_NAME in the
+        comparison.  */
+      if (TREE_CODE (op0) == SSA_NAME
+         && !has_single_use (op0)
+         && extract_code_and_val_from_cond (op0, rhs,
+                                            invert, &code, &val))
+       {
+         register_new_assert_for (op0, code, val, NULL, e, bsi);
+         retval = true;
+       }
+
+      /* Similarly for the second operand of the comparison.  */
+      if (TREE_CODE (op1) == SSA_NAME
+         && !has_single_use (op1)
+         && extract_code_and_val_from_cond (op1, rhs,
+                                            invert, &code, &val))
+       {
+         register_new_assert_for (op1, code, val, NULL, e, bsi);
+         retval = true;
+       }
+    }
+  else if ((code == NE_EXPR
+           && (TREE_CODE (rhs) == TRUTH_AND_EXPR
+               || TREE_CODE (rhs) == BIT_AND_EXPR))
+          || (code == EQ_EXPR
+              && (TREE_CODE (rhs) == TRUTH_OR_EXPR
+                  || TREE_CODE (rhs) == BIT_IOR_EXPR)))
+    {
+      /* Recurse on each operand.  */
+      retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 0),
+                                           code, e, bsi);
+      retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 1),
+                                           code, e, bsi);
+    }
+  else if (TREE_CODE (rhs) == TRUTH_NOT_EXPR)
+    {
+      /* Recurse, flipping CODE.  */
+      code = invert_tree_comparison (code, false);
+      retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 0),
+                                           code, e, bsi);
+    }
+  else if (TREE_CODE (rhs) == SSA_NAME)
+    {
+      /* Recurse through the copy.  */
+      retval |= register_edge_assert_for_1 (rhs, code, e, bsi);
+    }
+  else if (TREE_CODE (rhs) == NOP_EXPR
+          || TREE_CODE (rhs) == CONVERT_EXPR
+          || TREE_CODE (rhs) == VIEW_CONVERT_EXPR
+          || TREE_CODE (rhs) == NON_LVALUE_EXPR)
+    { 
+      /* Recurse through the type conversion.  */
+      retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 0),
+                                           code, e, bsi);
+    }
 
+  return retval;
+}
 
 /* Try to register an edge assertion for SSA name NAME on edge E for
-   the conditional jump pointed by SI.  Return true if an assertion
-   for NAME could be registered.  */
+   the condition COND contributing to the conditional jump pointed to by SI.
+   Return true if an assertion for NAME could be registered.  */
 
 static bool
-register_edge_assert_for (tree name, edge e, block_stmt_iterator si)
+register_edge_assert_for (tree name, edge e, block_stmt_iterator si, tree cond)
 {
-  tree val, stmt;
+  tree val;
   enum tree_code comp_code;
-
-  stmt = bsi_stmt (si);
+  bool retval = false;
+  bool is_else_edge = (e->flags & EDGE_FALSE_VALUE) != 0;
 
   /* Do not attempt to infer anything in names that flow through
      abnormal edges.  */
   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
     return false;
 
-  /* If NAME was not found in the sub-graph reachable from E, then
-     there's nothing to do.  */
-  if (!TEST_BIT (found_in_subgraph, SSA_NAME_VERSION (name)))
+  if (!extract_code_and_val_from_cond (name, cond, is_else_edge,
+                                      &comp_code, &val))
     return false;
 
-  /* We found a use of NAME in the sub-graph rooted at E->DEST.
-     Register an assertion for NAME according to the value that NAME
-     takes on edge E.  */
-  if (TREE_CODE (stmt) == COND_EXPR)
+  /* Only register an ASSERT_EXPR if NAME was found in the sub-graph
+     reachable from E.  */
+  if (TEST_BIT (found_in_subgraph, SSA_NAME_VERSION (name)))
     {
-      /* If BB ends in a COND_EXPR then NAME then we should insert
-        the original predicate on EDGE_TRUE_VALUE and the
-        opposite predicate on EDGE_FALSE_VALUE.  */
-      tree cond = COND_EXPR_COND (stmt);
-      bool is_else_edge = (e->flags & EDGE_FALSE_VALUE) != 0;
+      register_new_assert_for (name, comp_code, val, NULL, e, si);
+      retval = true;
+    }
 
-      /* Predicates may be a single SSA name or NAME OP VAL.  */
-      if (cond == name)
-       {
-         /* If the predicate is a name, it must be NAME, in which
-            case we create the predicate NAME == true or
-            NAME == false accordingly.  */
-         comp_code = EQ_EXPR;
-         val = (is_else_edge) ? boolean_false_node : boolean_true_node;
-       }
-      else
-       {
-         /* Otherwise, we have a comparison of the form NAME COMP VAL
-            or VAL COMP NAME.  */
-         if (name == TREE_OPERAND (cond, 1))
-           {
-             /* If the predicate is of the form VAL COMP NAME, flip
-                COMP around because we need to register NAME as the
-                first operand in the predicate.  */
-             comp_code = swap_tree_comparison (TREE_CODE (cond));
-             val = TREE_OPERAND (cond, 0);
-           }
-         else
-           {
-             /* The comparison is of the form NAME COMP VAL, so the
-                comparison code remains unchanged.  */
-             comp_code = TREE_CODE (cond);
-             val = TREE_OPERAND (cond, 1);
-           }
+  /* If COND is effectively an equality test of an SSA_NAME against
+     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
+     have non-zero value.  */
+  if (((comp_code == EQ_EXPR && integer_onep (val))
+       || (comp_code == NE_EXPR && integer_zerop (val))))
+    {
+      tree def_stmt = SSA_NAME_DEF_STMT (name);
 
-         /* If we are inserting the assertion on the ELSE edge, we
-            need to invert the sign comparison.  */
-         if (is_else_edge)
-           comp_code = invert_tree_comparison (comp_code, 0);
+      if (TREE_CODE (def_stmt) == MODIFY_EXPR
+         && (TREE_CODE (TREE_OPERAND (def_stmt, 1)) == TRUTH_AND_EXPR
+             || TREE_CODE (TREE_OPERAND (def_stmt, 1)) == BIT_AND_EXPR))
+       {
+         tree op0 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+         tree op1 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 1);
+         retval |= register_edge_assert_for_1 (op0, NE_EXPR, e, si);
+         retval |= register_edge_assert_for_1 (op1, NE_EXPR, e, si);
        }
     }
-  else
+
+  /* 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
+     have zero value.  */
+  if (((comp_code == EQ_EXPR && integer_zerop (val))
+       || (comp_code == NE_EXPR && integer_onep (val))))
     {
-      /* FIXME.  Handle SWITCH_EXPR.  */
-      gcc_unreachable ();
+      tree def_stmt = SSA_NAME_DEF_STMT (name);
+
+      if (TREE_CODE (def_stmt) == MODIFY_EXPR
+         && (TREE_CODE (TREE_OPERAND (def_stmt, 1)) == TRUTH_OR_EXPR
+             || TREE_CODE (TREE_OPERAND (def_stmt, 1)) == BIT_IOR_EXPR))
+       {
+         tree op0 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+         tree op1 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 1);
+         retval |= register_edge_assert_for_1 (op0, EQ_EXPR, e, si);
+         retval |= register_edge_assert_for_1 (op1, EQ_EXPR, e, si);
+       }
     }
 
-  register_new_assert_for (name, comp_code, val, NULL, e, si);
-  return true;
+  return retval;
 }
 
 
 static bool find_assert_locations (basic_block bb);
 
 /* Determine whether the outgoing edges of BB should receive an
-   ASSERT_EXPR for each of the operands of BB's last statement.  The
-   last statement of BB must be a COND_EXPR or a SWITCH_EXPR.
+   ASSERT_EXPR for each of the operands of BB's LAST statement.
+   The last statement of BB must be a COND_EXPR or a SWITCH_EXPR.
 
    If any of the sub-graphs rooted at BB have an interesting use of
    the predicate operands, an assert location node is added to the
    list of assertions for the corresponding operands.  */
 
 static bool
-find_conditional_asserts (basic_block bb)
+find_conditional_asserts (basic_block bb, tree last)
 {
   bool need_assert;
-  block_stmt_iterator last_si;
-  tree op, last;
+  block_stmt_iterator bsi;
+  tree op;
   edge_iterator ei;
   edge e;
   ssa_op_iter iter;
 
   need_assert = false;
-  last_si = bsi_last (bb);
-  last = bsi_stmt (last_si);
+  bsi = bsi_for_stmt (last);
 
   /* Look for uses of the operands in each of the sub-graphs
      rooted at BB.  We need to check each of the outgoing edges
@@ -2333,7 +2977,24 @@ find_conditional_asserts (basic_block bb)
       /* Remove the COND_EXPR operands from the FOUND_IN_SUBGRAPH bitmap.
         Otherwise, when we finish traversing each of the sub-graphs, we
         won't know whether the variables were found in the sub-graphs or
-        if they had been found in a block upstream from BB.  */
+        if they had been found in a block upstream from BB. 
+
+        This is actually a bad idea is some cases, particularly jump
+        threading.  Consider a CFG like the following:
+
+                    0
+                   /|
+                  1 |
+                   \|
+                    2
+                   / \
+                  3   4
+
+        Assume that one or more operands in the conditional at the
+        end of block 0 are used in a conditional in block 2, but not
+        anywhere in block 1.  In this case we will not insert any
+        assert statements in block 1, which may cause us to miss
+        opportunities to optimize, particularly for jump threading.  */
       FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE)
        RESET_BIT (found_in_subgraph, SSA_NAME_VERSION (op));
 
@@ -2346,7 +3007,8 @@ find_conditional_asserts (basic_block bb)
       /* Register the necessary assertions for each operand in the
         conditional predicate.  */
       FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE)
-       need_assert |= register_edge_assert_for (op, e, last_si);
+       need_assert |= register_edge_assert_for (op, e, bsi,
+                                                COND_EXPR_COND (last));
     }
 
   /* Finally, indicate that we have found the operands in the
@@ -2478,21 +3140,50 @@ find_assert_locations (basic_block bb)
             operands it was looking for was present in the sub-graph.  */
          SET_BIT (found_in_subgraph, SSA_NAME_VERSION (op));
 
-         /* If OP is used only once, namely in this STMT, don't
-            bother creating an ASSERT_EXPR for it.  Such an
-            ASSERT_EXPR would do nothing but increase compile time.
-            Experiments show that with this simple check, we can save
-            more than 20% of ASSERT_EXPRs.  */
-         if (has_single_use (op))
-           continue;
-
          /* If OP is used in such a way that we can infer a value
             range for it, and we don't find a previous assertion for
             it, create a new assertion location node for OP.  */
          if (infer_value_range (stmt, op, &comp_code, &value))
            {
-             register_new_assert_for (op, comp_code, value, bb, NULL, si);
-             need_assert = true;
+             /* If we are able to infer a nonzero value range for OP,
+                then walk backwards through the use-def chain to see if OP
+                was set via a typecast.
+
+                If so, then we can also infer a nonzero value range
+                for the operand of the NOP_EXPR.  */
+             if (comp_code == NE_EXPR && integer_zerop (value))
+               {
+                 tree t = op;
+                 tree def_stmt = SSA_NAME_DEF_STMT (t);
+       
+                 while (TREE_CODE (def_stmt) == MODIFY_EXPR
+                        && TREE_CODE (TREE_OPERAND (def_stmt, 1)) == NOP_EXPR
+                        && TREE_CODE (TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0)) == SSA_NAME
+                        && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0))))
+                   {
+                     t = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+                     def_stmt = SSA_NAME_DEF_STMT (t);
+
+                     /* Note we want to register the assert for the
+                        operand of the NOP_EXPR after SI, not after the
+                        conversion.  */
+                     if (! has_single_use (t))
+                       {
+                         register_new_assert_for (t, comp_code, value,
+                                                  bb, NULL, si);
+                         need_assert = true;
+                       }
+                   }
+               }
+
+             /* If OP is used only once, namely in this STMT, don't
+                bother creating an ASSERT_EXPR for it.  Such an
+                ASSERT_EXPR would do nothing but increase compile time.  */
+             if (!has_single_use (op))
+               {
+                 register_new_assert_for (op, comp_code, value, bb, NULL, si);
+                 need_assert = true;
+               }
            }
        }
 
@@ -2507,7 +3198,7 @@ find_assert_locations (basic_block bb)
       && TREE_CODE (last) == COND_EXPR
       && !fp_predicate (COND_EXPR_COND (last))
       && !ZERO_SSA_OPERANDS (last, SSA_OP_USE))
-    need_assert |= find_conditional_asserts (bb);
+    need_assert |= find_conditional_asserts (bb, last);
 
   /* Recurse into the dominator children of BB.  */
   for (son = first_dom_son (CDI_DOMINATORS, bb);
@@ -2530,7 +3221,7 @@ process_assert_insertions_for (tree name, assert_locus_t loc)
   edge_iterator ei;
   edge e;
 
-  cond = build (loc->comp_code, boolean_type_node, name, loc->val);
+  cond = build2 (loc->comp_code, boolean_type_node, name, loc->val);
   assert_expr = build_assert_expr_for (cond, name);
 
   if (loc->e)
@@ -2655,8 +3346,7 @@ insert_range_assertions (void)
   sbitmap_zero (blocks_visited);
 
   need_assert_for = BITMAP_ALLOC (NULL);
-  asserts_for = xmalloc (num_ssa_names * sizeof (assert_locus_t));
-  memset (asserts_for, 0, num_ssa_names * sizeof (assert_locus_t));
+  asserts_for = XCNEWVEC (assert_locus_t, num_ssa_names);
 
   calculate_dominance_info (CDI_DOMINATORS);
 
@@ -2720,33 +3410,35 @@ remove_range_assertions (void)
     for (si = bsi_start (bb); !bsi_end_p (si);)
       {
        tree stmt = bsi_stmt (si);
+       tree use_stmt;
 
        if (TREE_CODE (stmt) == MODIFY_EXPR
            && TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR)
          {
-           tree rhs = TREE_OPERAND (stmt, 1);
+           tree rhs = TREE_OPERAND (stmt, 1), var;
            tree cond = fold (ASSERT_EXPR_COND (rhs));
            use_operand_p use_p;
            imm_use_iterator iter;
 
            gcc_assert (cond != boolean_false_node);
-           TREE_OPERAND (stmt, 1) = ASSERT_EXPR_VAR (rhs);
-           update_stmt (stmt);
 
-           /* The statement is now a copy.  Propagate the RHS into
-              every use of the LHS.  */
-           FOR_EACH_IMM_USE_SAFE (use_p, iter, TREE_OPERAND (stmt, 0))
-             {
-               SET_USE (use_p, ASSERT_EXPR_VAR (rhs));
-               update_stmt (USE_STMT (use_p));
-             }
+           /* Propagate the RHS into every use of the LHS.  */
+           var = ASSERT_EXPR_VAR (rhs);
+           FOR_EACH_IMM_USE_STMT (use_stmt, iter, TREE_OPERAND (stmt, 0))
+             FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+               {
+                 SET_USE (use_p, var);
+                 gcc_assert (TREE_CODE (var) == SSA_NAME);
+               }
 
            /* And finally, remove the copy, it is not needed.  */
-           bsi_remove (&si);
+           bsi_remove (&si, true);
          }
        else
          bsi_next (&si);
       }
+
+  sbitmap_free (blocks_visited);
 }
 
 
@@ -2763,11 +3455,19 @@ stmt_interesting_for_vrp (tree stmt)
   else if (TREE_CODE (stmt) == MODIFY_EXPR)
     {
       tree lhs = TREE_OPERAND (stmt, 0);
+      tree rhs = TREE_OPERAND (stmt, 1);
 
+      /* In general, assignments with virtual operands are not useful
+        for deriving ranges, with the obvious exception of calls to
+        builtin functions.  */
       if (TREE_CODE (lhs) == SSA_NAME
          && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
              || POINTER_TYPE_P (TREE_TYPE (lhs)))
-         && ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+         && ((TREE_CODE (rhs) == CALL_EXPR
+              && TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
+              && DECL_P (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0))
+              && DECL_IS_BUILTIN (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)))
+             || ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)))
        return true;
     }
   else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR)
@@ -2777,17 +3477,14 @@ stmt_interesting_for_vrp (tree stmt)
 }
 
 
-/* Initialize local data structures for VRP.  Return true if VRP
-   is worth running (i.e. if we found any statements that could
-   benefit from range information).  */
+/* Initialize local data structures for VRP.  */
 
 static void
 vrp_initialize (void)
 {
   basic_block bb;
 
-  vr_value = xmalloc (num_ssa_names * sizeof (value_range_t *));
-  memset (vr_value, 0, num_ssa_names * sizeof (value_range_t *));
+  vr_value = XCNEWVEC (value_range_t *, num_ssa_names);
 
   FOR_EACH_BB (bb)
     {
@@ -2841,7 +3538,11 @@ vrp_visit_assignment (tree stmt, tree *output_p)
 
   /* We only keep track of ranges in integral and pointer types.  */
   if (TREE_CODE (lhs) == SSA_NAME
-      && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+      && ((INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+          /* It is valid to have NULL MIN/MAX values on a type.  See
+             build_range_type.  */
+          && TYPE_MIN_VALUE (TREE_TYPE (lhs))
+          && TYPE_MAX_VALUE (TREE_TYPE (lhs)))
          || POINTER_TYPE_P (TREE_TYPE (lhs))))
     {
       struct loop *l;
@@ -2852,7 +3553,7 @@ vrp_visit_assignment (tree stmt, tree *output_p)
       /* If STMT is inside a loop, we may be able to know something
         else about the range of LHS by examining scalar evolution
         information.  */
-      if (cfg_loops && (l = loop_containing_stmt (stmt)))
+      if (current_loops && (l = loop_containing_stmt (stmt)))
        adjust_range_with_scev (&new_vr, l, stmt, lhs);
 
       if (update_value_range (lhs, &new_vr))
@@ -2924,8 +3625,16 @@ compare_name_with_value (enum tree_code comp, tree var, tree val)
       t = compare_range_with_value (comp, &equiv_vr, val);
       if (t)
        {
-         /* All the ranges should compare the same against VAL.  */
-         gcc_assert (retval == NULL || t == retval);
+         /* If we get different answers from different members
+            of the equivalence set this check must be in a dead
+            code region.  Folding it to a trap representation
+            would be correct here.  For now just return don't-know.  */
+         if (retval != NULL
+             && t != retval)
+           {
+             retval = NULL_TREE;
+             break;
+           }
          retval = t;
        }
     }
@@ -3007,9 +3716,17 @@ compare_names (enum tree_code comp, tree n1, tree n2)
          t = compare_ranges (comp, &vr1, &vr2);
          if (t)
            {
-             /* All the ranges in the equivalent sets should compare
-                the same.  */
-             gcc_assert (retval == NULL || t == retval);
+             /* If we get different answers from different members
+                of the equivalence set this check must be in a dead
+                code region.  Folding it to a trap representation
+                would be correct here.  For now just return don't-know.  */
+             if (retval != NULL
+                 && t != retval)
+               {
+                 bitmap_clear_bit (e1, SSA_NAME_VERSION (n1));
+                 bitmap_clear_bit (e2, SSA_NAME_VERSION (n2));
+                 return NULL_TREE;
+               }
              retval = t;
            }
        }
@@ -3234,9 +3951,20 @@ vrp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
     }
 
   ann = stmt_ann (stmt);
-  if (TREE_CODE (stmt) == MODIFY_EXPR
-      && ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
-    return vrp_visit_assignment (stmt, output_p);
+  if (TREE_CODE (stmt) == MODIFY_EXPR)
+    {
+      tree rhs = TREE_OPERAND (stmt, 1);
+
+      /* In general, assignments with virtual operands are not useful
+        for deriving ranges, with the obvious exception of calls to
+        builtin functions.  */
+      if ((TREE_CODE (rhs) == CALL_EXPR
+          && TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
+          && DECL_P (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0))
+          && DECL_IS_BUILTIN (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)))
+         || ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+       return vrp_visit_assignment (stmt, output_p);
+    }
   else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR)
     return vrp_visit_cond_stmt (stmt, taken_edge_p);
 
@@ -3250,14 +3978,8 @@ vrp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
 
 
 /* Meet operation for value ranges.  Given two value ranges VR0 and
-   VR1, store in VR0 the result of meeting VR0 and VR1.
-   
-   The meeting rules are as follows:
-
-   1- If VR0 and VR1 have an empty intersection, set VR0 to VR_VARYING.
-
-   2- If VR0 and VR1 have a non-empty intersection, set VR0 to the
-      union of VR0 and VR1.  */
+   VR1, store in VR0 a range that contains both VR0 and VR1.  This
+   may not be the smallest possible such range.  */
 
 static void
 vrp_meet (value_range_t *vr0, value_range_t *vr1)
@@ -3288,54 +4010,44 @@ vrp_meet (value_range_t *vr0, value_range_t *vr1)
 
   if (vr0->type == VR_RANGE && vr1->type == VR_RANGE)
     {
-      /* If VR0 and VR1 have a non-empty intersection, compute the
-        union of both ranges.  */
-      if (value_ranges_intersect_p (vr0, vr1))
-       {
-         int cmp;
-         tree min, max;
-
-         /* The lower limit of the new range is the minimum of the
-            two ranges.  If they cannot be compared, the result is
-            VARYING.  */
-         cmp = compare_values (vr0->min, vr1->min);
-         if (cmp == 0 || cmp == 1)
-           min = vr1->min;
-         else if (cmp == -1)
-           min = vr0->min;
-         else
-           {
-             set_value_range_to_varying (vr0);
-             return;
-           }
-
-         /* Similarly, the upper limit of the new range is the
-            maximum of the two ranges.  If they cannot be compared,
-            the result is VARYING.  */
-         cmp = compare_values (vr0->max, vr1->max);
-         if (cmp == 0 || cmp == -1)
-           max = vr1->max;
-         else if (cmp == 1)
-           max = vr0->max;
-         else
-           {
-             set_value_range_to_varying (vr0);
-             return;
-           }
+      int cmp;
+      tree min, max;
+
+      /* Compute the convex hull of the ranges.  The lower limit of
+         the new range is the minimum of the two ranges.  If they
+        cannot be compared, then give up.  */
+      cmp = compare_values (vr0->min, vr1->min);
+      if (cmp == 0 || cmp == 1)
+        min = vr1->min;
+      else if (cmp == -1)
+        min = vr0->min;
+      else
+       goto give_up;
+
+      /* Similarly, the upper limit of the new range is the maximum
+         of the two ranges.  If they cannot be compared, then
+        give up.  */
+      cmp = compare_values (vr0->max, vr1->max);
+      if (cmp == 0 || cmp == -1)
+        max = vr1->max;
+      else if (cmp == 1)
+        max = vr0->max;
+      else
+       goto give_up;
 
-         /* The resulting set of equivalences is the intersection of
-            the two sets.  */
-         if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-           bitmap_and_into (vr0->equiv, vr1->equiv);
+      /* The resulting set of equivalences is the intersection of
+        the two sets.  */
+      if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
+        bitmap_and_into (vr0->equiv, vr1->equiv);
+      else if (vr0->equiv && !vr1->equiv)
+        bitmap_clear (vr0->equiv);
 
-         set_value_range (vr0, vr0->type, min, max, vr0->equiv);
-       }
-      else
-       goto no_meet;
+      set_value_range (vr0, vr0->type, min, max, vr0->equiv);
     }
   else if (vr0->type == VR_ANTI_RANGE && vr1->type == VR_ANTI_RANGE)
     {
-      /* Two anti-ranges meet only if they are both identical.  */
+      /* Two anti-ranges meet only if their complements intersect.
+         Only handle the case of identical ranges.  */
       if (compare_values (vr0->min, vr1->min) == 0
          && compare_values (vr0->max, vr1->max) == 0
          && compare_values (vr0->min, vr0->max) == 0)
@@ -3344,39 +4056,62 @@ vrp_meet (value_range_t *vr0, value_range_t *vr1)
             the two sets.  */
          if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
            bitmap_and_into (vr0->equiv, vr1->equiv);
+         else if (vr0->equiv && !vr1->equiv)
+           bitmap_clear (vr0->equiv);
        }
       else
-       goto no_meet;
+       goto give_up;
     }
   else if (vr0->type == VR_ANTI_RANGE || vr1->type == VR_ANTI_RANGE)
     {
-      /* A numeric range [VAL1, VAL2] and an anti-range ~[VAL3, VAL4]
-        meet only if the ranges have an empty intersection.  The
-        result of the meet operation is the anti-range.  */
+      /* For a numeric range [VAL1, VAL2] and an anti-range ~[VAL3, VAL4],
+         only handle the case where the ranges have an empty intersection.
+        The result of the meet operation is the anti-range.  */
       if (!symbolic_range_p (vr0)
          && !symbolic_range_p (vr1)
          && !value_ranges_intersect_p (vr0, vr1))
        {
+         /* Copy most of VR1 into VR0.  Don't copy VR1's equivalence
+            set.  We need to compute the intersection of the two
+            equivalence sets.  */
          if (vr1->type == VR_ANTI_RANGE)
-           copy_value_range (vr0, vr1);
+           set_value_range (vr0, vr1->type, vr1->min, vr1->max, vr0->equiv);
+
+         /* The resulting set of equivalences is the intersection of
+            the two sets.  */
+         if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
+           bitmap_and_into (vr0->equiv, vr1->equiv);
+         else if (vr0->equiv && !vr1->equiv)
+           bitmap_clear (vr0->equiv);
        }
       else
-       goto no_meet;
+       goto give_up;
     }
   else
     gcc_unreachable ();
 
   return;
 
-no_meet:
-  /* The two range VR0 and VR1 do not meet.  Before giving up and
-     setting the result to VARYING, see if we can at least derive a
-     useful anti-range.  */
+give_up:
+  /* Failed to find an efficient meet.  Before giving up and setting
+     the result to VARYING, see if we can at least derive a useful
+     anti-range.  FIXME, all this nonsense about distinguishing
+     anti-ranges from ranges is necessary because of the odd
+     semantics of range_includes_zero_p and friends.  */
   if (!symbolic_range_p (vr0)
-      && !range_includes_zero_p (vr0)
+      && ((vr0->type == VR_RANGE && !range_includes_zero_p (vr0))
+         || (vr0->type == VR_ANTI_RANGE && range_includes_zero_p (vr0)))
       && !symbolic_range_p (vr1)
-      && !range_includes_zero_p (vr1))
-    set_value_range_to_nonnull (vr0, TREE_TYPE (vr0->min));
+      && ((vr1->type == VR_RANGE && !range_includes_zero_p (vr1))
+         || (vr1->type == VR_ANTI_RANGE && range_includes_zero_p (vr1))))
+    {
+      set_value_range_to_nonnull (vr0, TREE_TYPE (vr0->min));
+
+      /* Since this meet operation did not result from the meeting of
+        two equivalent names, VR0 cannot have any equivalences.  */
+      if (vr0->equiv)
+       bitmap_clear (vr0->equiv);
+    }
   else
     set_value_range_to_varying (vr0);
 }
@@ -3451,7 +4186,7 @@ vrp_visit_phi_node (tree phi)
   /* To prevent infinite iterations in the algorithm, derive ranges
      when the new value is slightly bigger or smaller than the
      previous one.  */
-  if (lhs_vr->type == VR_RANGE)
+  if (lhs_vr->type == VR_RANGE && vr_result.type == VR_RANGE)
     {
       if (!POINTER_TYPE_P (TREE_TYPE (lhs)))
        {
@@ -3493,125 +4228,418 @@ varying:
   return SSA_PROP_VARYING;
 }
 
-/* Walk through the IL simplifying expressions using knowledge
-   gathered by VRP.  */
+/* Simplify a division or modulo operator to a right shift or
+   bitwise and if the first operand is unsigned or is greater
+   than zero and the second operand is an exact power of two.  */
 
 static void
-simplify_using_ranges (void)
+simplify_div_or_mod_using_ranges (tree stmt, tree rhs, enum tree_code rhs_code)
 {
-  basic_block bb;
+  tree val = NULL;
+  tree op = TREE_OPERAND (rhs, 0);
+  value_range_t *vr = get_value_range (TREE_OPERAND (rhs, 0));
 
-  FOR_EACH_BB (bb)
+  if (TYPE_UNSIGNED (TREE_TYPE (op)))
+    {
+      val = integer_one_node;
+    }
+  else
+    {
+      val = compare_range_with_value (GT_EXPR, vr, integer_zero_node);
+    }
+
+  if (val && integer_onep (val))
     {
-      block_stmt_iterator bsi;
+      tree t;
+      tree op0 = TREE_OPERAND (rhs, 0);
+      tree op1 = TREE_OPERAND (rhs, 1);
+
+      if (rhs_code == TRUNC_DIV_EXPR)
+       {
+         t = build_int_cst (NULL_TREE, tree_log2 (op1));
+         t = build2 (RSHIFT_EXPR, TREE_TYPE (op0), op0, t);
+       }
+      else
+       {
+         t = build_int_cst (TREE_TYPE (op1), 1);
+         t = int_const_binop (MINUS_EXPR, op1, t, 0);
+         t = fold_convert (TREE_TYPE (op0), t);
+         t = build2 (BIT_AND_EXPR, TREE_TYPE (op0), op0, t);
+       }
+
+      TREE_OPERAND (stmt, 1) = t;
+      update_stmt (stmt);
+    }
+}
+
+/* If the operand to an ABS_EXPR is >= 0, then eliminate the
+   ABS_EXPR.  If the operand is <= 0, then simplify the
+   ABS_EXPR into a NEGATE_EXPR.  */
 
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+static void
+simplify_abs_using_ranges (tree stmt, tree rhs)
+{
+  tree val = NULL;
+  tree op = TREE_OPERAND (rhs, 0);
+  tree type = TREE_TYPE (op);
+  value_range_t *vr = get_value_range (TREE_OPERAND (rhs, 0));
+
+  if (TYPE_UNSIGNED (type))
+    {
+      val = integer_zero_node;
+    }
+  else if (vr)
+    {
+      val = compare_range_with_value (LE_EXPR, vr, integer_zero_node);
+      if (!val)
        {
-         tree stmt = bsi_stmt (bsi);
+         val = compare_range_with_value (GE_EXPR, vr, integer_zero_node);
 
-         if (TREE_CODE (stmt) == MODIFY_EXPR)
+         if (val)
            {
-             tree rhs = TREE_OPERAND (stmt, 1);
-             enum tree_code rhs_code = TREE_CODE (rhs);
-
-             /* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR
-                and BIT_AND_EXPR respectively if the first operand is greater
-                than zero and the second operand is an exact power of two.  */
-             if ((rhs_code == TRUNC_DIV_EXPR || rhs_code == TRUNC_MOD_EXPR)
-                 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0)))
-                 && integer_pow2p (TREE_OPERAND (rhs, 1)))
-               {
-                 tree val = NULL;
-                 tree op = TREE_OPERAND (rhs, 0);
-                 value_range_t *vr = get_value_range (TREE_OPERAND (rhs, 0));
+             if (integer_zerop (val))
+               val = integer_one_node;
+             else if (integer_onep (val))
+               val = integer_zero_node;
+           }
+       }
 
-                 if (TYPE_UNSIGNED (TREE_TYPE (op)))
-                   {
-                     val = integer_one_node;
-                   }
-                 else
-                   {
-                     val = compare_range_with_value (GT_EXPR, vr,
-                                                     integer_zero_node);
-                   }
+      if (val
+         && (integer_onep (val) || integer_zerop (val)))
+       {
+         tree t;
 
-                 if (val && integer_onep (val))
-                   {
-                     tree t;
-                     tree op0 = TREE_OPERAND (rhs, 0);
-                     tree op1 = TREE_OPERAND (rhs, 1);
+         if (integer_onep (val))
+           t = build1 (NEGATE_EXPR, TREE_TYPE (op), op);
+         else
+           t = op;
 
-                     if (rhs_code == TRUNC_DIV_EXPR)
-                       {
-                         t = build_int_cst (NULL_TREE, tree_log2 (op1));
-                         t = build (RSHIFT_EXPR, TREE_TYPE (op0), op0, t);
-                       }
-                     else
-                       {
-                         t = build_int_cst (TREE_TYPE (op1), 1);
-                         t = int_const_binop (MINUS_EXPR, op1, t, 0);
-                         t = fold_convert (TREE_TYPE (op0), t);
-                         t = build2 (BIT_AND_EXPR, TREE_TYPE (op0), op0, t);
-                       }
+         TREE_OPERAND (stmt, 1) = t;
+         update_stmt (stmt);
+       }
+    }
+}
 
-                     TREE_OPERAND (stmt, 1) = t;
-                     update_stmt (stmt);
-                   }
+/* We are comparing trees OP0 and OP1 using COND_CODE.  OP0 has
+   a known value range VR.
+
+   If there is one and only one value which will satisfy the
+   conditional, then return that value.  Else return NULL.  */
+
+static tree
+test_for_singularity (enum tree_code cond_code, tree op0,
+                     tree op1, value_range_t *vr)
+{
+  tree min = NULL;
+  tree max = NULL;
+
+  /* Extract minimum/maximum values which satisfy the
+     the conditional as it was written.  */
+  if (cond_code == LE_EXPR || cond_code == LT_EXPR)
+    {
+      min = TYPE_MIN_VALUE (TREE_TYPE (op0));
+
+      max = op1;
+      if (cond_code == LT_EXPR)
+       {
+         tree one = build_int_cst (TREE_TYPE (op0), 1);
+         max = fold_build2 (MINUS_EXPR, TREE_TYPE (op0), max, one);
+       }
+    }
+  else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
+    {
+      max = TYPE_MAX_VALUE (TREE_TYPE (op0));
+
+      min = op1;
+      if (cond_code == GT_EXPR)
+       {
+         tree one = build_int_cst (TREE_TYPE (op0), 1);
+         min = fold_build2 (PLUS_EXPR, TREE_TYPE (op0), min, one);
+       }
+    }
+
+  /* Now refine the minimum and maximum values using any
+     value range information we have for op0.  */
+  if (min && max)
+    {
+      if (compare_values (vr->min, min) == -1)
+       min = min;
+      else
+       min = vr->min;
+      if (compare_values (vr->max, max) == 1)
+       max = max;
+      else
+       max = vr->max;
+
+      /* If the new min/max values have converged to a single value,
+        then there is only one value which can satisfy the condition,
+        return that value.  */
+      if (operand_equal_p (min, max, 0) && is_gimple_min_invariant (min))
+       return min;
+    }
+  return NULL;
+}
+
+/* Simplify a conditional using a relational operator to an equality
+   test if the range information indicates only one value can satisfy
+   the original conditional.  */
+
+static void
+simplify_cond_using_ranges (tree stmt)
+{
+  tree cond = COND_EXPR_COND (stmt);
+  tree op0 = TREE_OPERAND (cond, 0);
+  tree op1 = TREE_OPERAND (cond, 1);
+  enum tree_code cond_code = TREE_CODE (cond);
+
+  if (cond_code != NE_EXPR
+      && cond_code != EQ_EXPR
+      && TREE_CODE (op0) == SSA_NAME
+      && INTEGRAL_TYPE_P (TREE_TYPE (op0))
+      && is_gimple_min_invariant (op1))
+    {
+      value_range_t *vr = get_value_range (op0);
+         
+      /* If we have range information for OP0, then we might be
+        able to simplify this conditional. */
+      if (vr->type == VR_RANGE)
+       {
+         tree new = test_for_singularity (cond_code, op0, op1, vr);
 
+         if (new)
+           {
+             if (dump_file)
+               {
+                 fprintf (dump_file, "Simplified relational ");
+                 print_generic_expr (dump_file, cond, 0);
+                 fprintf (dump_file, " into ");
                }
 
-             /* Transform ABS (X) into X or -X as appropriate.  */
-             if (rhs_code == ABS_EXPR
-                 && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
-                 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0))))
+             COND_EXPR_COND (stmt)
+               = build2 (EQ_EXPR, boolean_type_node, op0, new);
+             update_stmt (stmt);
+
+             if (dump_file)
                {
-                 tree val = NULL;
-                 tree op = TREE_OPERAND (rhs, 0);
-                 tree type = TREE_TYPE (op);
-                 value_range_t *vr = get_value_range (TREE_OPERAND (rhs, 0));
+                 print_generic_expr (dump_file, COND_EXPR_COND (stmt), 0);
+                 fprintf (dump_file, "\n");
+               }
+             return;
 
-                 if (TYPE_UNSIGNED (type))
-                   {
-                     val = integer_zero_node;
-                   }
-                 else if (vr)
-                   {
-                     val = compare_range_with_value (LE_EXPR, vr,
-                                                     integer_zero_node);
-                     if (!val)
-                       {
-                         val = compare_range_with_value (GE_EXPR, vr,
-                                                         integer_zero_node);
-
-                         if (val)
-                           {
-                             if (integer_zerop (val))
-                               val = integer_one_node;
-                             else if (integer_onep (val))
-                               val = integer_zero_node;
-                           }
-                       }
+           }
 
-                     if (val
-                         && (integer_onep (val) || integer_zerop (val)))
-                       {
-                         tree t;
+         /* Try again after inverting the condition.  We only deal
+            with integral types here, so no need to worry about
+            issues with inverting FP comparisons.  */
+         cond_code = invert_tree_comparison (cond_code, false);
+         new = test_for_singularity (cond_code, op0, op1, vr);
 
-                         if (integer_onep (val))
-                           t = build1 (NEGATE_EXPR, TREE_TYPE (op), op);
-                         else
-                           t = op;
+         if (new)
+           {
+             if (dump_file)
+               {
+                 fprintf (dump_file, "Simplified relational ");
+                 print_generic_expr (dump_file, cond, 0);
+                 fprintf (dump_file, " into ");
+               }
 
-                         TREE_OPERAND (stmt, 1) = t;
-                         update_stmt (stmt);
-                       }
-                   }
+             COND_EXPR_COND (stmt)
+               = build2 (NE_EXPR, boolean_type_node, op0, new);
+             update_stmt (stmt);
+
+             if (dump_file)
+               {
+                 print_generic_expr (dump_file, COND_EXPR_COND (stmt), 0);
+                 fprintf (dump_file, "\n");
                }
+             return;
+
            }
+       }
+    }
+}
+
+/* Simplify STMT using ranges if possible.  */
+
+void
+simplify_stmt_using_ranges (tree stmt)
+{
+  if (TREE_CODE (stmt) == MODIFY_EXPR)
+    {
+      tree rhs = TREE_OPERAND (stmt, 1);
+      enum tree_code rhs_code = TREE_CODE (rhs);
+
+      /* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR
+        and BIT_AND_EXPR respectively if the first operand is greater
+        than zero and the second operand is an exact power of two.  */
+      if ((rhs_code == TRUNC_DIV_EXPR || rhs_code == TRUNC_MOD_EXPR)
+         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0)))
+         && integer_pow2p (TREE_OPERAND (rhs, 1)))
+       simplify_div_or_mod_using_ranges (stmt, rhs, rhs_code);
+
+      /* Transform ABS (X) into X or -X as appropriate.  */
+      if (rhs_code == ABS_EXPR
+         && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
+         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0))))
+       simplify_abs_using_ranges (stmt, rhs);
+    }
+  else if (TREE_CODE (stmt) == COND_EXPR
+          && COMPARISON_CLASS_P (COND_EXPR_COND (stmt)))
+    {
+      simplify_cond_using_ranges (stmt);
+    }
+}
+
+/* Stack of dest,src equivalency pairs that need to be restored after
+   each attempt to thread a block's incoming edge to an outgoing edge. 
+
+   A NULL entry is used to mark the end of pairs which need to be
+   restored.  */
+static VEC(tree,heap) *stack;
+
+/* A trivial wrapper so that we can present the generic jump
+   threading code with a simple API for simplifying statements.  */
+static tree
+simplify_stmt_for_jump_threading (tree stmt)
+{
+  /* We only use VRP information to simplify conditionals.  This is
+     overly conservative, but it's unclear if doing more would be
+     worth the compile time cost.  */
+  if (TREE_CODE (stmt) != COND_EXPR)
+    return NULL;
+
+  return vrp_evaluate_conditional (COND_EXPR_COND (stmt), true);
+}
+
+/* Blocks which have more than one predecessor and more than
+   one successor present jump threading opportunities.  ie,
+   when the block is reached from a specific predecessor, we
+   may be able to determine which of the outgoing edges will
+   be traversed.  When this optimization applies, we are able
+   to avoid conditionals at runtime and we may expose secondary
+   optimization opportunities.
 
-         /* TODO.  Simplify conditionals.   */
+   This routine is effectively a driver for the generic jump
+   threading code.  It basically just presents the generic code
+   with edges that may be suitable for jump threading.
+
+   Unlike DOM, we do not iterate VRP if jump threading was successful.
+   While iterating may expose new opportunities for VRP, it is expected
+   those opportunities would be very limited and the compile time cost
+   to expose those opportunities would be significant. 
+
+   As jump threading opportunities are discovered, they are registered
+   for later realization.  */
+
+static void
+identify_jump_threads (void)
+{
+  basic_block bb;
+  tree dummy;
+
+  /* Ugh.  When substituting values earlier in this pass we can
+     wipe the dominance information.  So rebuild the dominator
+     information as we need it within the jump threading code.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  /* We do not allow VRP information to be used for jump threading
+     across a back edge in the CFG.  Otherwise it becomes too
+     difficult to avoid eliminating loop exit tests.  Of course
+     EDGE_DFS_BACK is not accurate at this time so we have to
+     recompute it.  */
+  mark_dfs_back_edges ();
+
+  /* Allocate our unwinder stack to unwind any temporary equivalences
+     that might be recorded.  */
+  stack = VEC_alloc (tree, heap, 20);
+
+  /* To avoid lots of silly node creation, we create a single
+     conditional and just modify it in-place when attempting to
+     thread jumps.  */
+  dummy = build2 (EQ_EXPR, boolean_type_node, NULL, NULL);
+  dummy = build3 (COND_EXPR, void_type_node, dummy, NULL, NULL);
+
+  /* Walk through all the blocks finding those which present a
+     potential jump threading opportunity.  We could set this up
+     as a dominator walker and record data during the walk, but
+     I doubt it's worth the effort for the classes of jump
+     threading opportunities we are trying to identify at this
+     point in compilation.  */
+  FOR_EACH_BB (bb)
+    {
+      tree last, cond;
+
+      /* If the generic jump threading code does not find this block
+        interesting, then there is nothing to do.  */
+      if (! potentially_threadable_block (bb))
+       continue;
+
+      /* We only care about blocks ending in a COND_EXPR.  While there
+        may be some value in handling SWITCH_EXPR here, I doubt it's
+        terribly important.  */
+      last = bsi_stmt (bsi_last (bb));
+      if (TREE_CODE (last) != COND_EXPR)
+       continue;
+
+      /* We're basically looking for any kind of conditional with
+        integral type arguments.  */
+      cond = COND_EXPR_COND (last);
+      if ((TREE_CODE (cond) == SSA_NAME
+          && INTEGRAL_TYPE_P (TREE_TYPE (cond)))
+         || (COMPARISON_CLASS_P (cond)
+             && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME
+             && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 0)))
+             && (TREE_CODE (TREE_OPERAND (cond, 1)) == SSA_NAME
+                 || is_gimple_min_invariant (TREE_OPERAND (cond, 1)))
+             && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1)))))
+       {
+         edge_iterator ei;
+         edge e;
+
+         /* We've got a block with multiple predecessors and multiple
+            successors which also ends in a suitable conditional.  For
+            each predecessor, see if we can thread it to a specific
+            successor.  */
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           {
+             /* Do not thread across back edges or abnormal edges
+                in the CFG.  */
+             if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
+               continue;
+
+             thread_across_edge (dummy, e, true,
+                                 &stack,
+                                 simplify_stmt_for_jump_threading);
+           }
        }
     }
+
+  /* We do not actually update the CFG or SSA graphs at this point as
+     ASSERT_EXPRs are still in the IL and cfg cleanup code does not yet
+     handle ASSERT_EXPRs gracefully.  */
+}
+
+/* We identified all the jump threading opportunities earlier, but could
+   not transform the CFG at that time.  This routine transforms the
+   CFG and arranges for the dominator tree to be rebuilt if necessary.
+
+   Note the SSA graph update will occur during the normal TODO
+   processing by the pass manager.  */
+static void
+finalize_jump_threads (void)
+{
+  bool cfg_altered = false;
+  cfg_altered = thread_through_all_blocks ();
+
+  /* If we threaded jumps, then we need to recompute the dominance
+     information, to safely do that we must clean up the CFG first.  */
+  if (cfg_altered)
+    {
+      free_dominance_info (CDI_DOMINATORS);
+      cleanup_tree_cfg ();
+      calculate_dominance_info (CDI_DOMINATORS);
+    }
+  VEC_free (tree, heap, stack);
 }
 
 
@@ -3634,8 +4662,7 @@ vrp_finalize (void)
   /* We may have ended with ranges that have exactly one value.  Those
      values can be substituted as any other copy/const propagated
      value using substitute_and_fold.  */
-  single_val_range = xmalloc (num_ssa_names * sizeof (*single_val_range));
-  memset (single_val_range, 0, num_ssa_names * sizeof (*single_val_range));
+  single_val_range = XCNEWVEC (prop_value_t, num_ssa_names);
 
   do_value_subst_p = false;
   for (i = 0; i < num_ssa_names; i++)
@@ -3657,11 +4684,9 @@ vrp_finalize (void)
 
   substitute_and_fold (single_val_range, true);
 
-  /* One could argue all simplifications should be done here
-     rather than using substitute_and_fold since this code
-     is going to have to perform a complete walk through the
-     IL anyway.  */
-  simplify_using_ranges ();
+  /* We must identify jump threading opportunities before we release
+     the datastructures built by VRP.  */
+  identify_jump_threads ();
 
   /* Free allocated memory.  */
   for (i = 0; i < num_ssa_names; i++)
@@ -3673,6 +4698,10 @@ vrp_finalize (void)
 
   free (single_val_range);
   free (vr_value);
+
+  /* So that we can distinguish between VRP data being available
+     and not available.  */
+  vr_value = NULL;
 }
 
 
@@ -3720,27 +4749,39 @@ vrp_finalize (void)
    DON'T KNOW.  In the future, it may be worthwhile to propagate
    probabilities to aid branch prediction.  */
 
-static void
+static unsigned int
 execute_vrp (void)
 {
   insert_range_assertions ();
 
-  cfg_loops = loop_optimizer_init (NULL);
-  if (cfg_loops)
-    scev_initialize (cfg_loops);
+  loop_optimizer_init (LOOPS_NORMAL);
+  if (current_loops)
+    scev_initialize ();
 
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
   vrp_finalize ();
 
-  if (cfg_loops)
+  if (current_loops)
     {
       scev_finalize ();
-      loop_optimizer_finalize (cfg_loops, NULL);
-      current_loops = NULL;
+      loop_optimizer_finalize ();
     }
 
+  /* ASSERT_EXPRs must be removed before finalizing jump threads
+     as finalizing jump threads calls the CFG cleanup code which
+     does not properly handle ASSERT_EXPRs.  */
   remove_range_assertions ();
+
+  /* If we exposed any new variables, go ahead and put them into
+     SSA form now, before we handle jump threading.  This simplifies
+     interactions between rewriting of _DECL nodes into SSA form
+     and rewriting SSA_NAME nodes into SSA form after block
+     duplication and CFG manipulation.  */
+  update_ssa (TODO_update_ssa);
+
+  finalize_jump_threads ();
+  return 0;
 }
 
 static bool
@@ -3760,12 +4801,13 @@ struct tree_opt_pass pass_vrp =
   TV_TREE_VRP,                         /* tv_id */
   PROP_ssa | PROP_alias,               /* properties_required */
   0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
+  PROP_smt_usage,                      /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_cleanup_cfg
     | TODO_ggc_collect
     | TODO_verify_ssa
     | TODO_dump_func
-    | TODO_update_ssa,                 /* todo_flags_finish */
+    | TODO_update_ssa
+    | TODO_update_smt_usage,                   /* todo_flags_finish */
   0                                    /* letter */
 };