This concludes the VRP and anti-ranges series for now (well, it was
the motivation for this patch which was pending for quite some time).
This re-implements PLUS_EXPR support on integer ranges to cover
all cases, even those that generate an anti-range as result.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2012-06-20  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/30318
        * tree-vrp.c (range_int_cst_p): Do not reject overflowed
        constants here.
        (range_int_cst_singleton_p): But explicitely here.
        (zero_nonzero_bits_from_vr): And here.
        (extract_range_from_binary_expr_1): Re-implement PLUS_EXPR
        to cover all cases we can perform arbitrary precision
        arithmetic with double-ints.
        (intersect_ranges): Handle adjacent anti-ranges.

        * gcc.dg/tree-ssa/vrp69.c: New testcase.

Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c.orig 2012-06-19 16:58:53.000000000 +0200
--- gcc/tree-vrp.c      2012-06-19 17:16:31.569517561 +0200
*************** range_int_cst_p (value_range_t *vr)
*** 844,852 ****
  {
    return (vr->type == VR_RANGE
          && TREE_CODE (vr->max) == INTEGER_CST
!         && TREE_CODE (vr->min) == INTEGER_CST
!         && !TREE_OVERFLOW (vr->max)
!         && !TREE_OVERFLOW (vr->min));
  }
  
  /* Return true if VR is a INTEGER_CST singleton.  */
--- 844,850 ----
  {
    return (vr->type == VR_RANGE
          && TREE_CODE (vr->max) == INTEGER_CST
!         && TREE_CODE (vr->min) == INTEGER_CST);
  }
  
  /* Return true if VR is a INTEGER_CST singleton.  */
*************** static inline bool
*** 855,860 ****
--- 853,860 ----
  range_int_cst_singleton_p (value_range_t *vr)
  {
    return (range_int_cst_p (vr)
+         && !TREE_OVERFLOW (vr->min)
+         && !TREE_OVERFLOW (vr->max)
          && tree_int_cst_equal (vr->min, vr->max));
  }
  
