public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][RFC] Rework int_const_binop, fix PR30318, VRP not creating anti-ranges for overflowing +/-
@ 2007-01-07 19:12 Richard Guenther
  2007-01-08  4:40 ` Ian Lance Taylor
  0 siblings, 1 reply; 2+ messages in thread
From: Richard Guenther @ 2007-01-07 19:12 UTC (permalink / raw)
  To: Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 2827 bytes --]

This addresses PR30318 that is about VRP not creating anti-ranges out
of overflowing PLUS/MINUS_EXPR.  Fixing this PR can possibly make removing
undefined signed overflow assumptions from VRP less harmful.

In order to do so this patch enhances certain parts of VRP to handle
anti-ranges better and canonicalizes certain anti-ranges back to ranges.

In the quest to tackle this PR I have started to re-work int_const_binop to
get rid of the vrp_int_const_binop wrapper in VRP.  What this patch does is
expose the new proposed interface under a different name and not touch
the old one (to keep patch size down).

The new interface get's rid of the nearly unused "notrunc" argument
(and so always force_fits_type), adds a type argument and a second
output, a boolean whether the operation overflowed (regardless of
definedness or undefinedness).  This avoids creating a new node just
to set the overflow flag and also allows tracking overflow for unsigned
types just as vrp_int_const_binop tried to do.  A new force_fit_type_1
was added to allow tracking of unsigned overflow here.

We can implement both old interfaces, int_const_binop and force_fit_type
using the new helpers, but I didn't yet change those to keep the patch small.

Suggestions for a better name for int_const_binop_1 welcome ;)

Note that I will split out the fold-const.c parts into a separate patch
if the general idea is ok - I just included them with the VRP patch to
make the intended use visible.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Note this patch relies on wrapping types wrapping in two's complement
way.  I have no idea how for example Ada types with range [1, 11] is
supposed to "wrap" -- with the patch we assume that adding 5 to a
range [10,10] will result in [15, 15] as it wraps according to TYPE_PRECISION,
not TYPE_MIN/MAX_VALUE.  So this part of the VRP patch needs to
be guarded appropriately - I'm just wondering about the Ada semantics here.

Comments?

Thanks,
Richard.

2007-01-07  Richard Guenther  <rguenther@suse.de>

        PR tree-optimization/30318
        * tree.h (int_const_binop_1): Export.
        * fold-const.c (force_fit_type_1): New static function.
        (int_const_binop_1): New function.
        * tree-vrp.c (set_value_range): Canonicalize anti-ranges
        to ranges where possible.
        (extract_range_from_assert): Merge anti-ranges if possible.
        (vrp_int_const_binop): Remove.
        (extract_range_from_binary_expr): Separate MIN_EXPR and MAX_EXPR
        cases, merge PLUS_EXPR and MINUS_EXPR cases.  Handle cases
        where PLUS_EXPR and MINUS_EXPR create an anti-range.  Replace
        uses of vrp_int_const_binop by int_const_binop_1.
        (compare_range_with_value): Handle anti-range with no valid
        value.

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

[-- Attachment #2: fix-pr30318.diff --]
[-- Type: text/x-patch, Size: 26801 bytes --]

2007-01-07  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/30318
	* tree.h (int_const_binop_1): Export.
	* fold-const.c (force_fit_type_1): New static function.
	(int_const_binop_1): New function.
	* tree-vrp.c (set_value_range): Canonicalize anti-ranges
	to ranges where possible.
	(extract_range_from_assert): Merge anti-ranges if possible.
	(vrp_int_const_binop): Remove.
	(extract_range_from_binary_expr): Separate MIN_EXPR and MAX_EXPR
	cases, merge PLUS_EXPR and MINUS_EXPR cases.  Handle cases
	where PLUS_EXPR and MINUS_EXPR create an anti-range.  Replace
	uses of vrp_int_const_binop by int_const_binop_1.
	(compare_range_with_value): Handle anti-range with no valid
	value.

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

Index: tree.h
===================================================================
*** tree.h	(revision 120546)
--- tree.h	(working copy)
*************** extern tree fold_unary_to_constant (enum
*** 4370,4375 ****
--- 4370,4376 ----
  extern tree fold_binary_to_constant (enum tree_code, tree, tree, tree);
  extern tree fold_read_from_constant_string (tree);
  extern tree int_const_binop (enum tree_code, tree, tree, int);
+ extern tree int_const_binop_1 (enum tree_code, tree, tree, tree, bool*);
  extern tree build_fold_addr_expr (tree);
  extern tree fold_build_cleanup_point_expr (tree type, tree expr);
  extern tree fold_strip_sign_ops (tree);
Index: fold-const.c
===================================================================
*** fold-const.c	(revision 120546)
--- fold-const.c	(working copy)
*************** force_fit_type (tree t, int overflowable
*** 293,298 ****
--- 293,374 ----
  
    return t;
  }
+ 
+ static tree
+ force_fit_type_1 (tree type, unsigned HOST_WIDE_INT low0, HOST_WIDE_INT high0,
+ 		  bool *overflow_p)
+ {
+   unsigned HOST_WIDE_INT low = low0;
+   HOST_WIDE_INT high = high0;
+   unsigned int prec;
+   int sign_extended_type;
+   bool overflow = false;
+ 
+   if (POINTER_TYPE_P (type)
+       || TREE_CODE (type) == OFFSET_TYPE)
+     prec = POINTER_SIZE;
+   else
+     prec = TYPE_PRECISION (type);
+   /* Size types *are* sign extended.  */
+   sign_extended_type = (!TYPE_UNSIGNED (type)
+ 			|| (TREE_CODE (type) == INTEGER_TYPE
+ 			    && TYPE_IS_SIZETYPE (type)));
+ 
+   /* First clear all bits that are beyond the type's precision.  */
+ 
+   if (prec >= 2 * HOST_BITS_PER_WIDE_INT)
+     ;
+   else if (prec > HOST_BITS_PER_WIDE_INT)
+     {
+       overflow = (high & ((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT))) != 0;
+       high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+     }
+   else
+     {
+       overflow = high != 0;
+       high = 0;
+       if (prec < HOST_BITS_PER_WIDE_INT)
+         {
+ 	  overflow |= (low & ((HOST_WIDE_INT) (-1) << prec)) != 0;
+ 	  low &= ~((HOST_WIDE_INT) (-1) << prec);
+ 	}
+     }
+ 
+   if (!sign_extended_type)
+     /* No sign extension */;
+   else if (prec >= 2 * HOST_BITS_PER_WIDE_INT)
+     /* Correct width already.  */;
+   else if (prec > HOST_BITS_PER_WIDE_INT)
+     {
+       /* Sign extend top half? */
+       if (high & ((unsigned HOST_WIDE_INT)1
+ 		  << (prec - HOST_BITS_PER_WIDE_INT - 1)))
+ 	high |= (HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT);
+     }
+   else if (prec == HOST_BITS_PER_WIDE_INT)
+     {
+       if ((HOST_WIDE_INT)low < 0)
+ 	high = -1;
+     }
+   else
+     {
+       /* Sign extend bottom half? */
+       if (low & ((unsigned HOST_WIDE_INT)1 << (prec - 1)))
+ 	{
+ 	  high = -1;
+ 	  low |= (HOST_WIDE_INT)(-1) << prec;
+ 	}
+     }
+ 
+   /* If the value didn't fit, set the overflow flag.  */
+   if (overflow_p
+       && (low != low0 || high != high0)
+       && (overflow || sign_extended_type))
+     *overflow_p |= true;
+ 
+   return build_int_cst_wide (type, low, high);
+ }
+ 
  \f
  /* Add two doubleword integers with doubleword result.
     Return nonzero if the operation overflows according to UNSIGNED_P.
*************** int_binop_types_match_p (enum tree_code 
*** 1419,1424 ****
--- 1495,1654 ----
  }
  
  
+ tree
+ int_const_binop_1 (enum tree_code code, tree type, tree arg1, tree arg2,
+ 		   bool *overflow_p)
+ {
+   unsigned HOST_WIDE_INT int1l, int2l;
+   HOST_WIDE_INT int1h, int2h;
+   unsigned HOST_WIDE_INT low;
+   HOST_WIDE_INT hi;
+   unsigned HOST_WIDE_INT garbagel;
+   HOST_WIDE_INT garbageh;
+   int uns = TYPE_UNSIGNED (type);
+   tree t;
+   int overflow = 0;
+ 
+   int1l = TREE_INT_CST_LOW (arg1);
+   int1h = TREE_INT_CST_HIGH (arg1);
+   int2l = TREE_INT_CST_LOW (arg2);
+   int2h = TREE_INT_CST_HIGH (arg2);
+ 
+   switch (code)
+     {
+     case BIT_IOR_EXPR:
+       low = int1l | int2l, hi = int1h | int2h;
+       break;
+ 
+     case BIT_XOR_EXPR:
+       low = int1l ^ int2l, hi = int1h ^ int2h;
+       break;
+ 
+     case BIT_AND_EXPR:
+       low = int1l & int2l, hi = int1h & int2h;
+       break;
+ 
+     case RSHIFT_EXPR:
+       int2l = -int2l;
+     case LSHIFT_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.  */
+       lshift_double (int1l, int1h, int2l, TYPE_PRECISION (type),
+ 		     &low, &hi, !uns);
+       break;
+ 
+     case RROTATE_EXPR:
+       int2l = - int2l;
+     case LROTATE_EXPR:
+       lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (type),
+ 		      &low, &hi);
+       break;
+ 
+     case PLUS_EXPR:
+       overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi);
+       break;
+ 
+     case MINUS_EXPR:
+       neg_double (int2l, int2h, &low, &hi);
+       add_double (int1l, int1h, low, hi, &low, &hi);
+       overflow = OVERFLOW_SUM_SIGN (hi, int2h, int1h);
+       break;
+ 
+     case MULT_EXPR:
+       overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi);
+       break;
+ 
+     case TRUNC_DIV_EXPR:
+     case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR:
+     case EXACT_DIV_EXPR:
+       /* This is a shortcut for a common special case.  */
+       if (int2h == 0 && (HOST_WIDE_INT) int2l > 0
+ 	  && ! TREE_CONSTANT_OVERFLOW (arg1)
+ 	  && ! TREE_CONSTANT_OVERFLOW (arg2)
+ 	  && int1h == 0 && (HOST_WIDE_INT) int1l >= 0)
+ 	{
+ 	  if (code == CEIL_DIV_EXPR)
+ 	    int1l += int2l - 1;
+ 
+ 	  low = int1l / int2l, hi = 0;
+ 	  break;
+ 	}
+ 
+       /* ... fall through ...  */
+ 
+     case ROUND_DIV_EXPR:
+       if (int2h == 0 && int2l == 0)
+ 	return NULL_TREE;
+       if (int2h == 0 && int2l == 1)
+ 	{
+ 	  low = int1l, hi = int1h;
+ 	  break;
+ 	}
+       if (int1l == int2l && int1h == int2h
+ 	  && ! (int1l == 0 && int1h == 0))
+ 	{
+ 	  low = 1, hi = 0;
+ 	  break;
+ 	}
+       overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
+ 				       &low, &hi, &garbagel, &garbageh);
+       break;
+ 
+     case TRUNC_MOD_EXPR:
+     case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR:
+       /* This is a shortcut for a common special case.  */
+       if (int2h == 0 && (HOST_WIDE_INT) int2l > 0
+ 	  && ! TREE_CONSTANT_OVERFLOW (arg1)
+ 	  && ! TREE_CONSTANT_OVERFLOW (arg2)
+ 	  && int1h == 0 && (HOST_WIDE_INT) int1l >= 0)
+ 	{
+ 	  if (code == CEIL_MOD_EXPR)
+ 	    int1l += int2l - 1;
+ 	  low = int1l % int2l, hi = 0;
+ 	  break;
+ 	}
+ 
+       /* ... fall through ...  */
+ 
+     case ROUND_MOD_EXPR:
+       if (int2h == 0 && int2l == 0)
+ 	return NULL_TREE;
+       overflow = div_and_round_double (code, uns,
+ 				       int1l, int1h, int2l, int2h,
+ 				       &garbagel, &garbageh, &low, &hi);
+       break;
+ 
+     case MIN_EXPR:
+     case MAX_EXPR:
+       if (uns)
+ 	low = (((unsigned HOST_WIDE_INT) int1h
+ 		< (unsigned HOST_WIDE_INT) int2h)
+ 	       || (((unsigned HOST_WIDE_INT) int1h
+ 		    == (unsigned HOST_WIDE_INT) int2h)
+ 		   && int1l < int2l));
+       else
+ 	low = (int1h < int2h
+ 	       || (int1h == int2h && int1l < int2l));
+ 
+       if (low == (code == MIN_EXPR))
+ 	low = int1l, hi = int1h;
+       else
+ 	low = int2l, hi = int2h;
+       break;
+ 
+     default:
+       return NULL_TREE;
+     }
+ 
+   if (overflow_p)
+     *overflow_p = overflow;
+ 
+   t = force_fit_type_1 (type, low, hi, overflow_p);
+ 
+   return t;
+ }
+ 
  /* Combine two integer constants ARG1 and ARG2 under operation CODE
     to produce a new constant.  Return NULL_TREE if we don't know how
     to evaluate CODE at compile-time.
Index: testsuite/gcc.dg/tree-ssa/vrp31.c
===================================================================
*** testsuite/gcc.dg/tree-ssa/vrp31.c	(revision 0)
--- testsuite/gcc.dg/tree-ssa/vrp31.c	(revision 0)
***************
*** 0 ****
--- 1,43 ----
+ /* { dg-do link } */
+ /* { dg-options "-O -ftree-vrp" } */
+ 
+ extern void link_error(void);
+ 
+ #define RANGE(name, min, max) if (name < min) return; if (name > max) return;
+ #define ANTI_RANGE(name, min, max) if (name >= min) if (name <= max) return;
+ #define CHECK_RANGE(expr, min, max) ({ __typeof__ (expr) v = (expr); if (v < min) link_error(); if (v > max) link_error(); })
+ #define CHECK_ANTI_RANGE(expr, min, max) ({ __typeof__ (expr) v = (expr); if (v >= min) if (v <= max) link_error(); })
+ 
+ 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()
+ {
+ }
+ 
Index: tree-vrp.c
===================================================================
*** tree-vrp.c	(revision 120547)
--- tree-vrp.c	(working copy)
*************** set_value_range (value_range_t *vr, enum
*** 168,173 ****
--- 168,198 ----
      gcc_assert (equiv == NULL || bitmap_empty_p (equiv));
  #endif
  
+   /* Canonicalize anti-ranges that start or end at TYPE_MIN_VALUE
+      or TYPE_MAX_VALUE to the appropriate range instead.  This avoids
+      special casing them in compare_range_with_value.
+      Make sure to preserve ~[a, a] and ~[-INF, +INF] though.  */
+   if (t == VR_ANTI_RANGE
+       && !POINTER_TYPE_P (TREE_TYPE (min))
+       && min != max
+       && ((min == TYPE_MIN_VALUE (TREE_TYPE (min)))
+ 	  != (max == TYPE_MAX_VALUE (TREE_TYPE (max)))))
+     {
+       t = VR_RANGE;
+       if (min == TYPE_MIN_VALUE (TREE_TYPE (min)))
+ 	{
+ 	  min = int_const_binop (PLUS_EXPR, max,
+ 				 build_int_cst (TREE_TYPE (max), 1), 0);
+ 	  max = TYPE_MAX_VALUE (TREE_TYPE (max));
+ 	}
+       else
+         {
+ 	  max = int_const_binop (MINUS_EXPR, min,
+ 				 build_int_cst (TREE_TYPE (min), 1), 0);
+ 	  min = TYPE_MIN_VALUE (TREE_TYPE (min));
+ 	}
+     }
+ 
    vr->type = t;
    vr->min = min;
    vr->max = max;
*************** extract_range_from_assert (value_range_t
*** 1053,1058 ****
--- 1078,1121 ----
  	  set_value_range_to_varying (vr_p);
  	}
      }
+   else if (var_vr->type == VR_ANTI_RANGE && vr_p->type == VR_ANTI_RANGE)
+     {
+       tree type = TREE_TYPE (var_vr->max);
+       tree tmp;
+       bool ovfl;
+ 
+       /* If the two anti-ranges touch each other, we can merge them.
+ 	 Since the assert expression creates an equivalency and asserts
+ 	 a predicate, we can take the union of the two ranges to get
+ 	 better precision.  */
+       if (value_ranges_intersect_p (var_vr, vr_p)
+ 	  || (INTEGRAL_TYPE_P (TREE_TYPE (var_vr->max))
+ 	      && (tmp = int_const_binop_1 (PLUS_EXPR, type, var_vr->max,
+ 					   build_int_cst (type, 1), &ovfl))
+ 	      && !ovfl
+ 	      && value_inside_range (tmp, vr_p))
+ 	  || (INTEGRAL_TYPE_P (TREE_TYPE (vr_p->max))
+ 	      && (tmp = int_const_binop_1 (PLUS_EXPR, type, vr_p->max,
+ 					   build_int_cst (type, 1), &ovfl))
+ 	      && !ovfl
+ 	      && value_inside_range (tmp, var_vr)))
+         {
+ 	  /* Use the smaller of the two minimums.  */
+ 	  if (compare_values (vr_p->min, var_vr->min) == -1)
+ 	    min = vr_p->min;
+ 	  else
+ 	    min = var_vr->min;
+ 
+ 	  /* Use the bigger of the two maximums.  */
+ 	  if (compare_values (vr_p->max, var_vr->max) == 1)
+ 	    max = vr_p->max;
+ 	  else
+ 	    max = var_vr->max;
+ 
+ 	  set_value_range (vr_p, vr_p->type, min, max, vr_p->equiv);
+ 	}
+       /* Else we can just use one of both, choose vr_p.  */
+     }
    else if ((var_vr->type == VR_RANGE && vr_p->type == VR_ANTI_RANGE)
             || (var_vr->type == VR_ANTI_RANGE && vr_p->type == VR_RANGE))
      {
*************** extract_range_from_ssa_name (value_range
*** 1186,1289 ****
  }
  
  
- /* 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.  */
- 
- static inline tree
- vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
- {
-   tree res;
- 
-   res = int_const_binop (code, val1, val2, 0);
- 
-   /* If we are not using wrapping arithmetic, operate symbolically
-      on -INF and +INF.  */
-   if (TYPE_UNSIGNED (TREE_TYPE (val1))
-       || flag_wrapv)
-     {
-       int checkz = compare_values (res, val1);
-       bool overflow = false;
- 
-       /* 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)))
- 	{
- 	  overflow = true;
- 	}
-       /* 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))
- 	{
- 	  tree tmp = int_const_binop (TRUNC_DIV_EXPR,
- 				      res,
- 				      val1, 0);
- 	  int check = compare_values (tmp, val2);
- 
- 	  if (check != 0)
- 	    overflow = true;
- 	}
- 
-       if (overflow)
- 	{
- 	  res = copy_node (res);
- 	  TREE_OVERFLOW (res) = 1;
- 	}
- 
-     }
-   else if (TREE_OVERFLOW (res)
- 	   && !TREE_OVERFLOW (val1)
- 	   && !TREE_OVERFLOW (val2))
-     {
-       /* If the operation overflowed but neither VAL1 nor VAL2 are
- 	 overflown, return -INF or +INF depending on the operation
- 	 and the combination of signs of the operands.  */
-       int sgn1 = tree_int_cst_sgn (val1);
-       int sgn2 = tree_int_cst_sgn (val2);
- 
-       /* Notice that we only need to handle the restricted set of
- 	 operations handled by extract_range_from_binary_expr.
- 	 Among them, only multiplication, addition and subtraction
- 	 can yield overflow without overflown operands because we
- 	 are working with integral types only... except in the
- 	 case VAL1 = -INF and VAL2 = -1 which overflows to +INF
- 	 for division too.  */
- 
-       /* For multiplication, the sign of the overflow is given
- 	 by the comparison of the signs of the operands.  */
-       if ((code == MULT_EXPR && sgn1 == sgn2)
-           /* For addition, the operands must be of the same sign
- 	     to yield an overflow.  Its sign is therefore that
- 	     of one of the operands, for example the first.  */
- 	  || (code == PLUS_EXPR && sgn1 > 0)
- 	  /* For subtraction, the operands must be of different
- 	     signs to yield an overflow.  Its sign is therefore
- 	     that of the first operand or the opposite of that
- 	     of the second operand.  A first operand of 0 counts
- 	     as positive here, for the corner case 0 - (-INF),
- 	     which overflows, but must yield +INF.  */
- 	  || (code == MINUS_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));
-       else
- 	return TYPE_MIN_VALUE (TREE_TYPE (res));
-     }
- 
-   return res;
- }
- 
- 
  /* Extract range information from a binary expression EXPR based on
     the ranges of each of its operands and the expression code.  */
  
--- 1249,1254 ----
*************** extract_range_from_binary_expr (value_ra
*** 1324,1330 ****
    op0 = TREE_OPERAND (expr, 0);
    if (TREE_CODE (op0) == SSA_NAME)
      vr0 = *(get_value_range (op0));
!   else if (is_gimple_min_invariant (op0))
      set_value_range (&vr0, VR_RANGE, op0, op0, NULL);
    else
      set_value_range_to_varying (&vr0);
--- 1289,1296 ----
    op0 = TREE_OPERAND (expr, 0);
    if (TREE_CODE (op0) == SSA_NAME)
      vr0 = *(get_value_range (op0));
!   else if (is_gimple_min_invariant (op0)
! 	   && TREE_CODE (op0) != ADDR_EXPR)
      set_value_range (&vr0, VR_RANGE, op0, op0, NULL);
    else
      set_value_range_to_varying (&vr0);
*************** extract_range_from_binary_expr (value_ra
*** 1332,1338 ****
    op1 = TREE_OPERAND (expr, 1);
    if (TREE_CODE (op1) == SSA_NAME)
      vr1 = *(get_value_range (op1));
!   else if (is_gimple_min_invariant (op1))
      set_value_range (&vr1, VR_RANGE, op1, op1, NULL);
    else
      set_value_range_to_varying (&vr1);
--- 1298,1305 ----
    op1 = TREE_OPERAND (expr, 1);
    if (TREE_CODE (op1) == SSA_NAME)
      vr1 = *(get_value_range (op1));
!   else if (is_gimple_min_invariant (op1)
! 	   && TREE_CODE (op1) != ADDR_EXPR)
      set_value_range (&vr1, VR_RANGE, op1, op1, NULL);
    else
      set_value_range_to_varying (&vr1);
*************** extract_range_from_binary_expr (value_ra
*** 1443,1470 ****
  	  return;
  	}
      }
!   else if (code == PLUS_EXPR
! 	   || code == MIN_EXPR
  	   || code == MAX_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 (code == PLUS_EXPR && 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);
      }
    else if (code == MULT_EXPR
  	   || code == TRUNC_DIV_EXPR
--- 1410,1496 ----
  	  return;
  	}
      }
!   else if (code == MIN_EXPR
  	   || code == MAX_EXPR)
      {
!       /* For min and max we can just apply the operation to the same
! 	 end of each range.  */
!       min = int_const_binop (code, vr0.min, vr1.min, 0);
!       max = int_const_binop (code, vr0.max, vr1.max, 0);
!     }
!   else if (code == PLUS_EXPR
! 	   || code == MINUS_EXPR)
!     {
!       bool omin, omax;
! 
!       /* If we have a PLUS_EXPR or MINUS_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 PLUS_EXPR apply the operation to the same end of each range.  */
!       if (code == PLUS_EXPR)
!         {
! 	  min = int_const_binop_1 (code, TREE_TYPE (vr0.min),
! 				   vr0.min, vr1.min, &omin);
! 	  max = int_const_binop_1 (code, TREE_TYPE (vr0.max),
! 				   vr0.max, vr1.max, &omax);
! 	}
! 
!       /* For MINUS_EXPR, apply the operation to the opposite ends of
! 	 each range.  */
!       if (code == MINUS_EXPR)
!         {
! 	  min = int_const_binop_1 (code, TREE_TYPE (vr0.min),
! 				   vr0.min, vr1.max, &omin);
! 	  max = int_const_binop_1 (code, TREE_TYPE (vr0.max),
! 		 		   vr0.max, vr1.min, &omax);
! 	}
! 
!       /* Overflow is handled by creating an anti-range if necessary for
!          wrapping overflow or by saturating to TYPE_MIN_VALUE or
! 	 TYPE_MAX_VALUE if overflow is undefined.  */
!       if (TYPE_UNSIGNED (TREE_TYPE (vr0.min))
! 	  || flag_wrapv)
! 	{
! 	  /* If overflow behavior for both a + c and b + d are the same
! 	     the result is a valid range again.  If only max overflowed,
! 	     create a proper anti-range for the result by swapping
! 	     min and max and adjusting them by one.  */
! 	  if (omin != omax)
! 	    {
! 	      tree one = build_int_cst (TREE_TYPE (max), 1);
! 	      tree tmp = min;
! 	      type = VR_ANTI_RANGE;
! 	      min = int_const_binop_1 (PLUS_EXPR, TREE_TYPE (max),
! 				       max, one, &omin);
! 	      max = int_const_binop_1 (MINUS_EXPR, TREE_TYPE (tmp),
! 				       tmp, one, &omax);
! 	      /* We can wrap again in transforming to an ANTI_RANGE, bail
! 		 out in this case.  */
! 	      if (omin || omax)
! 		{
! 		  set_value_range_to_varying (vr);
! 		  return;
! 		}
! 	    }
! 	}
!       else
!         {
! 	  /* If overflow is undefined treat overflow as -INF/+INF.  */
! 	  if (omin)
! 	    min = TYPE_MIN_VALUE (TREE_TYPE (min));
! 	  if (omax)
! 	    max = TYPE_MAX_VALUE (TREE_TYPE (max));
! 	}
      }
    else if (code == MULT_EXPR
  	   || code == TRUNC_DIV_EXPR
*************** extract_range_from_binary_expr (value_ra
*** 1475,1480 ****
--- 1501,1507 ----
      {
        tree val[4];
        size_t i;
+       bool ovfl;
  
        /* If we have an unsigned MULT_EXPR with two VR_ANTI_RANGEs,
  	 drop to VR_VARYING.  It would take more effort to compute a
*************** extract_range_from_binary_expr (value_ra
*** 1501,1508 ****
  
  	 However, this involves several calls to compare_values and it
  	 is pretty convoluted.  It's simpler to do the 4 operations
! 	 (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
! 	 MAX1) and then figure the smallest and largest values to form
  	 the new range.  */
  
        /* Divisions by zero result in a VARYING value.  */
--- 1528,1535 ----
  
  	 However, this involves several calls to compare_values and it
  	 is pretty convoluted.  It's simpler to do the 4 operations
! 	 (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX1)
! 	 and then figure the smallest and largest values to form
  	 the new range.  */
  
        /* Divisions by zero result in a VARYING value.  */
*************** extract_range_from_binary_expr (value_ra
*** 1514,1554 ****
  	}
  
        /* Compute the 4 cross operations.  */
!       val[0] = vrp_int_const_binop (code, vr0.min, vr1.min);
  
!       val[1] = (vr1.max != vr1.min)
! 	       ? vrp_int_const_binop (code, vr0.min, vr1.max)
  	       : NULL_TREE;
  
!       val[2] = (vr0.max != vr0.min)
! 	       ? vrp_int_const_binop (code, vr0.max, vr1.min)
  	       : NULL_TREE;
  
!       val[3] = (vr0.min != vr0.max && vr1.min != vr1.max)
! 	       ? vrp_int_const_binop (code, vr0.max, vr1.max)
  	       : NULL_TREE;
  
        /* 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];
  
--- 1541,1579 ----
  	}
  
        /* Compute the 4 cross operations.  */
!       val[0] = int_const_binop_1 (code, TREE_TYPE (vr0.min),
! 				  vr0.min, vr1.min, &ovfl);
  
!       val[1] = (vr1.max != vr1.min && !ovfl)
! 	       ? int_const_binop_1 (code, TREE_TYPE (vr0.min),
! 				    vr0.min, vr1.max, &ovfl)
  	       : NULL_TREE;
  
!       val[2] = (vr0.max != vr0.min && !ovfl)
! 	       ? int_const_binop_1 (code, TREE_TYPE (vr0.max),
! 				    vr0.max, vr1.min, &ovfl)
  	       : NULL_TREE;
  
!       val[3] = (vr0.min != vr0.max && vr1.min != vr1.max && !ovfl)
! 	       ? int_const_binop_1 (code, TREE_TYPE (vr0.max),
! 				    vr0.max, vr1.max, &ovfl)
  	       : NULL_TREE;
  
+       /* If any overflow occured drop to varying.  */
+       if (ovfl)
+         {
+ 	  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 (val[i])
  	    {
  	      if (compare_values (val[i], min) == -1)
  		min = val[i];
  
*************** extract_range_from_binary_expr (value_ra
*** 1557,1582 ****
  	    }
  	}
      }
-   else if (code == MINUS_EXPR)
-     {
-       /* If we have a MINUS_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 difference 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 MINUS_EXPR, apply the operation to the opposite ends of
- 	 each range.  */
-       min = vrp_int_const_binop (code, vr0.min, vr1.max);
-       max = vrp_int_const_binop (code, vr0.max, vr1.min);
-     }
    else if (code == BIT_AND_EXPR)
      {
        if (vr0.type == VR_RANGE
--- 1582,1587 ----
*************** compare_range_with_value (enum tree_code
*** 2230,2235 ****
--- 2237,2249 ----
    /* Anti-ranges need to be handled separately.  */
    if (vr->type == VR_ANTI_RANGE)
      {
+       /* Comparing with the special anti-range ~[-INF, +INF] yields
+ 	 arbitrary result.  It can occur on dead parts of the CFG.  */
+       if (!POINTER_TYPE_P (TREE_TYPE (vr->min))
+ 	  && vr->min == TYPE_MIN_VALUE (TREE_TYPE (vr->min))
+ 	  && vr->max == TYPE_MAX_VALUE (TREE_TYPE (vr->max)))
+ 	return boolean_false_node;
+ 
        /* For anti-ranges, the only predicates that we can compute at
  	 compile time are equality and inequality.  */
        if (comp == GT_EXPR

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH][RFC] Rework int_const_binop, fix PR30318, VRP not creating anti-ranges for overflowing +/-
  2007-01-07 19:12 [PATCH][RFC] Rework int_const_binop, fix PR30318, VRP not creating anti-ranges for overflowing +/- Richard Guenther
@ 2007-01-08  4:40 ` Ian Lance Taylor
  0 siblings, 0 replies; 2+ messages in thread
From: Ian Lance Taylor @ 2007-01-08  4:40 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Gcc Patch List

"Richard Guenther" <richard.guenther@gmail.com> writes:

> Comments?

Looks like a good approach to me.

Ian

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-01-08  4:40 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-01-07 19:12 [PATCH][RFC] Rework int_const_binop, fix PR30318, VRP not creating anti-ranges for overflowing +/- Richard Guenther
2007-01-08  4:40 ` Ian Lance Taylor

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).