OSDN Git Service

2009-04-20 Joey Ye <joey.ye@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-vrp.c
index 348382e..e3d14b2 100644 (file)
@@ -1,5 +1,5 @@
 /* Support routines for Value Range Propagation (VRP).
-   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>.
 
 This file is part of GCC.
@@ -57,7 +57,8 @@ static int compare_values (tree val1, tree val2);
 static int compare_values_warnv (tree val1, tree val2, bool *);
 static void vrp_meet (value_range_t *, value_range_t *);
 static tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
-                                                    tree, tree, bool, bool *);
+                                                    tree, tree, bool, bool *,
+                                                    bool *);
 
 /* Location information for ASSERT_EXPRs.  Each instance of this
    structure describes an ASSERT_EXPR for an SSA name.  Since a single
@@ -598,6 +599,42 @@ set_value_range_to_undefined (value_range_t *vr)
 }
 
 
+/* If abs (min) < abs (max), set VR to [-max, max], if
+   abs (min) >= abs (max), set VR to [-min, min].  */
+
+static void
+abs_extent_range (value_range_t *vr, tree min, tree max)
+{
+  int cmp;
+
+  gcc_assert (TREE_CODE (min) == INTEGER_CST);
+  gcc_assert (TREE_CODE (max) == INTEGER_CST);
+  gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (min)));
+  gcc_assert (!TYPE_UNSIGNED (TREE_TYPE (min)));
+  min = fold_unary (ABS_EXPR, TREE_TYPE (min), min);
+  max = fold_unary (ABS_EXPR, TREE_TYPE (max), max);
+  if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max))
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+  cmp = compare_values (min, max);
+  if (cmp == -1)
+    min = fold_unary (NEGATE_EXPR, TREE_TYPE (min), max);
+  else if (cmp == 0 || cmp == 1)
+    {
+      max = min;
+      min = fold_unary (NEGATE_EXPR, TREE_TYPE (min), min);
+    }
+  else
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+  set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
+}
+
+
 /* Return value range information for VAR.  
 
    If we have no values ranges recorded (ie, VRP is not running), then
@@ -1331,28 +1368,6 @@ ssa_name_nonnegative_p (const_tree t)
   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 (const_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;
-}
-
 /* If OP has a value range with a single constant value return that,
    otherwise return NULL_TREE.  This returns OP itself if OP is a
    constant.  */
