OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-vrp.c
index 56fc5a2..3f5ec66 100644 (file)
@@ -695,17 +695,22 @@ get_value_range (const_tree var)
   /* If VAR is a default definition of a parameter, the variable can
      take any value in VAR's type.  */
   sym = SSA_NAME_VAR (var);
-  if (SSA_NAME_IS_DEFAULT_DEF (var)
-      && TREE_CODE (sym) == PARM_DECL)
-    {
-      /* Try to use the "nonnull" attribute to create ~[0, 0]
-        anti-ranges for pointers.  Note that this is only valid with
-        default definitions of PARM_DECLs.  */
-      if (POINTER_TYPE_P (TREE_TYPE (sym))
-         && nonnull_arg_p (sym))
+  if (SSA_NAME_IS_DEFAULT_DEF (var))
+    {
+      if (TREE_CODE (sym) == PARM_DECL)
+       {
+         /* Try to use the "nonnull" attribute to create ~[0, 0]
+            anti-ranges for pointers.  Note that this is only valid with
+            default definitions of PARM_DECLs.  */
+         if (POINTER_TYPE_P (TREE_TYPE (sym))
+             && nonnull_arg_p (sym))
+           set_value_range_to_nonnull (vr, TREE_TYPE (sym));
+         else
+           set_value_range_to_varying (vr);
+       }
+      else if (TREE_CODE (sym) == RESULT_DECL
+              && DECL_BY_REFERENCE (sym))
        set_value_range_to_nonnull (vr, TREE_TYPE (sym));
-      else
-       set_value_range_to_varying (vr);
     }
 
   return vr;
@@ -1519,7 +1524,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
 
   limit = avoid_overflow_infinity (limit);
 
-  type = TREE_TYPE (limit);
+  type = TREE_TYPE (var);
   gcc_assert (limit != var);
 
   /* For pointer arithmetic, we only keep track of pointer equality
@@ -1693,8 +1698,13 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
          /* For LT_EXPR, we create the range [MIN, MAX - 1].  */
          if (cond_code == LT_EXPR)
            {
-             tree one = build_int_cst (type, 1);
-             max = fold_build2 (MINUS_EXPR, type, max, one);
+             if (TYPE_PRECISION (TREE_TYPE (max)) == 1
+                 && !TYPE_UNSIGNED (TREE_TYPE (max)))
+               max = fold_build2 (PLUS_EXPR, TREE_TYPE (max), max,
+                                  build_int_cst (TREE_TYPE (max), -1));
+             else
+               max = fold_build2 (MINUS_EXPR, TREE_TYPE (max), max,
+                                  build_int_cst (TREE_TYPE (max), 1));
              if (EXPR_P (max))
                TREE_NO_WARNING (max) = 1;
            }
@@ -1728,8 +1738,13 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
          /* For GT_EXPR, we create the range [MIN + 1, MAX].  */
          if (cond_code == GT_EXPR)
            {
-             tree one = build_int_cst (type, 1);
-             min = fold_build2 (PLUS_EXPR, type, min, one);
+             if (TYPE_PRECISION (TREE_TYPE (min)) == 1
+                 && !TYPE_UNSIGNED (TREE_TYPE (min)))
+               min = fold_build2 (MINUS_EXPR, TREE_TYPE (min), min,
+                                  build_int_cst (TREE_TYPE (min), -1));
+             else
+               min = fold_build2 (PLUS_EXPR, TREE_TYPE (min), min,
+                                  build_int_cst (TREE_TYPE (min), 1));
              if (EXPR_P (min))
                TREE_NO_WARNING (min) = 1;
            }
@@ -1915,9 +1930,19 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
                  min = positive_overflow_infinity (TREE_TYPE (var_vr->min));
                }
              else if (!POINTER_TYPE_P (TREE_TYPE (var_vr->min)))
-               min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
-                                  anti_max,
-                                  build_int_cst (TREE_TYPE (var_vr->min), 1));
+               {
+                 if (TYPE_PRECISION (TREE_TYPE (var_vr->min)) == 1
+                     && !TYPE_UNSIGNED (TREE_TYPE (var_vr->min)))
+                   min = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+                                      anti_max,
+                                      build_int_cst (TREE_TYPE (var_vr->min),
+                                                     -1));
+                 else
+                   min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+                                      anti_max,
+                                      build_int_cst (TREE_TYPE (var_vr->min),
+                                                     1));
+               }
              else
                min = fold_build_pointer_plus_hwi (anti_max, 1);
              max = real_max;
@@ -1942,9 +1967,19 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
                  max = negative_overflow_infinity (TREE_TYPE (var_vr->min));
                }
              else if (!POINTER_TYPE_P (TREE_TYPE (var_vr->min)))
