The following avoids using trees with TREE_OVERFLOW in vrp_int_const_binop
which is GC memory heavy and simplifies vrp_int_const_binop by
using wide_ints (instead of implementing unsigned overflow detection
manually).

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

Richard.

2017-05-09  Richard Biener  <rguent...@suse.de>

        * tree-vrp.c (vrp_int_const_binop): Use wide-ints and simplify.
        (extract_range_from_multiplicative_op_1): Adjust.
        (extract_range_from_binary_expr_1): Use int_const_binop.

Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c      (revision 247733)
+++ gcc/tree-vrp.c      (working copy)
@@ -1617,66 +1613,91 @@ extract_range_from_ssa_name (value_range
 /* Wrapper around int_const_binop.  If the operation overflows and we
    are not using wrapping arithmetic, then adjust the result to be
    -INF or +INF depending on CODE, VAL1 and VAL2.  This can return
-   NULL_TREE if we need to use an overflow infinity representation but
-   the type does not support it.  */
+   NULL_TREE for division by zero.  */
 
-static tree
-vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
+static wide_int
+vrp_int_const_binop (enum tree_code code, tree val1, tree val2,
+                    bool *overflow_p)
 {
-  tree res;
-
-  res = int_const_binop (code, val1, val2);
+  bool overflow = false;
+  signop sign = TYPE_SIGN (TREE_TYPE (val1));
+  wide_int res;
 
-  /* If we are using unsigned arithmetic, operate symbolically
-     on -INF and +INF as int_const_binop only handles signed overflow.  */
-  if (TYPE_UNSIGNED (TREE_TYPE (val1)))
+  switch (code)
     {
-      int checkz = compare_values (res, val1);
-      bool overflow = false;
+    case RSHIFT_EXPR:
+    case LSHIFT_EXPR:
+      {
+       wide_int wval2 = wi::to_wide (val2, TYPE_PRECISION (TREE_TYPE (val1)));
+       if (wi::neg_p (wval2))
+         {
+           wval2 = -wval2;
+           if (code == RSHIFT_EXPR)
+             code = LSHIFT_EXPR;
+           else
+             code = RSHIFT_EXPR;
+         }
 
-      /* Ensure that res = val1 [+*] val2 >= val1
-         or that res = val1 - val2 <= val1.  */
-      if ((code == PLUS_EXPR
-          && !(checkz == 1 || checkz == 0))
-          || (code == MINUS_EXPR
-             && !(checkz == 0 || checkz == -1)))
+       if (code == RSHIFT_EXPR)
+         /* It's unclear from the C standard whether shifts can overflow.
+            The following code ignores overflow; perhaps a C standard
+            interpretation ruling is needed.  */
+         res = wi::rshift (val1, wval2, sign);
+       else
+         res = wi::lshift (val1, wval2);
+       break;
+      }
+
+    case MULT_EXPR:
+      res = wi::mul (val1, val2, sign, &overflow);
+      break;
+
+    case TRUNC_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      if (val2 == 0)
        {
-         overflow = true;
+         *overflow_p = true;
+         return res;
        }
-      /* Checking for multiplication overflow is done by dividing the
-        output of the multiplication by the first input of the
-        multiplication.  If the result of that division operation is
-        not equal to the second input of the multiplication, then the
-        multiplication overflowed.  */
-      else if (code == MULT_EXPR && !integer_zerop (val1))
+      else
+       res = wi::div_trunc (val1, val2, sign, &overflow);
+      break;
+
+    case FLOOR_DIV_EXPR:
+      if (val2 == 0)
        {
-         tree tmp = int_const_binop (TRUNC_DIV_EXPR,
-                                     res,
-                                     val1);
-         int check = compare_values (tmp, val2);
+         *overflow_p = true;
+         return res;
+       }
+      res = wi::div_floor (val1, val2, sign, &overflow);
+      break;
 
-         if (check != 0)
-           overflow = true;
+    case CEIL_DIV_EXPR:
+      if (val2 == 0)
+       {
+         *overflow_p = true;
+         return res;
        }
+      res = wi::div_ceil (val1, val2, sign, &overflow);
+      break;
 
-      if (overflow)
+    case ROUND_DIV_EXPR:
+      if (val2 == 0)
        {
-         res = copy_node (res);
-         TREE_OVERFLOW (res) = 1;
+         *overflow_p = 0;
+         return res;
        }
+      res = wi::div_round (val1, val2, sign, &overflow);
+      break;
 
+    default:
+      gcc_unreachable ();
     }
-  else if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (val1)))
-    /* If the singed operation wraps then int_const_binop has done
-       everything we want.  */
-    ;
-  /* Signed division of -1/0 overflows and by the time it gets here
-     returns NULL_TREE.  */
-  else if (!res)
-    return NULL_TREE;
-  else if (TREE_OVERFLOW (res)
-          && ! TREE_OVERFLOW (val1)
-          && ! TREE_OVERFLOW (val2))
+
+  *overflow_p = overflow;
+
+  if (overflow
+      && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (val1)))
     {
       /* If the operation overflowed but neither VAL1 nor VAL2 are
         overflown, return -INF or +INF depending on the operation
@@ -1710,17 +1731,18 @@ vrp_int_const_binop (enum tree_code code
             overflow direction is the same as the sign of val1.
             Actually rshift does not overflow at all, but we only
             handle the case of shifting overflowed -INF and +INF.  */
-         || (code == RSHIFT_EXPR
-             && sgn1 >= 0)
+         || (code == RSHIFT_EXPR && sgn1 >= 0)
          /* For division, the only case is -INF / -1 = +INF.  */
          || code == TRUNC_DIV_EXPR
          || code == FLOOR_DIV_EXPR
          || code == CEIL_DIV_EXPR
          || code == EXACT_DIV_EXPR
          || code == ROUND_DIV_EXPR)
