OSDN Git Service

revert another accidental check-in
[pf3gnuchains/gcc-fork.git] / gcc / tree-vrp.c
index d77653f..404531f 100644 (file)
@@ -1,5 +1,5 @@
 /* Support routines for Value Range Propagation (VRP).
-   Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>.
 
 This file is part of GCC.
@@ -46,7 +46,6 @@ static sbitmap found_in_subgraph;
 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 (tree, bool, bool *);
 static tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
                                                     tree, tree, bool, bool *);
 
@@ -104,6 +103,16 @@ static value_range_t **vr_value;
    node.  */
 static int *vr_phi_edge_counts;
 
+typedef struct {
+  tree stmt;
+  tree vec;
+} switch_update;
+
+static VEC (edge, heap) *to_remove_edges;
+DEF_VEC_O(switch_update);
+DEF_VEC_ALLOC_O(switch_update, heap);
+static VEC (switch_update, heap) *to_update_switch_stmts;
+
 
 /* Return the maximum value for TYPEs base type.  */
 
@@ -763,7 +772,9 @@ usable_range_p (value_range_t *vr, bool *strict_overflow_p)
 static bool
 vrp_expr_computes_nonnegative (tree expr, bool *strict_overflow_p)
 {
-  return tree_expr_nonnegative_warnv_p (expr, strict_overflow_p);
+  return (tree_expr_nonnegative_warnv_p (expr, strict_overflow_p)
+         || (TREE_CODE (expr) == SSA_NAME
+             && ssa_name_nonnegative_p (expr)));
 }
 
 /* Like tree_expr_nonzero_warnv_p, but this function uses value ranges
@@ -772,7 +783,9 @@ vrp_expr_computes_nonnegative (tree expr, bool *strict_overflow_p)
 static bool
 vrp_expr_computes_nonzero (tree expr, bool *strict_overflow_p)
 {
-  if (tree_expr_nonzero_warnv_p (expr, strict_overflow_p))
+  if (tree_expr_nonzero_warnv_p (expr, strict_overflow_p)
+      || (TREE_CODE (expr) == SSA_NAME
+         && ssa_name_nonzero_p (expr)))
     return true;
 
   /* If we have an expression of the form &X->a, then the expression
@@ -1572,7 +1585,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
                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
+                   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
@@ -1877,8 +1890,6 @@ extract_range_from_binary_expr (value_range_t *vr,
       && 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)
     {
@@ -1965,9 +1976,7 @@ extract_range_from_binary_expr (value_range_t *vr,
 
   /* For integer ranges, apply the operation to each end of the
      range and see what we end up with.  */
