Abstract a lot of the {PLUS,MINUS}_EXPR code in
authorAldy Hernandez <aldyh@redhat.com>
Mon, 2 Jul 2018 12:18:00 +0000 (12:18 +0000)
committerAldy Hernandez <aldyh@gcc.gnu.org>
Mon, 2 Jul 2018 12:18:00 +0000 (12:18 +0000)
extract_range_from_binary_expr_1 into separate functions.

From-SVN: r262306

gcc/ChangeLog
gcc/tree-vrp.c

index b4874ca72db8f7b9af68ef35dd445e74d808b3d7..15f2749d49242716fcddb80aed4de1542cda2bee 100644 (file)
@@ -1,3 +1,11 @@
+2018-07-02  Aldy Hernandez  <aldyh@redhat.com>
+
+       * tree-vrp.c (extract_range_from_binary_expr_1): Abstract a lot of the
+       {PLUS,MINUS}_EXPR code to...
+       (adjust_symbolic_bound): ...here,
+       (combine_bound): ...here,
+       (set_value_range_with_overflow): ...and here.
+
 2018-07-02  Aldy Hernandez  <aldyh@redhat.com>
 
        * tree-vrp.c (extract_range_from_unary_expr): Abstract ABS_EXPR
index 42436b38eba2f314997b2807e6c1e493d51659f6..c966334acbcfe213dc1eb86007cdb44fcb31a255 100644 (file)
@@ -1275,6 +1275,196 @@ extract_range_from_multiplicative_op_1 (value_range *vr,
                   wide_int_to_tree (type, max), NULL);
 }
 