@@ -1583,7 +1598,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
         all should be optimized away above us.  */
       if ((cond_code == LT_EXPR
           && compare_values (max, min) == 0)
-         || is_overflow_infinity (max))
+         || (CONSTANT_CLASS_P (max) && TREE_OVERFLOW (max)))
        set_value_range_to_varying (vr_p);
       else
        {
@@ -1618,7 +1633,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
         all should be optimized away above us.  */
       if ((cond_code == GT_EXPR
           && compare_values (min, max) == 0)
-         || is_overflow_infinity (min))
+         || (CONSTANT_CLASS_P (min) && TREE_OVERFLOW (min)))
        set_value_range_to_varying (vr_p);
       else
        {
@@ -2054,6 +2069,7 @@ extract_range_from_binary_expr (value_range_t *vr,
       && code != MIN_EXPR
       && code != MAX_EXPR
       && code != BIT_AND_EXPR
+      && code != BIT_IOR_EXPR
       && code != TRUTH_AND_EXPR
       && code != TRUTH_OR_EXPR)
     {
@@ -2106,11 +2122,17 @@ extract_range_from_binary_expr (value_range_t *vr,
   /* Refuse to operate on VARYING ranges, ranges of different kinds
      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.  */
+     the operands is VR_VARYING or symbolic range.  Similarly for
+     divisions.  TODO, we may be able to derive anti-ranges in
+     some cases.  */
   if (code != BIT_AND_EXPR
       && code != TRUTH_AND_EXPR
       && code != TRUTH_OR_EXPR
+      && code != TRUNC_DIV_EXPR
+      && code != FLOOR_DIV_EXPR
+      && code != CEIL_DIV_EXPR
+      && code != EXACT_DIV_EXPR
+      && code != ROUND_DIV_EXPR
       && (vr0.type == VR_VARYING
          || vr1.type == VR_VARYING
          || vr0.type != vr1.type
@@ -2274,6 +2296,86 @@ extract_range_from_binary_expr (value_range_t *vr,
            }
        }
 
+      else if ((code == TRUNC_DIV_EXPR
+               || code == FLOOR_DIV_EXPR
+               || code == CEIL_DIV_EXPR
+               || code == EXACT_DIV_EXPR
+               || code == ROUND_DIV_EXPR)
+              && (vr0.type != VR_RANGE || symbolic_range_p (&vr0)))
+       {
+         /* For division, if op1 has VR_RANGE but op0 does not, something
+            can be deduced just from that range.  Say [min, max] / [4, max]
+            gives [min / 4, max / 4] range.  */
+         if (vr1.type == VR_RANGE
+             && !symbolic_range_p (&vr1)
+             && !range_includes_zero_p (&vr1))
+           {
+             vr0.type = type = VR_RANGE;
+             vr0.min = vrp_val_min (TREE_TYPE (op0));
+             vr0.max = vrp_val_max (TREE_TYPE (op1));
+           }
+         else
+           {
+             set_value_range_to_varying (vr);
+             return;
+           }
+       }
+
+      /* For divisions, if op0 is VR_RANGE, we can deduce a range
+        even if op1 is VR_VARYING, VR_ANTI_RANGE, symbolic or can
+        include 0.  */
+      if ((code == TRUNC_DIV_EXPR
+          || code == FLOOR_DIV_EXPR
+          || code == CEIL_DIV_EXPR
+          || code == EXACT_DIV_EXPR
+          || code == ROUND_DIV_EXPR)
+         && vr0.type == VR_RANGE
+         && (vr1.type != VR_RANGE
+             || symbolic_range_p (&vr1)
+             || range_includes_zero_p (&vr1)))
+       {
+         tree zero = build_int_cst (TREE_TYPE (vr0.min), 0);
+         int cmp;
+
+         sop = false;
+         min = NULL_TREE;
+         max = NULL_TREE;
+         if (vrp_expr_computes_nonnegative (op1, &sop) && !sop)
+           {
+             /* For unsigned division or when divisor is known
+                to be non-negative, the range has to cover
+                all numbers from 0 to max for positive max
+                and all numbers from min to 0 for negative min.  */
+             cmp = compare_values (vr0.max, zero);
+             if (cmp == -1)
+               max = zero;
+             else if (cmp == 0 || cmp == 1)
+               max = vr0.max;
+             else
+               type = VR_VARYING;
+             cmp = compare_values (vr0.min, zero);
+             if (cmp == 1)
+               min = zero;
+             else if (cmp == 0 || cmp == -1)
+               min = vr0.min;
+             else
+               type = VR_VARYING;
+           }
+         else
+           {
+             /* Otherwise the range is -max .. max or min .. -min
+                depending on which bound is bigger in absolute value,
+                as the division can change the sign.  */
+             abs_extent_range (vr, vr0.min, vr0.max);
+             return;
+           }
+         if (type == VR_VARYING)
+           {
+             set_value_range_to_varying (vr);
+             return;
+           }
+       }
+
       /* Multiplications and divisions are a bit tricky to handle,
         depending on the mix of signs we have in the two ranges, we
         need to operate on different values to get the minimum and
@@ -2286,84 +2388,82 @@ extract_range_from_binary_expr (value_range_t *vr,
         (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
         MAX1) and then figure the smallest and largest values to form
         the new range.  */
-
-      /* Divisions by zero result in a VARYING value.  */
-      else if (code != MULT_EXPR
-              && (vr0.type == VR_ANTI_RANGE || range_includes_zero_p (&vr1)))
-       {
-         set_value_range_to_varying (vr);
-         return;
-       }
-
-      /* Compute the 4 cross operations.  */
-      sop = false;
-      val[0] = vrp_int_const_binop (code, vr0.min, vr1.min);
-      if (val[0] == NULL_TREE)
-       sop = true;
-
-      if (vr1.max == vr1.min)
-       val[1] = NULL_TREE;
       else
        {
-         val[1] = vrp_int_const_binop (code, vr0.min, vr1.max);
-         if (val[1] == NULL_TREE)
-           sop = true;
-       }
+         gcc_assert ((vr0.type == VR_RANGE
+                      || (code == MULT_EXPR && vr0.type == VR_ANTI_RANGE))
+                     && vr0.type == vr1.type);
 
-      if (vr0.max == vr0.min)
-       val[2] = NULL_TREE;
-      else
-       {
-         val[2] = vrp_int_const_binop (code, vr0.max, vr1.min);
-         if (val[2] == NULL_TREE)
+         /* Compute the 4 cross operations.  */
+         sop = false;
+         val[0] = vrp_int_const_binop (code, vr0.min, vr1.min);
+         if (val[0] == NULL_TREE)
            sop = true;
-       }
 
-      if (vr0.min == vr0.max || vr1.min == vr1.max)
-       val[3] = NULL_TREE;
-      else
-       {
-         val[3] = vrp_int_const_binop (code, vr0.max, vr1.max);
-         if (val[3] == NULL_TREE)
-           sop = true;
-       }
+         if (vr1.max == vr1.min)
+           val[1] = NULL_TREE;
+         else
+           {
+             val[1] = vrp_int_const_binop (code, vr0.min, vr1.max);
+             if (val[1] == NULL_TREE)
+               sop = true;
+           }
 
-      if (sop)
-       {
-         set_value_range_to_varying (vr);
-         return;
-       }
+         if (vr0.max == vr0.min)
+           val[2] = NULL_TREE;
+         else
+           {
+             val[2] = vrp_int_const_binop (code, vr0.max, vr1.min);
+             if (val[2] == NULL_TREE)
+               sop = true;
+           }
 
-      /* Set MIN to the minimum of VAL[i] and MAX to the maximum
-        of VAL[i].  */
-      min = val[0];
-      max = val[0];
-      for (i = 1; i < 4; i++)
-       {
-         if (!is_gimple_min_invariant (min)
-             || (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
-             || !is_gimple_min_invariant (max)
-             || (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
-           break;
+         if (vr0.min == vr0.max || vr1.min == vr1.max)
+           val[3] = NULL_TREE;
+         else
+           {
+             val[3] = vrp_int_const_binop (code, vr0.max, vr1.max);
+             if (val[3] == NULL_TREE)
+               sop = true;
+           }
+
+         if (sop)
+           {
+             set_value_range_to_varying (vr);
+             return;
+           }
 
-         if (val[i])
+         /* Set MIN to the minimum of VAL[i] and MAX to the maximum
+            of VAL[i].  */
+         min = val[0];
+         max = val[0];
+         for (i = 1; i < 4; i++)
            {
-             if (!is_gimple_min_invariant (val[i])
-                 || (TREE_OVERFLOW (val[i])
-                     && !is_overflow_infinity (val[i])))
+             if (!is_gimple_min_invariant (min)
+                 || (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
+                 || !is_gimple_min_invariant (max)
+                 || (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
+               break;
+
+             if (val[i])
                {
-                 /* If we found an overflowed value, set MIN and MAX
-                    to it so that we set the resulting range to
-                    VARYING.  */
-                 min = max = val[i];
-                 break;
-               }
+                 if (!is_gimple_min_invariant (val[i])
+                     || (TREE_OVERFLOW (val[i])
+                         && !is_overflow_infinity (val[i])))
+                   {
+                     /* If we found an overflowed value, set MIN and MAX
+                        to it so that we set the resulting range to
+                        VARYING.  */
+                     min = max = val[i];
+                     break;
+                   }
 
-             if (compare_values (val[i], min) == -1)
-               min = val[i];
+                 if (compare_values (val[i], min) == -1)
+                   min = val[i];
 
-             if (compare_values (val[i], max) == 1)
-               max = val[i];
+                 if (compare_values (val[i], max) == 1)
+                   max = val[i];
+               }
            }
        }
     }
@@ -2414,6 +2514,45 @@ extract_range_from_binary_expr (value_range_t *vr,
          return;
        }
     }
+  else if (code == BIT_IOR_EXPR)
+    {
+      if (vr0.type == VR_RANGE
+          && vr1.type == VR_RANGE
+         && TREE_CODE (vr0.min) == INTEGER_CST
+         && TREE_CODE (vr1.min) == INTEGER_CST
+         && TREE_CODE (vr0.max) == INTEGER_CST
+         && TREE_CODE (vr1.max) == INTEGER_CST
+         && tree_int_cst_sgn (vr0.min) >= 0
+         && tree_int_cst_sgn (vr1.min) >= 0)
+       {
+         double_int vr0_max = tree_to_double_int (vr0.max);
+         double_int vr1_max = tree_to_double_int (vr1.max);
+         double_int ior_max;
+
+         /* Set all bits to the right of the most significant one to 1.
+            For example, [0, 4] | [4, 4] = [4, 7]. */
+         ior_max.low = vr0_max.low | vr1_max.low;
+         ior_max.high = vr0_max.high | vr1_max.high;
+         if (ior_max.high != 0)
+           {
+             ior_max.low = ~(unsigned HOST_WIDE_INT)0u;
+             ior_max.high |= ((HOST_WIDE_INT) 1
+                              << floor_log2 (ior_max.high)) - 1;
+           }
+         else if (ior_max.low != 0)
+           ior_max.low |= ((unsigned HOST_WIDE_INT) 1u
+                           << floor_log2 (ior_max.low)) - 1;
+
+         /* Both of these endpoints are conservative.  */
+          min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
+          max = double_int_to_tree (expr_type, ior_max);
+       }
+      else
+       {
+         set_value_range_to_varying (vr);
+         return;
+       }
+    }
   else
     gcc_unreachable ();
 
@@ -2905,7 +3044,8 @@ extract_range_from_comparison (value_range_t *vr, enum tree_code code,
   bool sop = false;
   tree val;
   
-  val = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, false, &sop);
+  val = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, false, &sop,
+                                                NULL);
 
   /* A disadvantage of using a special infinity as an overflow
      representation is that we lose the ability to record overflow
@@ -3785,6 +3925,14 @@ register_new_assert_for (tree name, tree expr,
                && gimple_code (gsi_stmt (si)) != GIMPLE_SWITCH);
 #endif
 
+  /* Never build an assert comparing against an integer constant with
+     TREE_OVERFLOW set.  This confuses our undefined overflow warning
+     machinery.  */
+  if (TREE_CODE (val) == INTEGER_CST
+      && TREE_OVERFLOW (val))
+    val = build_int_cst_wide (TREE_TYPE (val),
+                             TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val));
+
   /* The new assertion A will be inserted at BB or E.  We need to
      determine if the new location is dominated by a previously
      registered location for A.  If we are doing an edge insertion,
@@ -4826,7 +4974,7 @@ insert_range_assertions (void)
    IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR.  */
 
 static void
-check_array_ref (tree ref, const location_t *location, bool ignore_off_by_one)
+check_array_ref (tree ref, location_t location, bool ignore_off_by_one)
 {
   value_range_t* vr = NULL;
   tree low_sub, up_sub;
@@ -4865,8 +5013,8 @@ check_array_ref (tree ref, const location_t *location, bool ignore_off_by_one)
           && TREE_CODE (low_sub) == INTEGER_CST
           && tree_int_cst_lt (low_sub, low_bound))
         {
-          warning (OPT_Warray_bounds,
-                   "%Harray subscript is outside array bounds", location);
+          warning_at (location, OPT_Warray_bounds,
+                     "array subscript is outside array bounds");
           TREE_NO_WARNING (ref) = 1;
         }
     }
@@ -4880,15 +5028,15 @@ check_array_ref (tree ref, const location_t *location, bool ignore_off_by_one)
                                                         0),
                                        up_sub)))
     {
-      warning (OPT_Warray_bounds, "%Harray subscript is above array bounds",
-               location);
+      warning_at (location, OPT_Warray_bounds,
+                 "array subscript is above array bounds");
       TREE_NO_WARNING (ref) = 1;
     }
   else if (TREE_CODE (low_sub) == INTEGER_CST
            && tree_int_cst_lt (low_sub, low_bound))
     {
-      warning (OPT_Warray_bounds, "%Harray subscript is below array bounds",
-               location);
+      warning_at (location, OPT_Warray_bounds,
+                 "array subscript is below array bounds");
       TREE_NO_WARNING (ref) = 1;
     }
 }
