wide-int-range.cc (wide_int_range_abs): New.
authorAldy Hernandez <aldyh@redhat.com>
Tue, 21 Aug 2018 06:27:14 +0000 (06:27 +0000)
committerAldy Hernandez <aldyh@gcc.gnu.org>
Tue, 21 Aug 2018 06:27:14 +0000 (06:27 +0000)
* wide-int-range.cc (wide_int_range_abs): New.
(wide_int_range_order_set): Rename from wide_int_range_min_max.
* wide-int-range.h (wide_int_range_abs): New.
(wide_int_range_min_max): New.
* tree-vrp.c (extract_range_from_unary_expr): Rewrite ABS_EXPR
case to call wide_int_range_abs.
Rewrite MIN/MAX_EXPR to call wide_int_range_min_max.
(extract_range_from_abs_expr): Delete.

From-SVN: r263685

gcc/ChangeLog
gcc/tree-vrp.c
gcc/wide-int-range.cc
gcc/wide-int-range.h

index cb9f5528e4b6db85722b2626611150ac3977ed9f..ad722fde33c5e0de96501ee6ac55b4b19dab3e9f 100644 (file)
@@ -1,3 +1,14 @@
+2018-08-21  Aldy Hernandez  <aldyh@redhat.com>
+
+       * wide-int-range.cc (wide_int_range_abs): New.
+       (wide_int_range_order_set): Rename from wide_int_range_min_max.
+       * wide-int-range.h (wide_int_range_abs): New.
+       (wide_int_range_min_max): New.
+       * tree-vrp.c (extract_range_from_unary_expr): Rewrite ABS_EXPR
+       case to call wide_int_range_abs.
+       Rewrite MIN/MAX_EXPR to call wide_int_range_min_max.
+       (extract_range_from_abs_expr): Delete.
+
 2018-08-20  Michael Meissner  <meissner@linux.ibm.com>
 
        PR target/87033