+/* If BOUND will include a symbolic bound, adjust it accordingly,
+   otherwise leave it as is.
+
+   CODE is the original operation that combined the bounds (PLUS_EXPR
+   or MINUS_EXPR).
+
+   TYPE is the type of the original operation.
+
+   SYM_OPn is the symbolic for OPn if it has a symbolic.
+
+   NEG_OPn is TRUE if the OPn was negated.  */
+
+static void
+adjust_symbolic_bound (tree &bound, enum tree_code code, tree type,
+                      tree sym_op0, tree sym_op1,
+                      bool neg_op0, bool neg_op1)
+{
+  bool minus_p = (code == MINUS_EXPR);
+  /* If the result bound is constant, we're done; otherwise, build the
+     symbolic lower bound.  */
+  if (sym_op0 == sym_op1)
+    ;
+  else if (sym_op0)
+    bound = build_symbolic_expr (type, sym_op0,
+                                neg_op0, bound);
+  else if (sym_op1)
+    {
+      /* We may not negate if that might introduce
+        undefined overflow.  */
+      if (!minus_p
+         || neg_op1
+         || TYPE_OVERFLOW_WRAPS (type))
+       bound = build_symbolic_expr (type, sym_op1,
+                                    neg_op1 ^ minus_p, bound);
+      else
+       bound = NULL_TREE;
+    }
+}
+
+/* Combine OP1 and OP1, which are two parts of a bound, into one wide
+   int bound according to CODE.  CODE is the operation combining the
+   bound (either a PLUS_EXPR or a MINUS_EXPR).
+
+   TYPE is the type of the combine operation.
+
+   WI is the wide int to store the result.
+
+   OVF is -1 if an underflow occurred, +1 if an overflow occurred or 0
+   if over/underflow occurred.  */
+
+static void
+combine_bound (enum tree_code code, wide_int &wi, int &ovf,
+              tree type, tree op0, tree op1)
+{
+  bool minus_p = (code == MINUS_EXPR);
+  const signop sgn = TYPE_SIGN (type);
+  const unsigned int prec = TYPE_PRECISION (type);
+
+  /* Combine the bounds, if any.  */
+  if (op0 && op1)
+    {
+      if (minus_p)
+       {
+         wi = wi::to_wide (op0) - wi::to_wide (op1);
+
+         /* Check for overflow.  */
+         if (wi::cmp (0, wi::to_wide (op1), sgn)
+             != wi::cmp (wi, wi::to_wide (op0), sgn))
+           ovf = wi::cmp (wi::to_wide (op0),
+                          wi::to_wide (op1), sgn);
+       }
+      else
+       {
+         wi = wi::to_wide (op0) + wi::to_wide (op1);
+
+         /* Check for overflow.  */
+         if (wi::cmp (wi::to_wide (op1), 0, sgn)
+             != wi::cmp (wi, wi::to_wide (op0), sgn))
+           ovf = wi::cmp (wi::to_wide (op0), wi, sgn);
+       }
+    }
+  else if (op0)
+    wi = wi::to_wide (op0);
+  else if (op1)
+    {
+      if (minus_p)
+       {
+         wi = -wi::to_wide (op1);
+
+         /* Check for overflow.  */
+         if (sgn == SIGNED
+             && wi::neg_p (wi::to_wide (op1))
+             && wi::neg_p (wi))
+           ovf = 1;
+         else if (sgn == UNSIGNED && wi::to_wide (op1) != 0)
+           ovf = -1;
+       }
+      else
+       wi = wi::to_wide (op1);
+    }
+  else
+    wi = wi::shwi (0, prec);
+}
+
+/* Given a range in [WMIN, WMAX], adjust it for possible overflow and
+   put the result in VR.
+
+   TYPE is the type of the range.
+
+   MIN_OVF and MAX_OVF indicate what type of overflow, if any,
+   occurred while originally calculating WMIN or WMAX.  -1 indicates
+   underflow.  +1 indicates overflow.  0 indicates neither.  */
+
+static void
+set_value_range_with_overflow (value_range &vr,
+                              tree type,
+                              const wide_int &wmin, const wide_int &wmax,
+                              int min_ovf, int max_ovf)
+{
+  const signop sgn = TYPE_SIGN (type);
+  const unsigned int prec = TYPE_PRECISION (type);
+  vr.type = VR_RANGE;
+  vr.equiv = NULL;
+  if (TYPE_OVERFLOW_WRAPS (type))
+    {
+      /* If overflow wraps, truncate the values and adjust the
+        range kind and bounds appropriately.  */
+      wide_int tmin = wide_int::from (wmin, prec, sgn);
+      wide_int tmax = wide_int::from (wmax, prec, sgn);
+      if (min_ovf == max_ovf)
+       {
+         /* No overflow or both overflow or underflow.  The
+            range kind stays VR_RANGE.  */
+         vr.min = wide_int_to_tree (type, tmin);
+         vr.max = wide_int_to_tree (type, tmax);
+       }
+      else if ((min_ovf == -1 && max_ovf == 0)
+              || (max_ovf == 1 && min_ovf == 0))
+       {
+         /* Min underflow or max overflow.  The range kind
+            changes to VR_ANTI_RANGE.  */
+         bool covers = false;
+         wide_int tem = tmin;
+         vr.type = VR_ANTI_RANGE;
+         tmin = tmax + 1;
+         if (wi::cmp (tmin, tmax, sgn) < 0)
+           covers = true;
+         tmax = tem - 1;
+         if (wi::cmp (tmax, tem, sgn) > 0)
+           covers = true;
+         /* If the anti-range would cover nothing, drop to varying.
+            Likewise if the anti-range bounds are outside of the
+            types values.  */
+         if (covers || wi::cmp (tmin, tmax, sgn) > 0)
+           {
+             set_value_range_to_varying (&vr);
+             return;
+           }
+         vr.min = wide_int_to_tree (type, tmin);
+         vr.max = wide_int_to_tree (type, tmax);
+       }
+      else
+       {
+         /* Other underflow and/or overflow, drop to VR_VARYING.  */
+         set_value_range_to_varying (&vr);
+         return;
+       }
+    }
+  else
+    {
+      /* If overflow does not wrap, saturate to the types min/max
+        value.  */
+      wide_int type_min = wi::min_value (prec, sgn);
+      wide_int type_max = wi::max_value (prec, sgn);
+      if (min_ovf == -1)
+       vr.min = wide_int_to_tree (type, type_min);
+      else if (min_ovf == 1)
+       vr.min = wide_int_to_tree (type, type_max);
+      else
+       vr.min = wide_int_to_tree (type, wmin);
+
+      if (max_ovf == -1)
+       vr.max = wide_int_to_tree (type, type_min);
+      else if (max_ovf == 1)
+       vr.max = wide_int_to_tree (type, type_max);
+      else
+       vr.max = wide_int_to_tree (type, wmax);
+    }
+}
+
 /* Extract range information from a binary operation CODE based on
    the ranges of each of its operands *VR0 and *VR1 with resulting
    type EXPR_TYPE.  The resulting range is stored in *VR.  */