@@ -4897,7 +5045,7 @@ check_array_ref (tree ref, const location_t *location, bool ignore_off_by_one)
    address of an ARRAY_REF, and call check_array_ref on it.  */
 
 static void
-search_for_addr_array(tree t, const location_t *location)
+search_for_addr_array (tree t, location_t location)
 {
   while (TREE_CODE (t) == SSA_NAME)
     {
@@ -4906,8 +5054,8 @@ search_for_addr_array(tree t, const location_t *location)
       if (gimple_code (g) != GIMPLE_ASSIGN)
        return;
 
-      if (get_gimple_rhs_class (gimple_assign_rhs_code (g)) !=
-         GIMPLE_SINGLE_RHS)
+      if (get_gimple_rhs_class (gimple_assign_rhs_code (g)) 
+         != GIMPLE_SINGLE_RHS)
        return;
 
       t = gimple_assign_rhs1 (g);
@@ -4924,7 +5072,7 @@ search_for_addr_array(tree t, const location_t *location)
       if (TREE_CODE (t) == ARRAY_REF)
        check_array_ref (t, location, true /*ignore_off_by_one*/);
 
-      t = TREE_OPERAND(t,0);
+      t = TREE_OPERAND (t, 0);
     }
   while (handled_component_p (t));
 }