-  if (code == TRUTH_ANDIF_EXPR
-      || code == TRUTH_ORIF_EXPR
-      || code == TRUTH_AND_EXPR
+  if (code == TRUTH_AND_EXPR
       || code == TRUTH_OR_EXPR)
     {
       /* If one of the operands is zero, we know that the whole
@@ -2286,7 +2295,6 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
   if (code == FIX_TRUNC_EXPR
       || code == FLOAT_EXPR
       || code == BIT_NOT_EXPR
-      || code == NON_LVALUE_EXPR
       || code == CONJ_EXPR)
     {
       set_value_range_to_varying (vr);
@@ -2340,71 +2348,63 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
     }
 
   /* Handle unary expressions on integer ranges.  */
-  if (code == NOP_EXPR || code == CONVERT_EXPR)
+  if ((code == NOP_EXPR
+       || code == CONVERT_EXPR)
+      && INTEGRAL_TYPE_P (type)
+      && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
     {
       tree inner_type = TREE_TYPE (op0);
       tree outer_type = type;
 
-      /* If VR0 represents a simple range, then try to convert
-        the min and max values for the range to the same type
-        as OUTER_TYPE.  If the results compare equal to VR0's
-        min and max values and the new min is still less than
-        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
-          && !overflow_infinity_range_p (&vr0))
-         || (vr0.type == VR_VARYING
-             && TYPE_PRECISION (outer_type) > TYPE_PRECISION (inner_type)))
+      /* Always use base-types here.  This is important for the
+        correct signedness.  */
+      if (TREE_TYPE (inner_type))
+       inner_type = TREE_TYPE (inner_type);
+      if (TREE_TYPE (outer_type))
+       outer_type = TREE_TYPE (outer_type);
+
+      /* If VR0 is varying and we increase the type precision, assume
+        a full range for the following transformation.  */
+      if (vr0.type == VR_VARYING
+         && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
        {
-         tree new_min, new_max, orig_min, orig_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 the original input's
-            min/max values.  */
-         if (is_gimple_val (new_min)
-             && is_gimple_val (new_max)
-             && tree_int_cst_equal (new_min, orig_min)
-             && tree_int_cst_equal (new_max, orig_max)
-             && (!is_overflow_infinity (new_min)
-                 || !is_overflow_infinity (new_max))
-             && (cmp = compare_values (new_min, new_max)) <= 0
-             && cmp >= -1)
-           {
-             set_value_range (vr, VR_RANGE, new_min, new_max, vr->equiv);
-             return;
-           }
+         vr0.type = VR_RANGE;
+         vr0.min = TYPE_MIN_VALUE (inner_type);
+         vr0.max = TYPE_MAX_VALUE (inner_type);
        }
 
-      /* When converting types of different sizes, set the result to
-        VARYING.  Things like sign extensions and precision loss may
-        change the range.  For instance, if x_3 is of type 'long long
-        int' and 'y_5 = (unsigned short) x_3', if x_3 is ~[0, 0], it
-        is impossible to know at compile time whether y_5 will be
-        ~[0, 0].  */
-      if (TYPE_SIZE (inner_type) != TYPE_SIZE (outer_type)
-         || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
+      /* If VR0 is a constant range or anti-range and the conversion is
+        not truncating we can convert the min and max values and
+        canonicalize the resulting range.  Otherwise we can do the
+        conversion if the size of the range is less than what the
+        precision of the target type can represent and the range is
+        not an anti-range.  */
+      if ((vr0.type == VR_RANGE
+          || vr0.type == VR_ANTI_RANGE)
+         && TREE_CODE (vr0.min) == INTEGER_CST
+         && TREE_CODE (vr0.max) == INTEGER_CST
+         && !is_overflow_infinity (vr0.min)
+         && !is_overflow_infinity (vr0.max)
+         && (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type)
+             || (vr0.type == VR_RANGE
+                 && integer_zerop (int_const_binop (RSHIFT_EXPR,
+                      int_const_binop (MINUS_EXPR, vr0.max, vr0.min, 0),
+                        size_int (TYPE_PRECISION (outer_type)), 0)))))
        {
-         set_value_range_to_varying (vr);
+         tree new_min, new_max;
+         new_min = force_fit_type_double (outer_type,
+                                          TREE_INT_CST_LOW (vr0.min),
+                                          TREE_INT_CST_HIGH (vr0.min), 0, 0);
+         new_max = force_fit_type_double (outer_type,
+                                          TREE_INT_CST_LOW (vr0.max),
+                                          TREE_INT_CST_HIGH (vr0.max), 0, 0);
+         set_and_canonicalize_value_range (vr, vr0.type,
+                                           new_min, new_max, NULL);
          return;
        }
+
+      set_value_range_to_varying (vr);
+      return;
     }
 
   /* Conversion of a VR_VARYING value to a wider type can result
@@ -2749,8 +2749,6 @@ extract_range_from_expr (value_range_t *vr, tree expr)
   else if (code == SSA_NAME)
     extract_range_from_ssa_name (vr, expr);
   else if (TREE_CODE_CLASS (code) == tcc_binary
-          || code == TRUTH_ANDIF_EXPR
-          || code == TRUTH_ORIF_EXPR
           || code == TRUTH_AND_EXPR
           || code == TRUTH_OR_EXPR
           || code == TRUTH_XOR_EXPR)
@@ -2805,13 +2803,6 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
   if (vr->type == VR_ANTI_RANGE)
     return;
 
-  /* Ensure that there are not values in the scev cache based on assumptions
-     on ranges of ssa names that were changed
-     (in set_value_range/set_value_range_to_varying).  Preserve cached numbers
-     of iterations, that were computed before the start of VRP (we do not
-     recompute these each time to save the compile time).  */
-  scev_reset_except_niters ();
-
   chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
 
   /* Like in PR19590, scev can return a constant function.  */
@@ -3803,12 +3794,10 @@ register_edge_assert_for_2 (tree name, edge e, block_stmt_iterator bsi,
 
       /* Extract NAME2 from the (optional) sign-changing cast.  */
       if (TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT
-          && (TREE_CODE (GIMPLE_STMT_OPERAND (def_stmt, 1)) == NOP_EXPR
-             || TREE_CODE (GIMPLE_STMT_OPERAND (def_stmt, 1)) == CONVERT_EXPR))
+          && CONVERT_EXPR_P (GIMPLE_STMT_OPERAND (def_stmt, 1)))
        {
          tree rhs = GIMPLE_STMT_OPERAND (def_stmt, 1);
-         if ((TREE_CODE (rhs) == NOP_EXPR
-              || TREE_CODE (rhs) == CONVERT_EXPR)
+         if (CONVERT_EXPR_P (rhs)
              && ! TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (rhs, 0)))
              && (TYPE_PRECISION (TREE_TYPE (rhs))
                  == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (rhs, 0)))))
@@ -3960,9 +3949,7 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
       /* 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) == NON_LVALUE_EXPR)
+  else if (CONVERT_EXPR_P (rhs))
     { 
       /* Recurse through the type conversion.  */
       retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 0),
@@ -4550,9 +4537,8 @@ process_assert_insertions (void)
   if (update_edges_p)
     bsi_commit_edge_inserts ();
 
-  if (dump_file && (dump_flags & TDF_STATS))
-    fprintf (dump_file, "\nNumber of ASSERT_EXPR expressions inserted: %d\n\n",
-            num_asserts);
+  statistics_counter_event (cfun, "Number of ASSERT_EXPR expressions inserted",
+                           num_asserts);
 }
 
 