@@ -1495,128 +1685,13 @@ extract_range_from_binary_expr_1 (value_range *vr,
              || (sym_max_op0 == sym_max_op1
                  && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1))))
        {
-         const signop sgn = TYPE_SIGN (expr_type);
-         const unsigned int prec = TYPE_PRECISION (expr_type);
-         wide_int type_min, type_max, wmin, wmax;
+         wide_int wmin, wmax;
          int min_ovf = 0;
          int max_ovf = 0;
 
-         /* Get the lower and upper bounds of the type.  */
-         if (TYPE_OVERFLOW_WRAPS (expr_type))
-           {
-             type_min = wi::min_value (prec, sgn);
-             type_max = wi::max_value (prec, sgn);
-           }
-         else
-           {
-             type_min = wi::to_wide (vrp_val_min (expr_type));
-             type_max = wi::to_wide (vrp_val_max (expr_type));
-           }
-
-         /* Combine the lower bounds, if any.  */
-         if (min_op0 && min_op1)
-           {
-             if (minus_p)
-               {
-                 wmin = wi::to_wide (min_op0) - wi::to_wide (min_op1);
-
-                 /* Check for overflow.  */
-                 if (wi::cmp (0, wi::to_wide (min_op1), sgn)
-                     != wi::cmp (wmin, wi::to_wide (min_op0), sgn))
-                   min_ovf = wi::cmp (wi::to_wide (min_op0),
-                                      wi::to_wide (min_op1), sgn);
-               }
-             else
-               {
-                 wmin = wi::to_wide (min_op0) + wi::to_wide (min_op1);
-
-                 /* Check for overflow.  */
-                 if (wi::cmp (wi::to_wide (min_op1), 0, sgn)
-                     != wi::cmp (wmin, wi::to_wide (min_op0), sgn))
-                   min_ovf = wi::cmp (wi::to_wide (min_op0), wmin, sgn);
-               }
-           }
-         else if (min_op0)
-           wmin = wi::to_wide (min_op0);
-         else if (min_op1)
-           {
-             if (minus_p)
-               {
-                 wmin = -wi::to_wide (min_op1);
-
-                 /* Check for overflow.  */
-                 if (sgn == SIGNED
-                     && wi::neg_p (wi::to_wide (min_op1))
-                     && wi::neg_p (wmin))
-                   min_ovf = 1;
-                 else if (sgn == UNSIGNED && wi::to_wide (min_op1) != 0)
-                   min_ovf = -1;
-               }
-             else
-               wmin = wi::to_wide (min_op1);
-           }
-         else
-           wmin = wi::shwi (0, prec);
-
-         /* Combine the upper bounds, if any.  */
-         if (max_op0 && max_op1)
-           {
-             if (minus_p)
-               {
-                 wmax = wi::to_wide (max_op0) - wi::to_wide (max_op1);
-
-                 /* Check for overflow.  */
-                 if (wi::cmp (0, wi::to_wide (max_op1), sgn)
-                     != wi::cmp (wmax, wi::to_wide (max_op0), sgn))
-                   max_ovf = wi::cmp (wi::to_wide (max_op0),
-                                      wi::to_wide (max_op1), sgn);
-               }
-             else
-               {
-                 wmax = wi::to_wide (max_op0) + wi::to_wide (max_op1);
-
-                 if (wi::cmp (wi::to_wide (max_op1), 0, sgn)
-                     != wi::cmp (wmax, wi::to_wide (max_op0), sgn))
-                   max_ovf = wi::cmp (wi::to_wide (max_op0), wmax, sgn);
-               }
-           }
-         else if (max_op0)
-           wmax = wi::to_wide (max_op0);
-         else if (max_op1)
-           {
-             if (minus_p)
-               {
-                 wmax = -wi::to_wide (max_op1);
-
-                 /* Check for overflow.  */
-                 if (sgn == SIGNED
-                     && wi::neg_p (wi::to_wide (max_op1))
-                     && wi::neg_p (wmax))
-                   max_ovf = 1;
-                 else if (sgn == UNSIGNED && wi::to_wide (max_op1) != 0)
-                   max_ovf = -1;
-               }
-             else
-               wmax = wi::to_wide (max_op1);
-           }
-         else
-           wmax = wi::shwi (0, prec);
-
-         /* Check for type overflow.  */
-         if (min_ovf == 0)
-           {
-             if (wi::cmp (wmin, type_min, sgn) == -1)
-               min_ovf = -1;
-             else if (wi::cmp (wmin, type_max, sgn) == 1)
-               min_ovf = 1;
-           }
-         if (max_ovf == 0)
-           {
-             if (wi::cmp (wmax, type_min, sgn) == -1)
-               max_ovf = -1;
-             else if (wi::cmp (wmax, type_max, sgn) == 1)
-               max_ovf = 1;
-           }
+         /* Build the bounds.  */
+         combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1);
+         combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1);
 
          /* If we have overflow for the constant part and the resulting
             range will be symbolic, drop to VR_VARYING.  */
@@ -1627,108 +1702,24 @@ extract_range_from_binary_expr_1 (value_range *vr,
              return;
            }
 