@@ -4945,11 +5093,11 @@ check_array_bounds (tree *tp, int *walk_subtree, void *data)
   *walk_subtree = TRUE;
 
   if (TREE_CODE (t) == ARRAY_REF)
-    check_array_ref (t, location, false /*ignore_off_by_one*/);
+    check_array_ref (t, *location, false /*ignore_off_by_one*/);
 
   if (TREE_CODE (t) == INDIRECT_REF
       || (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0)))
-    search_for_addr_array (TREE_OPERAND (t, 0), location);
+    search_for_addr_array (TREE_OPERAND (t, 0), *location);
 
   if (TREE_CODE (t) == ADDR_EXPR)
     *walk_subtree = FALSE;
@@ -4971,9 +5119,23 @@ check_all_array_refs (void)
       /* Skip bb's that are clearly unreachable.  */
       if (single_pred_p (bb))
       {
-       basic_block pred_bb = EDGE_PRED (bb, 0)->src;
+       int i;
+       bool reachable = true;
+       edge e2;
+       edge e = EDGE_PRED (bb, 0);
+       basic_block pred_bb = e->src;
        gimple ls = NULL;
 
+       for (i = 0; VEC_iterate (edge, to_remove_edges, i, e2); ++i)
+         if (e == e2)
+           {
+             reachable = false;
+             break;
+           }
+
+       if (!reachable)
+         continue;
+
        if (!gsi_end_p (gsi_last_bb (pred_bb)))
          ls = gsi_stmt (gsi_last_bb (pred_bb));
 
@@ -4987,7 +5149,6 @@ check_all_array_refs (void)
       for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
        {
          gimple stmt = gsi_stmt (si);
-         const location_t *location = gimple_location_ptr (stmt);
          struct walk_stmt_info wi;
          if (!gimple_has_location (stmt))
            continue;
@@ -4999,13 +5160,14 @@ check_all_array_refs (void)
              for (i = 0; i < n; i++)
                {
                  tree arg = gimple_call_arg (stmt, i);
-                 search_for_addr_array (arg, location);
+                 search_for_addr_array (arg, gimple_location (stmt));
                }
            }
          else
            {
              memset (&wi, 0, sizeof (wi));
-             wi.info = CONST_CAST (void *, (const void *) location);
+             wi.info = CONST_CAST (void *, (const void *)
+                                   gimple_location_ptr (stmt));
 
              walk_gimple_op (gsi_stmt (si),
                              check_array_bounds,
@@ -5108,7 +5270,7 @@ stmt_interesting_for_vrp (gimple stmt)
          && ((is_gimple_call (stmt)
               && gimple_call_fndecl (stmt) != NULL_TREE
               && DECL_IS_BUILTIN (gimple_call_fndecl (stmt)))
-             || ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)))
+             || !gimple_vuse (stmt)))
        return true;
     }
   else if (gimple_code (stmt) == GIMPLE_COND
@@ -5439,13 +5601,39 @@ compare_names (enum tree_code comp, tree n1, tree n2,
   return NULL_TREE;
 }
 
+/* Helper function for vrp_evaluate_conditional_warnv.  */
+
+static tree
+vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code code,
+                                                     tree op0, tree op1,
+                                                     bool * strict_overflow_p)
+{
+  value_range_t *vr0, *vr1;
+
+  vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL;
+  vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL;
+
+  if (vr0 && vr1)
+    return compare_ranges (code, vr0, vr1, strict_overflow_p);
+  else if (vr0 && vr1 == NULL)
+    return compare_range_with_value (code, vr0, op1, strict_overflow_p);
+  else if (vr0 == NULL && vr1)
+    return (compare_range_with_value
+           (swap_tree_comparison (code), vr1, op0, strict_overflow_p));
+  return NULL;
+}
+
 /* Helper function for vrp_evaluate_conditional_warnv. */
 
 static tree
 vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, tree op0,
                                         tree op1, bool use_equiv_p,