index 2ddb0c2c197e9ade56ed67ac266d84d33171ee35..24e089b019b715b049d218d648e481f093aafcdf 100644 (file)
@@ -1594,50 +1594,19 @@ extract_range_from_binary_expr_1 (value_range *vr,
   else if (code == MIN_EXPR
           || code == MAX_EXPR)
     {
-      if (vr0.type == VR_RANGE
-         && !symbolic_range_p (&vr0))
-       {
-         type = VR_RANGE;
-         if (vr1.type == VR_RANGE
-             && !symbolic_range_p (&vr1))
-           {
-             /* For operations that make the resulting range directly
-                proportional to the original ranges, apply the operation to
-                the same end of each range.  */
-             min = int_const_binop (code, vr0.min, vr1.min);
-             max = int_const_binop (code, vr0.max, vr1.max);
-           }
-         else if (code == MIN_EXPR)
-           {
-             min = vrp_val_min (expr_type);
-             max = vr0.max;
-           }
-         else if (code == MAX_EXPR)
-           {
-             min = vr0.min;
-             max = vrp_val_max (expr_type);
-           }
-       }
-      else if (vr1.type == VR_RANGE
-              && !symbolic_range_p (&vr1))
-       {
-         type = VR_RANGE;
-         if (code == MIN_EXPR)
-           {
-             min = vrp_val_min (expr_type);
-             max = vr1.max;
-           }
-         else if (code == MAX_EXPR)
-           {
-             min = vr1.min;
-             max = vrp_val_max (expr_type);
-           }
-       }
+      wide_int wmin, wmax;
+      wide_int vr0_min, vr0_max;
+      wide_int vr1_min, vr1_max;
+      extract_range_into_wide_ints (&vr0, sign, prec, &vr0_min, &vr0_max);
+      extract_range_into_wide_ints (&vr1, sign, prec, &vr1_min, &vr1_max);
+      if (wide_int_range_min_max (wmin, wmax, code, sign, prec,
+                                 vr0_min, vr0_max, vr1_min, vr1_max))
+       set_value_range (vr, VR_RANGE,
+                        wide_int_to_tree (expr_type, wmin),
+                        wide_int_to_tree (expr_type, wmax), NULL);
       else
-       {
-         set_value_range_to_varying (vr);
-         return;
-       }
+       set_value_range_to_varying (vr);
+      return;
     }
   else if (code == MULT_EXPR)
     {
@@ -1924,85 +1893,6 @@ extract_range_from_binary_expr_1 (value_range *vr,
     set_value_range (vr, type, min, max, NULL);
 }
 
-/* Calculates the absolute value of a range and puts the result in VR.
-   VR0 is the input range.  TYPE is the type of the resulting
-   range.  */
-
-static void
-extract_range_from_abs_expr (value_range &vr, tree type, value_range &vr0)
-{
-  /* Pass through vr0 in the easy cases.  */
-  if (TYPE_UNSIGNED (type)
-      || value_range_nonnegative_p (&vr0))
-    {
-      copy_value_range (&vr, &vr0);
-      return;
-    }
-
-  /* For the remaining varying or symbolic ranges we can't do anything
-     useful.  */
-  if (vr0.type == VR_VARYING
-      || symbolic_range_p (&vr0))
-    {
-      set_value_range_to_varying (&vr);
-      return;
-    }
-
-  /* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a
-     useful range.  */
-  if (!TYPE_OVERFLOW_UNDEFINED (type)
-      && ((vr0.type == VR_RANGE
-          && vrp_val_is_min (vr0.min))
-         || (vr0.type == VR_ANTI_RANGE
-             && !vrp_val_is_min (vr0.min))))
-    {
-      set_value_range_to_varying (&vr);
-      return;
-    }
-
-  /* ABS_EXPR may flip the range around, if the original range
-     included negative values.  */
-  tree min, max;
-  if (!vrp_val_is_min (vr0.min))
-    min = fold_unary_to_constant (ABS_EXPR, type, vr0.min);
-  else
-    min = TYPE_MAX_VALUE (type);
-
-  if (!vrp_val_is_min (vr0.max))
-    max = fold_unary_to_constant (ABS_EXPR, type, vr0.max);
-  else
-    max = TYPE_MAX_VALUE (type);
-
-  int cmp = compare_values (min, max);
-  gcc_assert (vr0.type != VR_ANTI_RANGE);
-
-  /* If the range contains zero then we know that the minimum value in the
-     range will be zero.  */
-  if (range_includes_zero_p (vr0.min, vr0.max) == 1)
-    {
-      if (cmp == 1)
-       max = min;
-      min = build_int_cst (type, 0);
-    }
-  else
-    {
-      /* If the range was reversed, swap MIN and MAX.  */
-      if (cmp == 1)
-       std::swap (min, max);
-    }
-
-  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, vr0.type, min, max, NULL);
-}
-
 /* Extract range information from a unary operation CODE based on
    the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE.
    The resulting range is stored in *VR.  */
@@ -2012,6 +1902,8 @@ extract_range_from_unary_expr (value_range *vr,
                               enum tree_code code, tree type,
                               value_range *vr0_, tree op0_type)
 {
+  signop sign = TYPE_SIGN (type);
+  unsigned int prec = TYPE_PRECISION (type);
   value_range vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
 
   /* VRP only operates on integral and pointer types.  */
@@ -2133,7 +2025,24 @@ extract_range_from_unary_expr (value_range *vr,
       return;
     }
   else if (code == ABS_EXPR)
-    return extract_range_from_abs_expr (*vr, type, vr0);
+    {
+      if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
+       {
+         set_value_range_to_varying (vr);
+         return;
+       }
+      wide_int wmin, wmax;
+      wide_int vr0_min, vr0_max;
+      extract_range_into_wide_ints (&vr0, sign, prec, &vr0_min, &vr0_max);
+      if (wide_int_range_abs (wmin, wmax, sign, prec, vr0_min, vr0_max,
+                             TYPE_OVERFLOW_UNDEFINED (type)))
+       set_value_range (vr, VR_RANGE,
+                        wide_int_to_tree (type, wmin),
+                        wide_int_to_tree (type, wmax), NULL);
+      else
+       set_value_range_to_varying (vr);
+      return;
+    }
 
   /* For unhandled operations fall back to varying.  */
   set_value_range_to_varying (vr);
index 726ec63b3a657ba27e4b2986e9aecf1451ba8efe..a202b5fd503660590e20d4171802ae8158d36d84 100644 (file)
@@ -119,9 +119,10 @@ wide_int_range_set_zero_nonzero_bits (signop sign,
    accordingly.  */
 
 static void
-wide_int_range_min_max (wide_int &min, wide_int &max,
-                       wide_int &w0, wide_int &w1, wide_int &w2, wide_int &w3,
-                       signop sign)
+wide_int_range_order_set (wide_int &min, wide_int &max,
+                         wide_int &w0, wide_int &w1,
+                         wide_int &w2, wide_int &w3,
+                         signop sign)
 {
   /* Order pairs w0,w1 and w2,w3.  */
   if (wi::gt_p (w0, w1, sign))
@@ -177,7 +178,7 @@ wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub,
                                     overflow_undefined))
     return false;
 
-  wide_int_range_min_max (res_lb, res_ub, cp1, cp2, cp3, cp4, sign);
+  wide_int_range_order_set (res_lb, res_ub, cp1, cp2, cp3, cp4, sign);
   return true;
 }
 
@@ -605,3 +606,60 @@ wide_int_range_trunc_mod (wide_int &wmin, wide_int &wmax,
     tmp = wi::zero (prec);
   wmax = wi::min (wmax, tmp, sign);
 }
+
+/* Calculate ABS_EXPR on a range and store the result in [MIN, MAX].  */
+
+bool
+wide_int_range_abs (wide_int &min, wide_int &max,
+                   signop sign, unsigned prec,
+                   const wide_int &vr0_min, const wide_int &vr0_max,
+                   bool overflow_undefined)
+{
+  /* Pass through VR0 the easy cases.  */
+  if (sign == UNSIGNED || wi::ge_p (vr0_min, 0, sign))
+    {
+      min = vr0_min;
+      max = vr0_max;
+      return true;
+    }
+
+  /* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a
+     useful range.  */
+  wide_int min_value = wi::min_value (prec, sign);
+  wide_int max_value = wi::max_value (prec, sign);
+  if (!overflow_undefined && wi::eq_p (vr0_min, min_value))
+    return false;
+
+  /* ABS_EXPR may flip the range around, if the original range
+     included negative values.  */
+  if (wi::eq_p (vr0_min, min_value))
+    min = max_value;
+  else
+    min = wi::abs (vr0_min);
+  if (wi::eq_p (vr0_max, min_value))
+    max = max_value;
+  else
+    max = wi::abs (vr0_max);
+
+  /* If the range contains zero then we know that the minimum value in the
+     range will be zero.  */
+  if (wi::le_p (vr0_min, 0, sign) && wi::ge_p (vr0_max, 0, sign))
+    {
+      if (wi::gt_p (min, max, sign))
+       max = min;
+      min = wi::zero (prec);
+    }
+  else
+    {
+      /* If the range was reversed, swap MIN and MAX.  */
+      if (wi::gt_p (min, max, sign))
+       std::swap (min, 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, sign))
+      return false;
+  return true;
+}
index 4421bc8aecad90a1718b4e94ff67153ec1b390f9..41198e05b1352a96e5f9e66638c717d2b69305c4 100644 (file)
@@ -94,6 +94,11 @@ extern void wide_int_range_trunc_mod (wide_int &wmin, wide_int &wmax,
                                      const wide_int &vr0_max,
                                      const wide_int &vr1_min,
                                      const wide_int &vr1_max);
+extern bool wide_int_range_abs (wide_int &min, wide_int &max,
+                               signop sign, unsigned prec,
+                               const wide_int &vr0_min,
+                               const wide_int &vr0_max,
+                               bool overflow_undefined);
 
 /* Return TRUE if shifting by range [MIN, MAX] is undefined behavior.  */
 
@@ -112,4 +117,24 @@ wide_int_range_shift_undefined_p (signop sign, unsigned prec,
   return wi::lt_p (min, 0, sign) || wi::ge_p (max, prec, sign);
 }
 
+/* Calculate MIN/MAX_EXPR of two ranges and store the result in [MIN, MAX].  */
+
+inline bool
+wide_int_range_min_max (wide_int &min, wide_int &max,
+                       tree_code code,
+                       signop sign, unsigned prec,
+                       const wide_int &vr0_min, const wide_int &vr0_max,
+                       const wide_int &vr1_min, const wide_int &vr1_max)
+{
+  wi::overflow_type overflow;
+  wide_int_binop (min, code, vr0_min, vr1_min, sign, &overflow);
+  wide_int_binop (max, code, vr0_max, vr1_max, sign, &overflow);
+  /* If the new range covers the entire domain, that's really no range
+     at all.  */
+  if (min == wi::min_value (prec, sign)
+      && max == wi::max_value (prec, sign))
+    return false;
+  return true;
+}
+
 #endif /* GCC_WIDE_INT_RANGE_H */