@@ -5278,64 +5264,7 @@ vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, tree op0,
   return NULL_TREE;
 }
 
-/* Given a conditional predicate COND, try to determine if COND yields
-   true or false based on the value ranges of its operands.  Return
-   BOOLEAN_TRUE_NODE if the conditional always evaluates to true,
-   BOOLEAN_FALSE_NODE if the conditional always evaluates to false, and,
-   NULL if the conditional cannot be evaluated at compile time.
-
-   If USE_EQUIV_P is true, the ranges of all the names equivalent with
-   the operands in COND are used when trying to compute its value.
-   This is only used during final substitution.  During propagation,
-   we only check the range of each variable and not its equivalents.
-
-   Set *STRICT_OVERFLOW_P to indicate whether we relied on an overflow
-   infinity to produce the result.  */
-
-static tree
-vrp_evaluate_conditional_warnv (tree cond, bool use_equiv_p,
-                               bool *strict_overflow_p)
-{
-  gcc_assert (TREE_CODE (cond) == SSA_NAME
-              || TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison);
-
-  if (TREE_CODE (cond) == SSA_NAME)
-    {
-      value_range_t *vr;
-      tree retval;
-
-      if (use_equiv_p)
-       retval = compare_name_with_value (NE_EXPR, cond, boolean_false_node,
-                                         strict_overflow_p);
-      else
-       {
-         value_range_t *vr = get_value_range (cond);
-         retval = compare_range_with_value (NE_EXPR, vr, boolean_false_node,
-                                            strict_overflow_p);
-       }
-
-      /* If COND has a known boolean range, return it.  */
-      if (retval)
-       return retval;
-
-      /* Otherwise, if COND has a symbolic range of exactly one value,
-        return it.  */
-      vr = get_value_range (cond);
-      if (vr->type == VR_RANGE && vr->min == vr->max)
-       return vr->min;
-    }
-  else
-    return vrp_evaluate_conditional_warnv_with_ops (TREE_CODE (cond),
-                                                   TREE_OPERAND (cond, 0),
-                                                   TREE_OPERAND (cond, 1),
-                                                   use_equiv_p,
-                                                   strict_overflow_p);
-
-  /* Anything else cannot be computed statically.  */
-  return NULL_TREE;
-}
-
-/* Given COND within STMT, try to simplify it based on value range
+/* Given (CODE OP0 OP1) within STMT, try to simplify it based on value range
    information.  Return NULL if the conditional can not be evaluated.
    The ranges of all the names equivalent with the operands in COND
    will be used when trying to compute the value.  If the result is
@@ -5343,13 +5272,17 @@ vrp_evaluate_conditional_warnv (tree cond, bool use_equiv_p,
    appropriate.  */
 
 tree