-                                        bool *strict_overflow_p)
+                                        bool *strict_overflow_p, bool *only_ranges)
 {
+  tree ret;
+  if (only_ranges)
+    *only_ranges = true;
+
   /* We only deal with integral and pointer types.  */
   if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
       && !POINTER_TYPE_P (TREE_TYPE (op0)))
@@ -5453,6 +5641,11 @@ vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, tree op0,
 
   if (use_equiv_p)
     {
+      if (only_ranges
+          && (ret = vrp_evaluate_conditional_warnv_with_ops_using_ranges
+                     (code, op0, op1, strict_overflow_p)))
+       return ret;
+      *only_ranges = false;
       if (TREE_CODE (op0) == SSA_NAME && TREE_CODE (op1) == SSA_NAME)
        return compare_names (code, op0, op1, strict_overflow_p);
       else if (TREE_CODE (op0) == SSA_NAME)
@@ -5462,20 +5655,8 @@ vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, tree op0,
                (swap_tree_comparison (code), op1, op0, strict_overflow_p));
     }
   else
-    {
-      value_range_t *vr0, *vr1;
-
-      vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL;
-      vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL;
-
-      if (vr0 && vr1)
-       return compare_ranges (code, vr0, vr1, strict_overflow_p);
-      else if (vr0 && vr1 == NULL)
-       return compare_range_with_value (code, vr0, op1, strict_overflow_p);
-      else if (vr0 == NULL && vr1)
-       return (compare_range_with_value
-               (swap_tree_comparison (code), vr1, op0, strict_overflow_p));
-    }
+    return vrp_evaluate_conditional_warnv_with_ops_using_ranges (code, op0, op1,
+                                                                strict_overflow_p);
   return NULL_TREE;
 }
 
