This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR26998, bad logic in VRP for NEGATE_EXPR


This fixes PR26998 by ensuring that we do not use fold_unary_to_constant
with a NEGATE_EXPR if we know that will overflow.  The current check for
this case is bogus, as the only value that will overflow in this case
is the signed TYPE_MIN_VALUE, there is no reason to handle TYPE_MAX_VALUE
specially.

In the particular PR, we were confronted with an anti-range of 
TYPE_MIN_VALUE of a signed type, so, in extracting new range information
from NEGATE_EXPR of that range, we concluded that it is

 ~[NEGATE_EXPR (TYPE_MIN_VALUE), TYPE_MAX_VALUE]

where the first expr fails to fold to a constant because it introduces
overflow.  Apart from this, -~[TYPE_MIN_VALUE, TYPE_MIN_VALUE] for signed
types is not ~[TYPE_MIN_VALUE, TYPE_MAX_VALUE], but ~[TYPE_MIN_VALUE, 
TYPE_MIN_VALUE] again, independend of if we have flag_wrapv in effect or 
not.  A testcase that could fail would be

extern void abort(void);
void decCompareOp (int result)
{
  if (result != (int)0x80000000)
    {
      result = -result;
      if (result != (int)0x80000001)
        abort ();
    }
}
int main()
{
  decCompareOp (0x7fffffff);
  return 0;
}

but it does not, because we do not extract a range for the NEGATE_EXRP
probably because atm we get a TREE_OVERFLOW flag on min.  With the patch
we now have

Visiting statement:
result_3 = ASSERT_EXPR <result_1, result_1 != -2147483648>;

Found new range for result_3: ~[-INF, -2147483648]

Visiting statement:
result_2 = -result_3;

Found new range for result_2: ~[-INF, -2147483648]

which is correct.

The patch ensures correct operation by treating TYPE_MIN_VALUE specially
to avoid fold either not folding the negation or setting overflow flags
on the result.  It also handles the problematic cases (initial minimum
value TYPE_MIN_VALUE) explicitly to get useful information from the
-[MIN, x] case if overflow is undefined.  Other cases are caught later
when we check for overflow by comparing the new min and max values and
eventually set the range to varying.

Bootstrapped and regtested on x86_64-unknown-linux-gnu with all languages
including Ada.

Ok for mainline?

Thanks,
Richard.

2006-06-08  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/26998
	* tree-vrp.c (extract_range_from_unary_expr): For NEGATE_EXPR
	of signed types, only TYPE_MIN_VALUE is special, but for both,
	minimum and maximum value.  Likewise VR_ANTI_RANGE is special
	in this case, as is -fwrapv.

	* gcc.dg/torture/pr26998.c: New testcase.
	* gcc.dg/tree-ssa/vrp29.c: New testcase.

Index: tree-vrp.c
===================================================================
*** tree-vrp.c	(revision 114482)
--- tree-vrp.c	(working copy)
*************** extract_range_from_unary_expr (value_ran
*** 1795,1808 ****
    if (code == NEGATE_EXPR
        && !TYPE_UNSIGNED (TREE_TYPE (expr)))
      {
!       /* NEGATE_EXPR flips the range around.  */
!       min = (vr0.max == TYPE_MAX_VALUE (TREE_TYPE (expr)) && !flag_wrapv)
! 	     ? TYPE_MIN_VALUE (TREE_TYPE (expr))
! 	     : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
! 
!       max = (vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr)) && !flag_wrapv)
! 	     ? TYPE_MAX_VALUE (TREE_TYPE (expr))
! 	     : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
  
      }
    else if (code == NEGATE_EXPR
--- 1795,1815 ----
    if (code == NEGATE_EXPR
        && !TYPE_UNSIGNED (TREE_TYPE (expr)))
      {
!       /* NEGATE_EXPR flips the range around.  We need to treat
! 	 TYPE_MIN_VALUE specially dependent on wrapping, range type
! 	 and if it was used as minimum or maximum value:  
! 	  -~[MIN, MIN] == ~[MIN, MIN]
! 	  -[MIN, 0] == [0, MAX]  for -fno-wrapv
! 	  -[MIN, 0] == [0, MIN]  for -fwrapv (will be set to varying later)  */
!       min = vr0.max == TYPE_MIN_VALUE (TREE_TYPE (expr))
! 	    ? TYPE_MIN_VALUE (TREE_TYPE (expr))
! 	    : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
! 
!       max = vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr))
! 	    ? (vr0.type == VR_ANTI_RANGE || flag_wrapv
! 	       ? TYPE_MIN_VALUE (TREE_TYPE (expr))
! 	       : TYPE_MAX_VALUE (TREE_TYPE (expr)))
! 	    : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
  
      }
    else if (code == NEGATE_EXPR
Index: testsuite/gcc.dg/torture/pr26998.c
===================================================================
*** testsuite/gcc.dg/torture/pr26998.c	(revision 0)
--- testsuite/gcc.dg/torture/pr26998.c	(revision 0)
***************
*** 0 ****
--- 1,11 ----
+ /* { dg-do compile } */
+ 
+ int decCompareOp (int result)
+ {
+     if (result != (int)0x80000000)
+     {
+         result = -result;
+         return (result > 0);
+     }
+     return 0;
+ }

Index: testsuite/gcc.dg/tree-ssa/vrp29.c
===================================================================
*** testsuite/gcc.dg/tree-ssa/vrp29.c	(revision 0)
--- testsuite/gcc.dg/tree-ssa/vrp29.c	(revision 0)
***************
*** 0 ****
--- 1,20 ----
+ /* { dg-do run } */
+ /* { dg-options "-O2" } */
+ 
+ extern void abort(void);
+ 
+ void decCompareOp (int result)
+ {
+   if (result != (int)0x80000000)
+     {
+       result = -result;
+       if (result != (int)0x80000001)
+         abort ();
+     }
+ }
+ 
+ int main()
+ {
+   decCompareOp (0x7fffffff);
+   return 0;
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]