*************** zero_nonzero_bits_from_vr (value_range_t
*** 1970,1976 ****
  {
    *may_be_nonzero = double_int_minus_one;
    *must_be_nonzero = double_int_zero;
!   if (!range_int_cst_p (vr))
      return false;
  
    if (range_int_cst_singleton_p (vr))
--- 1970,1978 ----
  {
    *may_be_nonzero = double_int_minus_one;
    *must_be_nonzero = double_int_zero;
!   if (!range_int_cst_p (vr)
!       || TREE_OVERFLOW (vr->min)
!       || TREE_OVERFLOW (vr->max))
      return false;
  
    if (range_int_cst_singleton_p (vr))
*************** extract_range_from_binary_expr_1 (value_
*** 2376,2414 ****
       range and see what we end up with.  */
    if (code == PLUS_EXPR)
      {
!       /* If we have a PLUS_EXPR with two VR_ANTI_RANGEs, drop to
!        VR_VARYING.  It would take more effort to compute a precise
!        range for such a case.  For example, if we have op0 == 1 and
!        op1 == -1 with their ranges both being ~[0,0], we would have
!        op0 + op1 == 0, so we cannot claim that the sum is in ~[0,0].
!        Note that we are guaranteed to have vr0.type == vr1.type at
!        this point.  */
!       if (vr0.type == VR_ANTI_RANGE)
        {
          set_value_range_to_varying (vr);
          return;
        }
- 
-       /* For operations that make the resulting range directly
-        proportional to the original ranges, apply the operation to
-        the same end of each range.  */
-       min = vrp_int_const_binop (code, vr0.min, vr1.min);
-       max = vrp_int_const_binop (code, vr0.max, vr1.max);
- 
-       /* If both additions overflowed the range kind is still correct.
-        This happens regularly with subtracting something in unsigned
-        arithmetic.
-          ???  See PR30318 for all the cases we do not handle.  */
-       if ((TREE_OVERFLOW (min) && !is_overflow_infinity (min))
-         && (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
-       {
-         min = build_int_cst_wide (TREE_TYPE (min),
-                                   TREE_INT_CST_LOW (min),
-                                   TREE_INT_CST_HIGH (min));
-         max = build_int_cst_wide (TREE_TYPE (max),
-                                   TREE_INT_CST_LOW (max),
-                                   TREE_INT_CST_HIGH (max));
-       }
      }
    else if (code == MIN_EXPR
           || code == MAX_EXPR)
--- 2378,2538 ----
       range and see what we end up with.  */
    if (code == PLUS_EXPR)
      {
!       /* If we have a PLUS_EXPR with two VR_RANGE integer constant
!          ranges compute the precise range for such case if possible.  */
!       if (range_int_cst_p (&vr0)
!         && range_int_cst_p (&vr1)
!         /* We attempt to do infinite precision signed integer arithmetic,
!            thus we need two more bits than the possibly unsigned inputs.  */
!         && TYPE_PRECISION (expr_type) < HOST_BITS_PER_DOUBLE_INT - 1)
!       {
!         double_int min0 = tree_to_double_int (vr0.min);
!         double_int max0 = tree_to_double_int (vr0.max);
!         double_int min1 = tree_to_double_int (vr1.min);
!         double_int max1 = tree_to_double_int (vr1.max);
!         bool uns = TYPE_UNSIGNED (expr_type);
!         double_int type_min
!           = double_int_min_value (TYPE_PRECISION (expr_type), uns);
!         double_int type_max
!           = double_int_max_value (TYPE_PRECISION (expr_type), uns);
!         double_int dmin, dmax;
! 
!         dmin = double_int_add (min0, min1);
!         dmax = double_int_add (max0, max1);
! 
!         if (TYPE_OVERFLOW_WRAPS (expr_type))
!           {
!             /* If overflow wraps, truncate the values and adjust the
!                range kind and bounds appropriately.  */
!             double_int tmin
!               = double_int_ext (dmin, TYPE_PRECISION (expr_type), uns);
!             double_int tmax
!               = double_int_ext (dmax, TYPE_PRECISION (expr_type), uns);
!             gcc_assert (double_int_scmp (dmin, dmax) <= 0);
!             if ((double_int_scmp (dmin, type_min) == -1
!                  && double_int_scmp (dmax, type_min) == -1)
!                 || (double_int_scmp (dmin, type_max) == 1
!                     && double_int_scmp (dmax, type_max) == 1)
!                 || (double_int_scmp (type_min, dmin) <= 0
!                     && double_int_scmp (dmax, type_max) <= 0))
!               {
!                 /* No overflow or both overflow or underflow.  The
!                    range kind stays VR_RANGE.  */
!                 min = double_int_to_tree (expr_type, tmin);
!                 max = double_int_to_tree (expr_type, tmax);
!               }
!             else if (double_int_scmp (dmin, type_min) == -1
!                      && double_int_scmp (dmax, type_max) == 1)
!               {
!                 /* Underflow and overflow, drop to VR_VARYING.  */
!                 set_value_range_to_varying (vr);
!                 return;
!               }
!             else
!               {
!                 /* Min underflow or max overflow.  The range kind
!                    changes to VR_ANTI_RANGE.  */
!                 double_int tem = tmin;
!                 gcc_assert ((double_int_scmp (dmin, type_min) == -1
!                              && double_int_scmp (dmax, type_min) >= 0
!                              && double_int_scmp (dmax, type_max) <= 0)
!                             || (double_int_scmp (dmax, type_max) == 1
!                                 && double_int_scmp (dmin, type_min) >= 0
!                                 && double_int_scmp (dmin, type_max) <= 0));
!                 type = VR_ANTI_RANGE;
!                 tmin = double_int_add (tmax, double_int_one);
!                 tmax = double_int_add (tem, double_int_minus_one);
!                 /* If the anti-range would cover nothing, drop to varying.
!                    Likewise if the anti-range bounds are outside of the
!                    types values.  */
!                 if (double_int_cmp (tmin, tmax, uns) > 0
!                     || double_int_cmp (tmin, type_min, uns) < 0
!                     || double_int_cmp (tmax, type_max, uns) > 0)
!                   {
!                     set_value_range_to_varying (vr);
!                     return;
!                   }
!                 min = double_int_to_tree (expr_type, tmin);
!                 max = double_int_to_tree (expr_type, tmax);
!               }
!           }
!         else
!           {
!             /* For non-wrapping arithmetic look at possibly smaller
!                value-ranges of the type.  */
!             if (vrp_val_min (expr_type))
!               type_min = tree_to_double_int (vrp_val_min (expr_type));
!             if (vrp_val_max (expr_type))
!               type_max = tree_to_double_int (vrp_val_max (expr_type));
! 
!             /* If overflow does not wrap, saturate to the types min/max
!                value.  */
!             if (double_int_scmp (dmin, type_min) == -1)
!               {
!                 if (needs_overflow_infinity (expr_type)
!                     && supports_overflow_infinity (expr_type))
!                   min = negative_overflow_infinity (expr_type);
!                 else
!                   min = double_int_to_tree (expr_type, type_min);
!               }
!             else if (double_int_scmp (dmin, type_max) == 1)
!               {
!                 if (needs_overflow_infinity (expr_type)
!                     && supports_overflow_infinity (expr_type))
!                   min = positive_overflow_infinity (expr_type);
!                 else
!                   min = double_int_to_tree (expr_type, type_max);
!               }
!             else
!               min = double_int_to_tree (expr_type, dmin);
! 
!             if (double_int_scmp (dmax, type_min) == -1)
!               {
!                 if (needs_overflow_infinity (expr_type)
!                     && supports_overflow_infinity (expr_type))
!                   max = negative_overflow_infinity (expr_type);
!                 else
!                   max = double_int_to_tree (expr_type, type_min);
!               }
!             else if (double_int_scmp (dmax, type_max) == 1)
!               {
!                 if (needs_overflow_infinity (expr_type)
!                     && supports_overflow_infinity (expr_type))
!                   max = positive_overflow_infinity (expr_type);
!                 else
!                   max = double_int_to_tree (expr_type, type_max);
!               }
!             else
!               max = double_int_to_tree (expr_type, dmax);
!           }
!         if (needs_overflow_infinity (expr_type)
!             && supports_overflow_infinity (expr_type))
!           {
!             if (is_negative_overflow_infinity (vr0.min)
!                 || is_negative_overflow_infinity (vr1.min))
!               min = negative_overflow_infinity (expr_type);
!             if (is_positive_overflow_infinity (vr0.max)
!                 || is_positive_overflow_infinity (vr1.max))
!               max = positive_overflow_infinity (expr_type);
!           }
!       }
!       else
        {
+         /* For other cases, for example if we have a PLUS_EXPR with two
+            VR_ANTI_RANGEs, drop to VR_VARYING.  It would take more effort
+            to compute a precise range for such a case.
+            ???  General even mixed range kind operations can be expressed
+            by for example transforming ~[3, 5] + [1, 2] to range-only
+            operations and a union primitive:
+              [-INF, 2] + [1, 2]  U  [5, +INF] + [1, 2]
+                  [-INF+1, 4]     U    [6, +INF(OVF)]
+            though usually the union is not exactly representable with
+            a single range or anti-range as the above is
+                [-INF+1, +INF(OVF)] intersected with ~[5, 5]
+            but one could use a scheme similar to equivalences for this. */
          set_value_range_to_varying (vr);
          return;
        }
      }
    else if (code == MIN_EXPR
           || code == MAX_EXPR)
*************** intersect_ranges (enum value_range_type
*** 7067,7074 ****
        /* [ ] ( ) or ( ) [ ]
         If the ranges have an empty intersection, the result of the
         intersect operation is the range for intersecting an
!        anti-range with a range or empty when intersecting two ranges.
!        For intersecting two anti-ranges simply choose vr0.  */
        if (*vr0type == VR_RANGE
          && vr1type == VR_ANTI_RANGE)
        ;
--- 7191,7197 ----
        /* [ ] ( ) or ( ) [ ]
         If the ranges have an empty intersection, the result of the
         intersect operation is the range for intersecting an
!        anti-range with a range or empty when intersecting two ranges.  */
        if (*vr0type == VR_RANGE
          && vr1type == VR_ANTI_RANGE)
        ;
*************** intersect_ranges (enum value_range_type
*** 7089,7095 ****
        else if (*vr0type == VR_ANTI_RANGE
               && vr1type == VR_ANTI_RANGE)
        {
!         /* Take VR0.  */
        }
      }
    else if ((maxeq || operand_less_p (vr1max, *vr0max) == 1)
--- 7212,7231 ----
        else if (*vr0type == VR_ANTI_RANGE
               && vr1type == VR_ANTI_RANGE)
        {
!         /* If the anti-ranges are adjacent to each other merge them.  */
!         if (TREE_CODE (*vr0max) == INTEGER_CST
!             && TREE_CODE (vr1min) == INTEGER_CST
!             && operand_less_p (*vr0max, vr1min) == 1
!             && integer_onep (int_const_binop (MINUS_EXPR,
!                                               vr1min, *vr0max)))
!           *vr0max = vr1max;
!         else if (TREE_CODE (vr1max) == INTEGER_CST
!                  && TREE_CODE (*vr0min) == INTEGER_CST
!                  && operand_less_p (vr1max, *vr0min) == 1
!                  && integer_onep (int_const_binop (MINUS_EXPR,
!                                                    *vr0min, vr1max)))
!           *vr0min = vr1min;
!         /* Else arbitrarily take VR0.  */
        }
      }
    else if ((maxeq || operand_less_p (vr1max, *vr0max) == 1)
Index: gcc/testsuite/gcc.dg/tree-ssa/vrp69.c
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/vrp69.c       2012-06-19 17:01:54.955547909 
+0200
***************
*** 0 ****
--- 1,38 ----
+ /* { dg-do link } */
+ /* { dg-options "-O2 -fdump-tree-vrp1" } */
+ 
+ #include "vrp.h"
+ 
+ void test1(int i, int j)
+ {
+   RANGE(i, 1, 5);
+   RANGE(j, 7, 10);
+   CHECK_RANGE(i + j, 8, 15);
+ }
+ 
+ #define UINT_MAX 2*(unsigned)__INT_MAX__ + 1
+ void test2(unsigned int i)
+ {
+   RANGE(i, UINT_MAX - 0x4, UINT_MAX - 0x1);
+   CHECK_ANTI_RANGE(i + 0x2, 0x1, UINT_MAX - 0x3);
+ }
+ void test3(unsigned int i)
+ {
+   RANGE(i, UINT_MAX - 0x4, UINT_MAX - 0x1);
+   CHECK_RANGE(i + 0x5, 0x0, 0x3);
+ }
+ void test4(unsigned int i)
+ {
+   RANGE(i, 2, 4);
+   CHECK_ANTI_RANGE(i - 4, 1, UINT_MAX - 2);
+ }
+ void test5(unsigned int i)
+ {
+   RANGE(i, 2, 4);
+   CHECK_RANGE(i - 8, UINT_MAX - 5, UINT_MAX - 3);
+ }
+ 
+ int main() {}
+ 
+ /* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
+ /* { dg-final { cleanup-tree-dump "vrp1" } } */

Reply via email to