@@ -5491,9 +5672,11 @@ vrp_evaluate_conditional (enum tree_code code, tree op0, tree op1, gimple stmt)
 {
   bool sop;
   tree ret;
+  bool only_ranges;
 
   sop = false;
-  ret = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, true, &sop);
+  ret = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, true, &sop,
+                                                &only_ranges);
 
   if (ret && sop)
     {
@@ -5526,7 +5709,7 @@ vrp_evaluate_conditional (enum tree_code code, tree op0, tree op1, gimple stmt)
     }
 
   if (warn_type_limits
-      && ret
+      && ret && only_ranges
       && TREE_CODE_CLASS (code) == tcc_comparison
       && TREE_CODE (op0) == SSA_NAME)
     {
@@ -5650,7 +5833,7 @@ vrp_visit_cond_stmt (gimple stmt, edge *taken_edge_p)
   val = vrp_evaluate_conditional_warnv_with_ops (gimple_cond_code (stmt),
                                                 gimple_cond_lhs (stmt),
                                                 gimple_cond_rhs (stmt),
-                                                false, &sop);
+                                                false, &sop, NULL);
   if (val)
     {
       if (!sop)
@@ -5684,7 +5867,7 @@ vrp_visit_cond_stmt (gimple stmt, edge *taken_edge_p)
    If there is a CASE_LABEL for VAL, its index is placed in IDX and true is
    returned.
 
-   If there is no CASE_LABEL for VAL and the is one that is larger than VAL,
+   If there is no CASE_LABEL for VAL and there is one that is larger than VAL,
    it is placed in IDX and false is returned.
 
    If VAL is larger than any CASE_LABEL, n is placed on IDX and false is
@@ -5906,7 +6089,7 @@ vrp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p)
       if ((is_gimple_call (stmt)
           && gimple_call_fndecl (stmt) != NULL_TREE
           && DECL_IS_BUILTIN (gimple_call_fndecl (stmt)))
-         || ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+         || !gimple_vuse (stmt))
        return vrp_visit_assignment_or_call (stmt, output_p);
     }
   else if (gimple_code (stmt) == GIMPLE_COND)
