OSDN Git Service

2010-09-01 Janus Weil <janus@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-vrp.c
index 35d12b3..c005c53 100644 (file)
@@ -3382,6 +3382,38 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop,
   else
     tmax = TYPE_MAX_VALUE (type);
 
+  /* Try to use estimated number of iterations for the loop to constrain the
+     final value in the evolution.
+     We are interested in the number of executions of the latch, while
+     nb_iterations_upper_bound includes the last execution of the exit test.  */
+  if (TREE_CODE (step) == INTEGER_CST
+      && loop->any_upper_bound
+      && !double_int_zero_p (loop->nb_iterations_upper_bound)
+      && is_gimple_val (init)
+      && (TREE_CODE (init) != SSA_NAME
+         || get_value_range (init)->type == VR_RANGE))
+    {
+      value_range_t maxvr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+      double_int dtmp;
+      dtmp = double_int_mul (tree_to_double_int (step),
+                            double_int_sub (loop->nb_iterations_upper_bound,
+                                            double_int_one));
+      tem = double_int_to_tree (TREE_TYPE (init), dtmp);
+      /* If the multiplication overflowed we can't do a meaningful
+        adjustment.  */
+      if (double_int_equal_p (dtmp, tree_to_double_int (tem)))
+       {
+         extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
+                                         TREE_TYPE (init), init, tem);
+         /* Likewise if the addition did.  */
+         if (maxvr.type == VR_RANGE)
+           {
+             tmin = maxvr.min;
+             tmax = maxvr.max;
+           }
+       }
+    }
+
   if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
     {
       min = tmin;
@@ -3414,40 +3446,35 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop,
          /* INIT is the maximum value.  If INIT is lower than VR->MAX
             but no smaller than VR->MIN, set VR->MAX to INIT.  */
          if (compare_values (init, max) == -1)
-           {
-             max = init;
-
-             /* If we just created an invalid range with the minimum
-                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)
-               return;
-           }
+           max = init;
 
          /* According to the loop information, the variable does not
             overflow.  If we think it does, probably because of an
             overflow due to arithmetic on a different INF value,
             reset now.  */
-         if (is_negative_overflow_infinity (min))
+         if (is_negative_overflow_infinity (min)
+             || compare_values (min, tmin) == -1)
            min = tmin;
+
        }
       else
        {
          /* If INIT is bigger than VR->MIN, set VR->MIN to INIT.  */
          if (compare_values (init, min) == 1)
-           {
-             min = init;
-
-             /* Again, avoid creating invalid range by failing.  */
-             if (compare_values (min, max) == 1)
-               return;
-           }
+           min = init;
 
-         if (is_positive_overflow_infinity (max))
+         if (is_positive_overflow_infinity (max)
+             || compare_values (tmax, max) == -1)
            max = tmax;
        }
 
+      /* If we just created an invalid range with the minimum
+        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)
+       return;
+
       set_value_range (vr, VR_RANGE, min, max, vr->equiv);
     }
 }
@@ -6509,8 +6536,6 @@ vrp_visit_phi_node (gimple phi)
   int edges, old_edges;
   struct loop *l;
 
-  copy_value_range (&vr_result, lhs_vr);
-
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "\nVisiting PHI node: ");
@@ -6571,13 +6596,6 @@ vrp_visit_phi_node (gimple phi)
        }
     }
 
-  /* If this is a loop PHI node SCEV may known more about its
-     value-range.  */
-  if (current_loops
-      && (l = loop_containing_stmt (phi))
-      && l->header == gimple_bb (phi))
-    adjust_range_with_scev (&vr_result, l, phi, lhs);
-
   if (vr_result.type == VR_VARYING)
     goto varying;
 
@@ -6589,61 +6607,63 @@ vrp_visit_phi_node (gimple phi)
      previous one.  We don't do this if we have seen a new executable
      edge; this helps us avoid an overflow infinity for conditionals
      which are not in a loop.  */
-  if (lhs_vr->type == VR_RANGE && vr_result.type == VR_RANGE
-      && edges <= old_edges)
-    {
-      if (!POINTER_TYPE_P (TREE_TYPE (lhs)))
-       {
-         int cmp_min = compare_values (lhs_vr->min, vr_result.min);
-         int cmp_max = compare_values (lhs_vr->max, vr_result.max);
-
-         /* If the new minimum is smaller or larger than the previous
-            one, go all the way to -INF.  In the first case, to avoid
-            iterating millions of times to reach -INF, and in the
-            other case to avoid infinite bouncing between different
-            minimums.  */
-         if (cmp_min > 0 || cmp_min < 0)
-           {
-             /* 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))
-                 || !vrp_var_may_overflow (lhs, phi))
-               vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min));
-             else if (supports_overflow_infinity (TREE_TYPE (vr_result.min)))
-               vr_result.min =
-                 negative_overflow_infinity (TREE_TYPE (vr_result.min));
-             else
-               goto varying;
-           }
-
-         /* Similarly, if the new maximum is smaller or larger than
-            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.  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))
-                 || !vrp_var_may_overflow (lhs, phi))
-               vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max));
-             else if (supports_overflow_infinity (TREE_TYPE (vr_result.max)))
-               vr_result.max =
-                 positive_overflow_infinity (TREE_TYPE (vr_result.max));
-             else
-               goto varying;
-           }
-       }
+  if (edges > 0
+      && edges == old_edges)
+    {
+      int cmp_min = compare_values (lhs_vr->min, vr_result.min);
+      int cmp_max = compare_values (lhs_vr->max, vr_result.max);
+
+      /* For non VR_RANGE or for pointers fall back to varying if
+        the range changed.  */
+      if ((lhs_vr->type != VR_RANGE || vr_result.type != VR_RANGE
+          || POINTER_TYPE_P (TREE_TYPE (lhs)))
+         && (cmp_min != 0 || cmp_max != 0))
+       goto varying;
+
+      /* If the new minimum is smaller or larger than the previous
+        one, go all the way to -INF.  In the first case, to avoid
+        iterating millions of times to reach -INF, and in the
+        other case to avoid infinite bouncing between different
+        minimums.  */
+      if (cmp_min > 0 || cmp_min < 0)
+       {
+         if (!needs_overflow_infinity (TREE_TYPE (vr_result.min))
+             || !vrp_var_may_overflow (lhs, phi))
+           vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min));
+         else if (supports_overflow_infinity (TREE_TYPE (vr_result.min)))
+           vr_result.min =
+               negative_overflow_infinity (TREE_TYPE (vr_result.min));
+       }
+
+      /* Similarly, if the new maximum is smaller or larger than
+        the previous one, go all the way to +INF.  */
+      if (cmp_max < 0 || cmp_max > 0)
+       {
+         if (!needs_overflow_infinity (TREE_TYPE (vr_result.max))
+             || !vrp_var_may_overflow (lhs, phi))
+           vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max));
+         else if (supports_overflow_infinity (TREE_TYPE (vr_result.max)))
+           vr_result.max =
+               positive_overflow_infinity (TREE_TYPE (vr_result.max));
+       }
+
+      /* If we dropped either bound to +-INF then if this is a loop
+        PHI node SCEV may known more about its value-range.  */
+      if ((cmp_min > 0 || cmp_min < 0
+          || cmp_max < 0 || cmp_max > 0)
+         && current_loops
+         && (l = loop_containing_stmt (phi))
+         && l->header == gimple_bb (phi))
+       adjust_range_with_scev (&vr_result, l, phi, lhs);
+
+      /* 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 end up with vr_result.min > vr_result.max.  */
+      if ((vrp_val_is_max (vr_result.max)
+          && vrp_val_is_min (vr_result.min))
+         || compare_values (vr_result.min,
+                            vr_result.max) > 0)
+       goto varying;
     }
 
   /* If the new range is different than the previous value, keep
@@ -7470,7 +7490,7 @@ identify_jump_threads (void)
 
   /* 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)
+  FOR_EACH_VEC_ELT (edge, to_remove_edges, i, e)
     e->flags |= EDGE_DFS_BACK;
 
   /* Allocate our unwinder stack to unwind any temporary equivalences
@@ -7650,6 +7670,12 @@ execute_vrp (void)
   rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
   scev_initialize ();
 
+  /* Estimate number of iterations - but do not use undefined behavior
+     for this.  We can't do this lazily as other functions may compute
+     this using undefined behavior.  */
+  free_numbers_of_iterations_estimates ();
+  estimate_numbers_of_iterations (false);
+
   insert_range_assertions ();
 
   to_remove_edges = VEC_alloc (edge, heap, 10);
@@ -7676,10 +7702,10 @@ execute_vrp (void)
 
   /* 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)
+  FOR_EACH_VEC_ELT (edge, to_remove_edges, i, e)
     remove_edge (e);
   /* Update SWITCH_EXPR case label vector.  */
-  for (i = 0; VEC_iterate (switch_update, to_update_switch_stmts, i, su); ++i)
+  FOR_EACH_VEC_ELT (switch_update, to_update_switch_stmts, i, su)
     {
       size_t j;
       size_t n = TREE_VEC_LENGTH (su->vec);