-               max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
-                                  anti_min,
-                                  build_int_cst (TREE_TYPE (var_vr->min), 1));
+               {
+                 if (TYPE_PRECISION (TREE_TYPE (var_vr->min)) == 1
+                     && !TYPE_UNSIGNED (TREE_TYPE (var_vr->min)))
+                   max = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+                                      anti_min,
+                                      build_int_cst (TREE_TYPE (var_vr->min),
+                                                     -1));
+                 else
+                   max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+                                      anti_min,
+                                      build_int_cst (TREE_TYPE (var_vr->min),
+                                                     1));
+               }
              else
                max = fold_build_pointer_plus_hwi (anti_min, -1);
              min = real_min;
@@ -2549,17 +2584,13 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
         behavior from the shift operation.  We cannot even trust
         SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl
         shifts, and the operation at the tree level may be widened.  */
-      if (code == RSHIFT_EXPR)
+      if (vr1.type != VR_RANGE
+         || !value_range_nonnegative_p (&vr1)
+         || TREE_CODE (vr1.max) != INTEGER_CST
+         || compare_tree_int (vr1.max, TYPE_PRECISION (expr_type) - 1) == 1)
        {
-         if (vr1.type != VR_RANGE
-             || !value_range_nonnegative_p (&vr1)
-             || TREE_CODE (vr1.max) != INTEGER_CST
-             || compare_tree_int (vr1.max,
-                                  TYPE_PRECISION (expr_type) - 1) == 1)
-           {
-             set_value_range_to_varying (vr);
-             return;
-           }
+         set_value_range_to_varying (vr);
+         return;
        }
 
       extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
@@ -2913,15 +2944,10 @@ extract_range_from_unary_expr_1 (value_range_t *vr,
         determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]).  */
       if (POINTER_TYPE_P (type))
        {
-         if (CONVERT_EXPR_CODE_P (code))
-           {
-             if (range_is_nonnull (&vr0))
-               set_value_range_to_nonnull (vr, type);
-             else if (range_is_null (&vr0))
-               set_value_range_to_null (vr, type);
-             else
-               set_value_range_to_varying (vr);
-           }
+         if (range_is_nonnull (&vr0))
+           set_value_range_to_nonnull (vr, type);
+         else if (range_is_null (&vr0))
+           set_value_range_to_null (vr, type);
          else
            set_value_range_to_varying (vr);
          return;
@@ -2965,16 +2991,18 @@ extract_range_from_unary_expr_1 (value_range_t *vr,
                         size_int (TYPE_PRECISION (outer_type)))))))
        {
          tree new_min, new_max;
-         new_min = force_fit_type_double (outer_type,
-                                          tree_to_double_int (vr0.min),
-                                          0, false);
-         new_max = force_fit_type_double (outer_type,
-                                          tree_to_double_int (vr0.max),
-                                          0, false);
          if (is_overflow_infinity (vr0.min))
            new_min = negative_overflow_infinity (outer_type);
+         else
+           new_min = force_fit_type_double (outer_type,
+                                            tree_to_double_int (vr0.min),
+                                            0, false);
          if (is_overflow_infinity (vr0.max))
            new_max = positive_overflow_infinity (outer_type);
+         else
+           new_max = force_fit_type_double (outer_type,
+                                            tree_to_double_int (vr0.max),
+                                            0, false);
          set_and_canonicalize_value_range (vr, vr0.type,
                                            new_min, new_max, NULL);
          return;
@@ -3219,8 +3247,8 @@ extract_range_from_cond_expr (value_range_t *vr, gimple stmt)
     set_value_range_to_varying (&vr1);
 
   /* The resulting value range is the union of the operand ranges */
-  vrp_meet (&vr0, &vr1);
   copy_value_range (vr, &vr0);
+  vrp_meet (vr, &vr1);
 }
 
 
@@ -6419,13 +6447,17 @@ vrp_meet (value_range_t *vr0, value_range_t *vr1)
 {
   if (vr0->type == VR_UNDEFINED)
     {
-      copy_value_range (vr0, vr1);
+      /* Drop equivalences.  See PR53465.  */
+      set_value_range (vr0, vr1->type, vr1->min, vr1->max, NULL);
       return;
     }
 
   if (vr1->type == VR_UNDEFINED)
     {
-      /* Nothing to do.  VR0 already has the resulting range.  */
+      /* VR0 already has the resulting range, just drop equivalences.
+        See PR53465.  */
+      if (vr0->equiv)
+       bitmap_clear (vr0->equiv);
       return;
     }
 
@@ -6567,6 +6599,7 @@ vrp_visit_phi_node (gimple phi)
   tree lhs = PHI_RESULT (phi);
   value_range_t *lhs_vr = get_value_range (lhs);
   value_range_t vr_result = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+  bool first = true;
   int edges, old_edges;
   struct loop *l;
 
@@ -6623,7 +6656,11 @@ vrp_visit_phi_node (gimple phi)
              fprintf (dump_file, "\n");
            }
 