-       return TYPE_MAX_VALUE (TREE_TYPE (res));
+       return wi::max_value (TYPE_PRECISION (TREE_TYPE (val1)),
+                             TYPE_SIGN (TREE_TYPE (val1)));
       else
-       return TYPE_MIN_VALUE (TREE_TYPE (res));
+       return wi::min_value (TYPE_PRECISION (TREE_TYPE (val1)),
+                             TYPE_SIGN (TREE_TYPE (val1)));
     }
 
   return res;
@@ -1817,12 +1839,10 @@ extract_range_from_multiplicative_op_1 (
                                        enum tree_code code,
                                        value_range *vr0, value_range *vr1)
 {
-  enum value_range_type type;
-  tree val[4];
-  size_t i;
-  tree min, max;
+  enum value_range_type rtype;
+  wide_int val, min, max;
   bool sop;
-  int cmp;
+  tree type;
 
   /* Multiplications, divisions and shifts are a bit tricky to handle,
      depending on the mix of signs we have in the two ranges, we
@@ -1848,88 +1868,69 @@ extract_range_from_multiplicative_op_1 (
               || (code == MULT_EXPR && vr0->type == VR_ANTI_RANGE))
              && vr0->type == vr1->type);
 
-  type = vr0->type;
+  rtype = vr0->type;
+  type = TREE_TYPE (vr0->min);
+  signop sgn = TYPE_SIGN (type);
 
-  /* Compute the 4 cross operations.  */
+  /* Compute the 4 cross operations and their minimum and maximum value.  */
   sop = false;
-  val[0] = vrp_int_const_binop (code, vr0->min, vr1->min);
-  if (val[0] == NULL_TREE)
-    sop = true;
+  val = vrp_int_const_binop (code, vr0->min, vr1->min, &sop);
+  if (! sop)
+    min = max = val;
 
   if (vr1->max == vr1->min)
-    val[1] = NULL_TREE;
-  else
+    ;
+  else if (! sop)
     {
-      val[1] = vrp_int_const_binop (code, vr0->min, vr1->max);
-      if (val[1] == NULL_TREE)
-       sop = true;
+      val = vrp_int_const_binop (code, vr0->min, vr1->max, &sop);
+      if (! sop)
+       {
+         if (wi::lt_p (val, min, sgn))
+           min = val;
+         else if (wi::gt_p (val, max, sgn))
+           max = val;
+       }
     }
 
   if (vr0->max == vr0->min)
-    val[2] = NULL_TREE;
-  else
+    ;
+  else if (! sop)
     {
-      val[2] = vrp_int_const_binop (code, vr0->max, vr1->min);
-      if (val[2] == NULL_TREE)
-       sop = true;
+      val = vrp_int_const_binop (code, vr0->max, vr1->min, &sop);
+      if (! sop)
+       {
+         if (wi::lt_p (val, min, sgn))
+           min = val;
+         else if (wi::gt_p (val, max, sgn))
+           max = val;
+       }
     }
 
   if (vr0->min == vr0->max || vr1->min == vr1->max)
-    val[3] = NULL_TREE;
-  else
+    ;
+  else if (! sop)
     {
-      val[3] = vrp_int_const_binop (code, vr0->max, vr1->max);
-      if (val[3] == NULL_TREE)
-       sop = true;
+      val = vrp_int_const_binop (code, vr0->max, vr1->max, &sop);
+      if (! sop)
+       {
+         if (wi::lt_p (val, min, sgn))
+           min = val;
+         else if (wi::gt_p (val, max, sgn))
+           max = val;
+       }
     }
 
+  /* If either operation overflowed, drop to VARYING.  */
   if (sop)
     {
       set_value_range_to_varying (vr);
       return;
     }
 
-  /* 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_gimple_min_invariant (max)
-         || TREE_OVERFLOW (max))
-       break;
-
-      if (val[i])
-       {
-         if (!is_gimple_min_invariant (val[i])
-             || TREE_OVERFLOW (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], max) == 1)
-           max = val[i];
-       }
-    }
-
-  /* If either MIN or MAX overflowed, then set the resulting range to
-     VARYING.  But we do accept an overflow infinity
-     representation.  */
-  if (min == NULL_TREE
-      || !is_gimple_min_invariant (min)
-      || TREE_OVERFLOW (min)
-      || max == NULL_TREE
-      || !is_gimple_min_invariant (max)
-      || TREE_OVERFLOW (max))
+  /* If the new range has its limits swapped around (MIN > MAX),
+     then the operation caused one of them to wrap around, mark
+     the new range VARYING.  */
+  if (wi::gt_p (min, max, sgn))
     {
       set_value_range_to_varying (vr);
       return;
@@ -1938,23 +1939,16 @@ extract_range_from_multiplicative_op_1 (
   /* We punt for [-INF, +INF].
      We learn nothing when we have INF on both sides.
      Note that we do accept [-INF, -INF] and [+INF, +INF].  */
-  if (vrp_val_is_min (min)
-      && vrp_val_is_max (max))
+  if (wi::eq_p (min, wi::min_value (TYPE_PRECISION (type), sgn))
+      && wi::eq_p (max, wi::max_value (TYPE_PRECISION (type), sgn)))
     {
       set_value_range_to_varying (vr);
       return;
     }
 
-  cmp = compare_values (min, max);
-  if (cmp == -2 || cmp == 1)
-    {
-      /* If the new range has its limits swapped around (MIN > MAX),
-        then the operation caused one of them to wrap around, mark
-        the new range VARYING.  */
-      set_value_range_to_varying (vr);
-    }
-  else
-    set_value_range (vr, type, min, max, NULL);
+  set_value_range (vr, rtype,
+                  wide_int_to_tree (type, min),
+                  wide_int_to_tree (type, max), NULL);
 }
 
 /* Extract range information from a binary operation CODE based on
@@ -2437,8 +2431,8 @@ extract_range_from_binary_expr_1 (value_
              /* 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);
+             min = int_const_binop (code, vr0.min, vr1.min);
+             max = int_const_binop (code, vr0.max, vr1.max);
            }
          else if (code == MIN_EXPR)
            {

Reply via email to