-vrp_evaluate_conditional (tree cond, tree stmt)
+vrp_evaluate_conditional (enum tree_code code, tree op0, tree op1, tree stmt)
 {
   bool sop;
   tree ret;
 
   sop = false;
-  ret = vrp_evaluate_conditional_warnv (cond, true, &sop);
+  ret = vrp_evaluate_conditional_warnv_with_ops (code,
+                                                op0,
+                                                op1,
+                                                true,
+                                                &sop);
 
   if (ret && sop)
     {
@@ -5383,7 +5316,8 @@ vrp_evaluate_conditional (tree cond, tree stmt)
 
   if (warn_type_limits
       && ret
-      && TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison)
+      && TREE_CODE_CLASS (code) == tcc_comparison
+      && TREE_CODE (op0) == SSA_NAME)
     {
       /* If the comparison is being folded and the operand on the LHS
         is being compared against a constant value that is outside of
@@ -5391,8 +5325,6 @@ vrp_evaluate_conditional (tree cond, tree stmt)
         always fold regardless of the value of OP0.  If -Wtype-limits
         was specified, emit a warning.  */
       const char *warnmsg = NULL;
-      tree op0 = TREE_OPERAND (cond, 0);
-      tree op1 = TREE_OPERAND (cond, 1);
       tree type = TREE_TYPE (op0);
       value_range_t *vr0 = get_value_range (op0);
 
@@ -5439,11 +5371,6 @@ vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p)
   bool sop;
 
   *taken_edge_p = NULL;
-
-  /* FIXME.  Handle SWITCH_EXPRs.  */
-  if (TREE_CODE (stmt) == SWITCH_EXPR)
-    return SSA_PROP_VARYING;
-
   cond = COND_EXPR_COND (stmt);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -5509,7 +5436,19 @@ vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p)
      MICO, TRAMP3D and SPEC2000) showed that doing this results in
      4 more predicates folded in SPEC.  */
   sop = false;
-  val = vrp_evaluate_conditional_warnv (cond, false, &sop);
+
+  if (TREE_CODE (cond) == SSA_NAME)
+    val = vrp_evaluate_conditional_warnv_with_ops (EQ_EXPR,
+                                                  cond,
+                                                  boolean_true_node,
+                                                  false,
+                                                  &sop);
+  else
+    val = vrp_evaluate_conditional_warnv_with_ops (TREE_CODE (cond),
+                                                  TREE_OPERAND (cond, 0),
+                                                  TREE_OPERAND (cond, 1),
+                                                  false,
+                                                  &sop);
   if (val)
     {
       if (!sop)
@@ -5536,6 +5475,203 @@ vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p)
   return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING;
 }
 