-         vrp_meet (&vr_result, &vr_arg);
+         if (first)
+           copy_value_range (&vr_result, &vr_arg);
+         else
+           vrp_meet (&vr_result, &vr_arg);
+         first = false;
 
          if (vr_result.type == VR_VARYING)
            break;
@@ -7259,7 +7296,9 @@ simplify_conversion_using_ranges (gimple stmt)
   tree innerop, middleop, finaltype;
   gimple def_stmt;
   value_range_t *innervr;
-  double_int innermin, innermax, middlemin, middlemax;
+  bool inner_unsigned_p, middle_unsigned_p, final_unsigned_p;
+  unsigned inner_prec, middle_prec, final_prec;
+  double_int innermin, innermed, innermax, middlemin, middlemed, middlemax;
 
   finaltype = TREE_TYPE (gimple_assign_lhs (stmt));
   if (!INTEGRAL_TYPE_P (finaltype))
@@ -7284,26 +7323,49 @@ simplify_conversion_using_ranges (gimple stmt)
      the middle conversion is removed.  */
   innermin = tree_to_double_int (innervr->min);
   innermax = tree_to_double_int (innervr->max);
-  middlemin = double_int_ext (innermin, TYPE_PRECISION (TREE_TYPE (middleop)),
-                             TYPE_UNSIGNED (TREE_TYPE (middleop)));
-  middlemax = double_int_ext (innermax, TYPE_PRECISION (TREE_TYPE (middleop)),
-                             TYPE_UNSIGNED (TREE_TYPE (middleop)));
-  /* If the middle values do not represent a proper range fail.  */
-  if (double_int_cmp (middlemin, middlemax,
-                     TYPE_UNSIGNED (TREE_TYPE (middleop))) > 0)
+
+  inner_prec = TYPE_PRECISION (TREE_TYPE (innerop));
+  middle_prec = TYPE_PRECISION (TREE_TYPE (middleop));
+  final_prec = TYPE_PRECISION (finaltype);
+
+  /* If the first conversion is not injective, the second must not
+     be widening.  */
+  if (double_int_cmp (double_int_sub (innermax, innermin),
+                     double_int_mask (middle_prec), true) > 0
+      && middle_prec < final_prec)
     return false;
+  /* We also want a medium value so that we can track the effect that
+     narrowing conversions with sign change have.  */
+  inner_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (innerop));
+  if (inner_unsigned_p)
+    innermed = double_int_rshift (double_int_mask (inner_prec),
+                                 1, inner_prec, false);
+  else
+    innermed = double_int_zero;
+  if (double_int_cmp (innermin, innermed, inner_unsigned_p) >= 0
+      || double_int_cmp (innermed, innermax, inner_unsigned_p) >= 0)
+    innermed = innermin;
+
+  middle_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (middleop));
+  middlemin = double_int_ext (innermin, middle_prec, middle_unsigned_p);
+  middlemed = double_int_ext (innermed, middle_prec, middle_unsigned_p);
+  middlemax = double_int_ext (innermax, middle_prec, middle_unsigned_p);
+
+  /* Require that the final conversion applied to both the original
+     and the intermediate range produces the same result.  */
+  final_unsigned_p = TYPE_UNSIGNED (finaltype);
   if (!double_int_equal_p (double_int_ext (middlemin,
-                                          TYPE_PRECISION (finaltype),
-                                          TYPE_UNSIGNED (finaltype)),
+                                          final_prec, final_unsigned_p),
                           double_int_ext (innermin,
-                                          TYPE_PRECISION (finaltype),
-                                          TYPE_UNSIGNED (finaltype)))
+                                          final_prec, final_unsigned_p))
+      || !double_int_equal_p (double_int_ext (middlemed,
+                                             final_prec, final_unsigned_p),
+                             double_int_ext (innermed,
+                                             final_prec, final_unsigned_p))
       || !double_int_equal_p (double_int_ext (middlemax,
-                                             TYPE_PRECISION (finaltype),
-                                             TYPE_UNSIGNED (finaltype)),
+                                             final_prec, final_unsigned_p),
                              double_int_ext (innermax,
-                                             TYPE_PRECISION (finaltype),
-                                             TYPE_UNSIGNED (finaltype))))
+                                             final_prec, final_unsigned_p)))
     return false;
 
   gimple_assign_set_rhs1 (stmt, innerop);