@@ -6170,9 +6353,12 @@ vrp_visit_phi_node (gimple phi)
             minimums.  */
          if (cmp_min > 0 || cmp_min < 0)
            {
-             /* If we will end up with a (-INF, +INF) range, set it
-                to VARYING.  */
-             if (vrp_val_is_max (vr_result.max))
+             /* If we will end up with a (-INF, +INF) range, set it to
+                VARYING.  Same if the previous max value was invalid for
+                the type and we'd end up with vr_result.min > vr_result.max.  */
+             if (vrp_val_is_max (vr_result.max)
+                 || compare_values (TYPE_MIN_VALUE (TREE_TYPE (vr_result.min)),
+                                    vr_result.max) > 0)
                goto varying;
 
              if (!needs_overflow_infinity (TREE_TYPE (vr_result.min))
@@ -6189,9 +6375,12 @@ vrp_visit_phi_node (gimple phi)
             the previous one, go all the way to +INF.  */
          if (cmp_max < 0 || cmp_max > 0)
            {
-             /* If we will end up with a (-INF, +INF) range, set it
-                to VARYING.  */
-             if (vrp_val_is_min (vr_result.min))
+             /* If we will end up with a (-INF, +INF) range, set it to
+                VARYING.  Same if the previous min value was invalid for
+                the type and we'd end up with vr_result.max < vr_result.min.  */
+             if (vrp_val_is_min (vr_result.min)
+                 || compare_values (TYPE_MAX_VALUE (TREE_TYPE (vr_result.max)),
+                                    vr_result.min) < 0)
                goto varying;
 
              if (!needs_overflow_infinity (TREE_TYPE (vr_result.max))
@@ -6220,11 +6409,151 @@ varying:
   return SSA_PROP_VARYING;
 }
 
+/* Simplify boolean operations if the source is known
+   to be already a boolean.  */
+static bool
+simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+{
+  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
+  tree val = NULL;
+  tree op0, op1;
+  value_range_t *vr;
+  bool sop = false;
+  bool need_conversion;
+
+  op0 = gimple_assign_rhs1 (stmt);
+  if (TYPE_PRECISION (TREE_TYPE (op0)) != 1)
+    {
+      if (TREE_CODE (op0) != SSA_NAME)
+       return false;
+      vr = get_value_range (op0);
+
+      val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
+      if (!val || !integer_onep (val))
+        return false;
+
+      val = compare_range_with_value (LE_EXPR, vr, integer_one_node, &sop);
+      if (!val || !integer_onep (val))
+        return false;
+    }
+
+  if (rhs_code == TRUTH_NOT_EXPR)
+    {
+      rhs_code = NE_EXPR;
+      op1 = build_int_cst (TREE_TYPE (op0), 1);
+    }
+  else
+    {
+      op1 = gimple_assign_rhs2 (stmt);
+
+      /* Reduce number of cases to handle.  */
+      if (is_gimple_min_invariant (op1))
+       {
+          /* Exclude anything that should have been already folded.  */
+         if (rhs_code != EQ_EXPR
+             && rhs_code != NE_EXPR
+             && rhs_code != TRUTH_XOR_EXPR)
+           return false;
+
+         if (!integer_zerop (op1)
+             && !integer_onep (op1)
+             && !integer_all_onesp (op1))
+           return false;
+
+         /* Limit the number of cases we have to consider.  */
+         if (rhs_code == EQ_EXPR)
+           {
+             rhs_code = NE_EXPR;
+             op1 = fold_unary (TRUTH_NOT_EXPR, TREE_TYPE (op1), op1);
+           }
+       }
+      else
+       {
+         /* Punt on A == B as there is no BIT_XNOR_EXPR.  */
+         if (rhs_code == EQ_EXPR)
+           return false;
+
+         if (TYPE_PRECISION (TREE_TYPE (op1)) != 1)
+           {
+             vr = get_value_range (op1);
+             val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
+             if (!val || !integer_onep (val))
+               return false;
+
+             val = compare_range_with_value (LE_EXPR, vr, integer_one_node, &sop);
+             if (!val || !integer_onep (val))
+               return false;
+           }
+       }
+    }
+
+  if (sop && issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_MISC))
+    {
+      location_t location;
+
+      if (!gimple_has_location (stmt))
+       location = input_location;
+      else
+       location = gimple_location (stmt);
+
+      if (rhs_code == TRUTH_AND_EXPR || rhs_code == TRUTH_OR_EXPR)
+        warning_at (location, OPT_Wstrict_overflow,
+                   _("assuming signed overflow does not occur when "
+                     "simplifying && or || to & or |"));
+      else
+        warning_at (location, OPT_Wstrict_overflow,
+                   _("assuming signed overflow does not occur when "
+                     "simplifying ==, != or ! to identity or ^"));
+    }
+
+  need_conversion =
+    !useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (stmt)),
+                               TREE_TYPE (op0));
+
+  /* Make sure to not sign-extend -1 as a boolean value.  */
+  if (need_conversion
+      && !TYPE_UNSIGNED (TREE_TYPE (op0))
+      && TYPE_PRECISION (TREE_TYPE (op0)) == 1)
+    return false;
+
+  switch (rhs_code)
+    {
+    case TRUTH_AND_EXPR:
+      rhs_code = BIT_AND_EXPR;
+      break;
+    case TRUTH_OR_EXPR:
+      rhs_code = BIT_IOR_EXPR;
+      break;
+    case TRUTH_XOR_EXPR:
+    case NE_EXPR:
+      if (integer_zerop (op1))
+       {
+         gimple_assign_set_rhs_with_ops (gsi,
+                                         need_conversion ? NOP_EXPR : SSA_NAME,
+                                         op0, NULL);
+         update_stmt (gsi_stmt (*gsi));
+         return true;
+       }
+
+      rhs_code = BIT_XOR_EXPR;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (need_conversion)
+    return false;
+
+  gimple_assign_set_rhs_with_ops (gsi, rhs_code, op0, op1);
+  update_stmt (gsi_stmt (*gsi));
+  return true;
+}
+
 /* 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
+static bool
 simplify_div_or_mod_using_ranges (gimple stmt)
 {
   enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
@@ -6284,14 +6613,17 @@ simplify_div_or_mod_using_ranges (gimple stmt)
        }
 
       update_stmt (stmt);
+      return true;
     }
+
+  return false;
 }
 
 /* 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.  */
 
-static void
+static bool
 simplify_abs_using_ranges (gimple stmt)
 {
   tree val = NULL;
@@ -6346,8 +6678,11 @@ simplify_abs_using_ranges (gimple stmt)
          else
            gimple_assign_set_rhs_code (stmt, SSA_NAME);
          update_stmt (stmt);
+         return true;
        }
     }
+
+  return false;
 }
 
 /* We are comparing trees OP0 and OP1 using COND_CODE.  OP0 has
@@ -6422,7 +6757,7 @@ test_for_singularity (enum tree_code cond_code, tree op0,
    test if the range information indicates only one value can satisfy
    the original conditional.  */
 
-static void
+static bool
 simplify_cond_using_ranges (gimple stmt)
 {
   tree op0 = gimple_cond_lhs (stmt);
@@ -6463,8 +6798,8 @@ simplify_cond_using_ranges (gimple stmt)
                  print_gimple_stmt (dump_file, stmt, 0, 0);
                  fprintf (dump_file, "\n");
                }
-             return;
 
+             return true;
            }
 
          /* Try again after inverting the condition.  We only deal
@@ -6493,17 +6828,19 @@ simplify_cond_using_ranges (gimple stmt)
                  print_gimple_stmt (dump_file, stmt, 0, 0);
                  fprintf (dump_file, "\n");
                }
-             return;
 
+             return true;
            }
        }
     }
+
+  return false;
 }
 
 /* Simplify a switch statement using the value range of the switch
    argument.  */
 