-         if (TYPE_OVERFLOW_WRAPS (expr_type))
-           {
-             /* If overflow wraps, truncate the values and adjust the
-                range kind and bounds appropriately.  */
-             wide_int tmin = wide_int::from (wmin, prec, sgn);
-             wide_int tmax = wide_int::from (wmax, prec, sgn);
-             if (min_ovf == max_ovf)
-               {
-                 /* No overflow or both overflow or underflow.  The
-                    range kind stays VR_RANGE.  */
-                 min = wide_int_to_tree (expr_type, tmin);
-                 max = wide_int_to_tree (expr_type, tmax);
-               }
-             else if ((min_ovf == -1 && max_ovf == 0)
-                      || (max_ovf == 1 && min_ovf == 0))
-               {
-                 /* Min underflow or max overflow.  The range kind
-                    changes to VR_ANTI_RANGE.  */
-                 bool covers = false;
-                 wide_int tem = tmin;
-                 type = VR_ANTI_RANGE;
-                 tmin = tmax + 1;
-                 if (wi::cmp (tmin, tmax, sgn) < 0)
-                   covers = true;
-                 tmax = tem - 1;
-                 if (wi::cmp (tmax, tem, sgn) > 0)
-                   covers = true;
-                 /* If the anti-range would cover nothing, drop to varying.
-                    Likewise if the anti-range bounds are outside of the
-                    types values.  */
-                 if (covers || wi::cmp (tmin, tmax, sgn) > 0)
-                   {
-                     set_value_range_to_varying (vr);
-                     return;
-                   }
-                 min = wide_int_to_tree (expr_type, tmin);
-                 max = wide_int_to_tree (expr_type, tmax);
-               }
-             else
-               {
-                 /* Other underflow and/or overflow, drop to VR_VARYING.  */
-                 set_value_range_to_varying (vr);
-                 return;
-               }
-           }
-         else
-           {
-             /* If overflow does not wrap, saturate to the types min/max
-                value.  */
-             if (min_ovf == -1)
-               min = wide_int_to_tree (expr_type, type_min);
-             else if (min_ovf == 1)
-               min = wide_int_to_tree (expr_type, type_max);
-             else
-               min = wide_int_to_tree (expr_type, wmin);
-
-             if (max_ovf == -1)
-               max = wide_int_to_tree (expr_type, type_min);
-             else if (max_ovf == 1)
-               max = wide_int_to_tree (expr_type, type_max);
-             else
-               max = wide_int_to_tree (expr_type, wmax);
-           }
-
-         /* If the result lower bound is constant, we're done;
-            otherwise, build the symbolic lower bound.  */
-         if (sym_min_op0 == sym_min_op1)
-           ;
-         else if (sym_min_op0)
-           min = build_symbolic_expr (expr_type, sym_min_op0,
-                                      neg_min_op0, min);
-         else if (sym_min_op1)
-           {
-             /* We may not negate if that might introduce
-                undefined overflow.  */
-             if (! minus_p
-                 || neg_min_op1
-                 || TYPE_OVERFLOW_WRAPS (expr_type))
-               min = build_symbolic_expr (expr_type, sym_min_op1,
-                                          neg_min_op1 ^ minus_p, min);
-             else
-               min = NULL_TREE;
-           }
-
-         /* Likewise for the upper bound.  */
-         if (sym_max_op0 == sym_max_op1)
-           ;
-         else if (sym_max_op0)
-           max = build_symbolic_expr (expr_type, sym_max_op0,
-                                      neg_max_op0, max);
-         else if (sym_max_op1)
-           {
-             /* We may not negate if that might introduce
-                undefined overflow.  */
-             if (! minus_p
-                 || neg_max_op1
-                 || TYPE_OVERFLOW_WRAPS (expr_type))
-               max = build_symbolic_expr (expr_type, sym_max_op1,
-                                          neg_max_op1 ^ minus_p, max);
-             else
-               max = NULL_TREE;
-           }
+         /* Adjust the range for possible overflow.  */
+         set_value_range_with_overflow (*vr, expr_type,
+                                        wmin, wmax, min_ovf, max_ovf);
+         if (vr->type == VR_VARYING)
+           return;
+
+         /* Build the symbolic bounds if needed.  */
+         adjust_symbolic_bound (vr->min, code, expr_type,
+                                sym_min_op0, sym_min_op1,
+                                neg_min_op0, neg_min_op1);
+         adjust_symbolic_bound (vr->max, code, expr_type,
+                                sym_max_op0, sym_max_op1,
+                                neg_max_op0, neg_max_op1);
+         /* ?? It would probably be cleaner to eliminate min/max/type
+            entirely and hold these values in VR directly.  */
+         min = vr->min;
+         max = vr->max;
+         type = vr->type;
        }
       else
        {