public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Simplify VRP vrp_int_const_binop
@ 2017-05-09  8:02 Richard Biener
  0 siblings, 0 replies; only message in thread
From: Richard Biener @ 2017-05-09  8:02 UTC (permalink / raw)
  To: gcc-patches


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  <rguenther@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)
 	    {

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2017-05-09  7:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-09  8:02 [PATCH] Simplify VRP vrp_int_const_binop Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).