-static void
+static bool
 simplify_switch_using_ranges (gimple stmt)
 {
   tree op = gimple_switch_index (stmt);
@@ -6515,25 +6852,41 @@ simplify_switch_using_ranges (gimple stmt)
   tree vec2;
   switch_update su;
 
-  if (TREE_CODE (op) != SSA_NAME)
-    return;
+  if (TREE_CODE (op) == SSA_NAME)
+    {
+      vr = get_value_range (op);
 
-  vr = get_value_range (op);
+      /* We can only handle integer ranges.  */
+      if (vr->type != VR_RANGE
+         || symbolic_range_p (vr))
+       return false;
 
-  /* We can only handle integer ranges.  */
-  if (vr->type != VR_RANGE
-      || symbolic_range_p (vr))
-    return;
+      /* Find case label for min/max of the value range.  */
+      take_default = !find_case_label_range (stmt, vr->min, vr->max, &i, &j);
+    }
+  else if (TREE_CODE (op) == INTEGER_CST)
+    {
+      take_default = !find_case_label_index (stmt, 1, op, &i);
+      if (take_default)
+       {
+         i = 1;
+         j = 0;
+       }
+      else 
+       {
+         j = i;
+       }
+    }
+  else
+    return false;
 
-  /* Find case label for min/max of the value range.  */
   n = gimple_switch_num_labels (stmt);
-  take_default = !find_case_label_range (stmt, vr->min, vr->max, &i, &j);
 
   /* Bail out if this is just all edges taken.  */
   if (i == 1
       && j == n - 1
       && take_default)
-    return;
+    return false;
 
   /* Build a new vector of taken case labels.  */
   vec2 = make_tree_vec (j - i + 1 + (int)take_default);
@@ -6574,35 +6927,62 @@ simplify_switch_using_ranges (gimple stmt)
   su.stmt = stmt;
   su.vec = vec2;
   VEC_safe_push (switch_update, heap, to_update_switch_stmts, &su);
+  return false;
 }
 
 /* Simplify STMT using ranges if possible.  */
 
-void
-simplify_stmt_using_ranges (gimple stmt)
+bool
+simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
 {
+  gimple stmt = gsi_stmt (*gsi);
   if (is_gimple_assign (stmt))
     {
       enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
 
+      switch (rhs_code)
+       {
+       case EQ_EXPR:
+       case NE_EXPR:
+       case TRUTH_NOT_EXPR:
+       case TRUTH_AND_EXPR:
+       case TRUTH_OR_EXPR:
+        case TRUTH_XOR_EXPR:
+          /* Transform EQ_EXPR, NE_EXPR, TRUTH_NOT_EXPR into BIT_XOR_EXPR
+            or identity if the RHS is zero or one, and the LHS are known
+            to be boolean values.  Transform all TRUTH_*_EXPR into
+             BIT_*_EXPR if both arguments are known to be boolean values.  */
+         if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
+           return simplify_truth_ops_using_ranges (gsi, stmt);
+         break;
+
       /* 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 (gimple_assign_rhs1 (stmt)))
-         && integer_pow2p (gimple_assign_rhs2 (stmt)))
-       simplify_div_or_mod_using_ranges (stmt);
+       case TRUNC_DIV_EXPR:
+       case TRUNC_MOD_EXPR:
+         if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))
+             && integer_pow2p (gimple_assign_rhs2 (stmt)))
+           return simplify_div_or_mod_using_ranges (stmt);
+         break;
 
       /* Transform ABS (X) into X or -X as appropriate.  */
-      if (rhs_code == ABS_EXPR
-         && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
-         && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
-       simplify_abs_using_ranges (stmt);
+       case ABS_EXPR:
+         if (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+             && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
+           return simplify_abs_using_ranges (stmt);
+         break;
+
+       default:
+         break;
+       }
     }
   else if (gimple_code (stmt) == GIMPLE_COND)
-    simplify_cond_using_ranges (stmt);
+    return simplify_cond_using_ranges (stmt);
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
-    simplify_switch_using_ranges (stmt);
+    return simplify_switch_using_ranges (stmt);
+
+  return false;
 }
 
 /* Stack of dest,src equivalency pairs that need to be restored after
@@ -6909,9 +7289,16 @@ execute_vrp (void)
     {
       size_t j;
       size_t n = TREE_VEC_LENGTH (su->vec);
+      tree label;
       gimple_switch_set_num_labels (su->stmt, n);
       for (j = 0; j < n; j++)
        gimple_switch_set_label (su->stmt, j, TREE_VEC_ELT (su->vec, j));
+      /* As we may have replaced the default label with a regular one
+        make sure to make it a real default label again.  This ensures
+        optimal expansion.  */
+      label = gimple_switch_default_label (su->stmt);
+      CASE_LOW (label) = NULL_TREE;
+      CASE_HIGH (label) = NULL_TREE;
     }
 
   if (VEC_length (edge, to_remove_edges) > 0)