+/* Searches the case label vector VEC for the index *IDX of the CASE_LABEL
+   that includes the value VAL.  The search is restricted to the range
+   [START_IDX, n - 2] where n is the size of VEC (n - 1 is the default label).
+
+   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,
+   it is placed in IDX and false is returned.
+
+   If VAL is larger than any CASE_LABEL, n - 1 is placed on IDX and false is
+   returned. */
+
+static bool
+find_case_label_index (tree vec, size_t start_idx, tree val, size_t *idx)
+{
+  size_t n = TREE_VEC_LENGTH (vec);
+  size_t low, high;
+
+  /* Find case label for minimum of the value range or the next one.
+     At each iteration we are searching in [low, high - 1]. */
+
+  for (low = start_idx, high = n - 1; high != low; )
+    {
+      tree t;
+      int cmp;
+      /* Note that i != high, so we never ask for n - 1. */
+      size_t i = (high + low) / 2;
+      t = TREE_VEC_ELT (vec, i);
+
+      /* Cache the result of comparing CASE_LOW and val.  */
+      cmp = tree_int_cst_compare (CASE_LOW (t), val);
+
+      if (cmp == 0)
+       {
+         /* Ranges cannot be empty. */
+         *idx = i;
+         return true;
+       }
+      else if (cmp > 0)
+        high = i;
+      else
+       {
+         low = i + 1;
+         if (CASE_HIGH (t) != NULL
+             && tree_int_cst_compare (CASE_HIGH (t), val) >= 0)
+           {
+             *idx = i;
+             return true;
+           }
+        }
+    }
+
+  *idx = high;
+  return false;
+}
+
+/* Searches the case label vector VEC for the range of CASE_LABELs that is used
+   for values between MIN and MAX. The first index is placed in MIN_IDX. The
+   last index is placed in MAX_IDX. If the range of CASE_LABELs is empty
+   then MAX_IDX < MIN_IDX.
+   Returns true if the default label is not needed. */
+
+static bool
+find_case_label_range (tree vec, tree min, tree max, size_t *min_idx, size_t *max_idx)
+{
+  size_t i, j;
+  bool min_take_default = !find_case_label_index (vec, 0, min, &i);
+  bool max_take_default = !find_case_label_index (vec, i, max, &j);
+
+  if (i == j
+      && min_take_default
+      && max_take_default)
+    {
+      /* Only the default case label reached. 
+         Return an empty range. */
+      *min_idx = 1;
+      *max_idx = 0;
+      return false;
+    }
+  else
+    {
+      bool take_default = min_take_default || max_take_default;
+      tree low, high;
+      size_t k;
+
+      if (max_take_default)
+       j--;
+
+      /* If the case label range is continuous, we do not need
+        the default case label.  Verify that.  */
+      high = CASE_LOW (TREE_VEC_ELT (vec, i));
+      if (CASE_HIGH (TREE_VEC_ELT (vec, i)))
+       high = CASE_HIGH (TREE_VEC_ELT (vec, i));
+      for (k = i + 1; k <= j; ++k)
+       {
+         low = CASE_LOW (TREE_VEC_ELT (vec, k));
+         if (!integer_onep (int_const_binop (MINUS_EXPR, low, high, 0)))
+           {
+             take_default = true;
+             break;
+           }
+         high = low;
+         if (CASE_HIGH (TREE_VEC_ELT (vec, k)))
+           high = CASE_HIGH (TREE_VEC_ELT (vec, k));
+       }
+
+      *min_idx = i;
+      *max_idx = j;
+      return !take_default;
+    }
+}
+
+/* Visit switch statement STMT.  If we can determine which edge
+   will be taken out of STMT's basic block, record it in
+   *TAKEN_EDGE_P and return SSA_PROP_INTERESTING.  Otherwise, return
+   SSA_PROP_VARYING.  */
+
+static enum ssa_prop_result
+vrp_visit_switch_stmt (tree stmt, edge *taken_edge_p)
+{
+  tree op, val;
+  value_range_t *vr;
+  size_t i = 0, j = 0, n;
+  tree vec;
+  bool take_default;
+
+  *taken_edge_p = NULL;
+  op = TREE_OPERAND (stmt, 0);
+  if (TREE_CODE (op) != SSA_NAME)
+    return SSA_PROP_VARYING;
+
+  vr = get_value_range (op);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "\nVisiting switch expression with operand ");
+      print_generic_expr (dump_file, op, 0);
+      fprintf (dump_file, " with known range ");
+      dump_value_range (dump_file, vr);
+      fprintf (dump_file, "\n");
+    }
+
+  if (vr->type != VR_RANGE
+      || symbolic_range_p (vr))
+    return SSA_PROP_VARYING;
+
+  /* Find the single edge that is taken from the switch expression.  */
+  vec = SWITCH_LABELS (stmt);
+  n = TREE_VEC_LENGTH (vec);
+
+  take_default = !find_case_label_range (vec, vr->min, vr->max, &i, &j);
+
+  /* Check if the range spans no CASE_LABEL. If so, we only reach the default
+     label */
+  if (j < i)
+    {
+      gcc_assert (take_default);
+      val = TREE_VEC_ELT (vec, n - 1);
+    }
+  else
+    {
+      /* Check if labels with index i to j and maybe the default label
+        are all reaching the same label.  */
+
+      val = TREE_VEC_ELT (vec, i);
+      if (take_default
+         && CASE_LABEL (TREE_VEC_ELT (vec, n - 1)) != CASE_LABEL (val))
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file, "  not a single destination for this "
+                    "range\n");
+          return SSA_PROP_VARYING;
+       }
+      for (++i; i <= j; ++i)
+        {
+          if (CASE_LABEL (TREE_VEC_ELT (vec, i)) != CASE_LABEL (val))
+           {
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               fprintf (dump_file, "  not a single destination for this "
+                        "range\n");
+             return SSA_PROP_VARYING;
+           }
+        }
+    }
+
+  *taken_edge_p = find_edge (bb_for_stmt (stmt),
+                            label_to_block (CASE_LABEL (val)));
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "  will take edge to ");
+      print_generic_stmt (dump_file, CASE_LABEL (val), 0);
+    }
+
+  return SSA_PROP_INTERESTING;
+}
+
 
 /* Evaluate statement STMT.  If the statement produces a useful range,
    return SSA_PROP_INTERESTING and record the SSA name with the
@@ -5575,8 +5711,10 @@ vrp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
          || 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)
+  else if (TREE_CODE (stmt) == COND_EXPR)
     return vrp_visit_cond_stmt (stmt, taken_edge_p);
+  else if (TREE_CODE (stmt) == SWITCH_EXPR)
+    return vrp_visit_switch_stmt (stmt, taken_edge_p);
 
   /* All other statements produce nothing of interest for VRP, so mark
      their outputs varying and prevent further simulation.  */
