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 PR28651, wrong-code for (int)(unsigned - 4) < (int)(unsigned)


This fixes PR28651 which is present on all branches and latent on the
mainline.  simplify_const_relational_operation tries to be clever with
respect to undefinedness of signed overflow, but fails to notice that
we have no idea if an operation on either side of the comparison is
carried out in signed or unsigned arithmetic.  The fact that the
comparison itself is signed or unsigned doesn't help here.

The fix is to restrict the transformation to the EQ and NE case where
it is valid.  On the mainline this bug is masked by the 
missed-optimization PR26847.

Bootstrapped and tested on x86_64-unknown-linux for all languages 
including ada on the 4.1 branch.

Ok for the mainline and the release branches?

Thanks,
Richard.

:ADDPATCH middle-end:

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

	PR middle-end/28651
	* simplify-rtx.c (simplify_const_relational_operation):
	Simplify A CMP B to A - B CMP 0 only for EQ and NE comparison
	codes.

        * gcc.c-torture/execute/pr28651.c: New testcase.

Index: simplify-rtx.c
===================================================================
*** simplify-rtx.c	(revision 115838)
--- simplify-rtx.c	(working copy)
*************** simplify_const_relational_operation (enu
*** 3075,3093 ****
       a register or a CONST_INT, this can't help; testing for these cases will
       prevent infinite recursion here and speed things up.
  
!      If CODE is an unsigned comparison, then we can never do this optimization,
!      because it gives an incorrect result if the subtraction wraps around zero.
!      ANSI C defines unsigned operations such that they never overflow, and
!      thus such cases can not be ignored; but we cannot do it even for
!      signed comparisons for languages such as Java, so test flag_wrapv.  */
  
!   if (!flag_wrapv && INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
        && ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
  	    && (REG_P (op1) || GET_CODE (trueop1) == CONST_INT))
        && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
!       /* We cannot do this for == or != if tem is a nonzero address.  */
!       && ((code != EQ && code != NE) || ! nonzero_address_p (tem))
!       && code != GTU && code != GEU && code != LTU && code != LEU)
      return simplify_const_relational_operation (signed_condition (code),
  						mode, tem, const0_rtx);
  
--- 3075,3092 ----
       a register or a CONST_INT, this can't help; testing for these cases will
       prevent infinite recursion here and speed things up.
  
!      We can only do this for EQ and NE comparisons as otherwise we may
!      lose or introduce overflow which we cannot disregard as undefined as
!      we do not know the signedness of the operation on either the left or
!      the right hand side of the comparison.  */
  
!   if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
!       && (code == EQ || code == NE)
        && ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
  	    && (REG_P (op1) || GET_CODE (trueop1) == CONST_INT))
        && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
!       /* We cannot do this if tem is a nonzero address.  */
!       && ! nonzero_address_p (tem))
      return simplify_const_relational_operation (signed_condition (code),
  						mode, tem, const0_rtx);
  
Index: testsuite/gcc.c-torture/execute/pr28651.c
===================================================================
*** testsuite/gcc.c-torture/execute/pr28651.c	(revision 0)
--- testsuite/gcc.c-torture/execute/pr28651.c	(revision 0)
***************
*** 0 ****
--- 1,24 ----
+ extern void abort (void);
+ int
+ foo (unsigned int u)
+ {
+   return (int)(u + 4) < (int)u;
+ }
+ 
+ int
+ main (int argc, char *argv[])
+ {
+   unsigned int u;
+ 
+   /* Run with no arguments so u will be MAX_INT and the optimizers
+      won't know its value.  */
+   if (argc > 1)
+     u = 1;
+   else
+     u = 0x7fffffff;
+ 
+   if (foo (u) == 0)
+     abort();
+   return 0;
+ }
+ 


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