@@ -6160,6 +6298,81 @@ simplify_cond_using_ranges (tree stmt)
     }
 }
 
+/* Simplify a switch statement using the value range of the switch
+   argument.  */
+
+static void
+simplify_switch_using_ranges (tree stmt)
+{
+  tree op = TREE_OPERAND (stmt, 0);
+  value_range_t *vr;
+  bool take_default;
+  edge e;
+  edge_iterator ei;
+  size_t i = 0, j = 0, n, n2;
+  tree vec, vec2;
+  switch_update su;
+
+  if (TREE_CODE (op) != SSA_NAME)
+    return;
+
+  vr = get_value_range (op);
+
+  /* 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.  */
+  vec = SWITCH_LABELS (stmt);
+  n = TREE_VEC_LENGTH (vec);
+  take_default = !find_case_label_range (vec, vr->min, vr->max, &i, &j);
+
+  /* Bail out if this is just all edges taken.  */
+  if (i == 0
+      && j == n - 2
+      && take_default)
+    return;
+
+  /* Build a new vector of taken case labels.  */
+  vec2 = make_tree_vec (j - i + 1 + (int)take_default);
+  for (n2 = 0; i <= j; ++i, ++n2)
+    TREE_VEC_ELT (vec2, n2) = TREE_VEC_ELT (vec, i);
+
+  /* Add the default edge, if necessary.  */
+  if (take_default)
+    TREE_VEC_ELT (vec2, n2++) = TREE_VEC_ELT (vec, n - 1);
+
+  /* Mark needed edges.  */
+  for (i = 0; i < n2; ++i)
+    {
+      e = find_edge (bb_for_stmt (stmt),
+                    label_to_block (CASE_LABEL (TREE_VEC_ELT (vec2, i))));
+      e->aux = (void *)-1;
+    }
+
+  /* Queue not needed edges for later removal.  */
+  FOR_EACH_EDGE (e, ei, bb_for_stmt (stmt)->succs)
+    {
+      if (e->aux == (void *)-1)
+       {
+         e->aux = NULL;
+         continue;
+       }
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "removing unreachable case label\n");
+       }
+      VEC_safe_push (edge, heap, to_remove_edges, e);
+    }
+
+  /* And queue an update for the stmt.  */
+  su.stmt = stmt;
+  su.vec = vec2;
+  VEC_safe_push (switch_update, heap, to_update_switch_stmts, &su);
+}
+
 /* Simplify STMT using ranges if possible.  */
 
 void
@@ -6186,9 +6399,9 @@ simplify_stmt_using_ranges (tree stmt)
     }
   else if (TREE_CODE (stmt) == COND_EXPR
           && COMPARISON_CLASS_P (COND_EXPR_COND (stmt)))
-    {
-      simplify_cond_using_ranges (stmt);
-    }
+    simplify_cond_using_ranges (stmt);
+  else if (TREE_CODE (stmt) == SWITCH_EXPR)
+    simplify_switch_using_ranges (stmt);
 }
 
 /* Stack of dest,src equivalency pairs that need to be restored after
@@ -6206,17 +6419,28 @@ static VEC(tree,heap) *stack;
 static tree
 simplify_stmt_for_jump_threading (tree stmt, tree within_stmt)
 {
+  tree conditional;
   /* 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), within_stmt);
+  conditional = COND_EXPR_COND (stmt);
+  if (TREE_CODE (conditional) == SSA_NAME)
+    return vrp_evaluate_conditional (EQ_EXPR,
+                                    conditional,
+                                    boolean_true_node,
+                                    within_stmt);
+  else
+    return vrp_evaluate_conditional (TREE_CODE (conditional),
+                                    TREE_OPERAND (conditional, 0),
+                                    TREE_OPERAND (conditional, 1),
+                                    within_stmt);
 }
 
 /* Blocks which have more than one predecessor and more than
-   one successor present jump threading opportunities.  ie,
+   one successor present jump threading opportunities, i.e.,
    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
@@ -6240,6 +6464,8 @@ identify_jump_threads (void)
 {
   basic_block bb;
   tree dummy;
+  int i;
+  edge e;
 
   /* Ugh.  When substituting values earlier in this pass we can
      wipe the dominance information.  So rebuild the dominator
@@ -6253,6 +6479,11 @@ identify_jump_threads (void)
      recompute it.  */
   mark_dfs_back_edges ();
 
+  /* Do not thread across edges we are about to remove.  Just marking
+     them as EDGE_DFS_BACK will do.  */
+  for (i = 0; VEC_iterate (edge, to_remove_edges, i, e); ++i)
+    e->flags |= EDGE_DFS_BACK;
+
   /* Allocate our unwinder stack to unwind any temporary equivalences
      that might be recorded.  */
   stack = VEC_alloc (tree, heap, 20);
@@ -6298,7 +6529,6 @@ identify_jump_threads (void)
              && 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
@@ -6403,20 +6633,6 @@ vrp_finalize (void)
   vr_phi_edge_counts = NULL;
 }
 
-/* Calculates number of iterations for all loops, to ensure that they are
-   cached.  */
-
-static void
-record_numbers_of_iterations (void)
-{
-  loop_iterator li;
-  struct loop *loop;
-
-  FOR_EACH_LOOP (li, loop, 0)
-    {
-      number_of_latch_executions (loop);
-    }
-}
 
 /* Main entry point to VRP (Value Range Propagation).  This pass is
    loosely based on J. R. C. Patterson, ``Accurate Static Branch
@@ -6465,22 +6681,18 @@ record_numbers_of_iterations (void)
 static unsigned int
 execute_vrp (void)
 {
+  int i;
+  edge e;
+  switch_update *su;
+
   loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
   rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
   scev_initialize ();
 
   insert_range_assertions ();
 
-  /* Compute the # of iterations for each loop before we start the VRP
-     analysis.  The value ranges determined by VRP are used in expression
-     simplification, that is also used by the # of iterations analysis.
-     However, in the middle of the VRP analysis, the value ranges do not take
-     all the possible paths in CFG into account, so they do not have to be
-     correct, and the # of iterations analysis can obtain wrong results.
-     This is a problem, since the results of the # of iterations analysis
-     are cached, so these mistakes would not be corrected when the value
-     ranges are corrected.  */
-  record_numbers_of_iterations ();
+  to_remove_edges = VEC_alloc (edge, heap, 10);
+  to_update_switch_stmts = VEC_alloc (switch_update, heap, 5);
 
   vrp_initialize ();
   ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
@@ -6499,6 +6711,21 @@ execute_vrp (void)
   update_ssa (TODO_update_ssa);
 
   finalize_jump_threads ();
+
+  /* Remove dead edges from SWITCH_EXPR optimization.  This leaves the
+     CFG in a broken state and requires a cfg_cleanup run.  */
+  for (i = 0; VEC_iterate (edge, to_remove_edges, i, e); ++i)
+    remove_edge (e);
+  /* Update SWITCH_EXPR case label vector.  */
+  for (i = 0; VEC_iterate (switch_update, to_update_switch_stmts, i, su); ++i)
+    SWITCH_LABELS (su->stmt) = su->vec;
+
+  if (VEC_length (edge, to_remove_edges) > 0)
+    free_dominance_info (CDI_DOMINATORS);
+
+  VEC_free (edge, heap, to_remove_edges);
+  VEC_free (switch_update, heap, to_update_switch_stmts);
+
   scev_finalize ();
   loop_optimizer_finalize ();