From: youki@rd.ecip.osaka-u.ac.jp (Youki Kadobayashi)
Newsgroups: fj.lang.c
Subject: Re: gcc optimize bug?
Date: 14 Apr 92 06:23:06 GMT
Followup-To: fj.lang.c
Distribution: fj
Organization: R&D, Edu Center for Info Processing, Japan
In-reply-to: kis@qi.rqa.sony.co.jp's message of 13 Apr 92 23:58:29 GMT


$B:eBg>pJs9)3X2J$NLgNS$H?=$7$^$9!#(B

>>>>> kis@qi.rqa.sony.co.jp (Koji Kishi) said:

> gcc2.1 $B$r(B NWS-3860 OS4.01R $B$G$&$4$+$7$F$^$9$,!"(B
> $B<!$N$h$&$J%W(B$B%m%0%i%`$r:GE,2=$D$-$G%3%s%Q%$%k$9$k$H<:GT$7$^$9!#(B
...
> #include <stdio.h>
> main()
> {
>     short i;
>     for (i = -1; i <= 1; i++)
>         printf("%d\n", i);
> }
...
> $B$?$V$s%*%W%A%^%$%6$,(B short $B$r(B unsigned $B$H;W$$9~$s$G$k$s$8$c$J$$$+$H;W(B
> $B$&$s$@$1$I!"(BRISC $B$@$1$C$F$N$,$h$/$o$+$i$J$$!#(B

$B$&$A$N(B Sun4c $B$H(B NeXT(68040) $B$G$O(B -g, -O -O2 $B$N$I$l$rA*$s$G$b!"(B
$B@5>o$K<B9T$G$-$^$7$?!#(B($B$7$+$7!"$9$4$$%3!<%IEG(B$B$-$^$9$M(B..)

gnu.gcc.bug $B$r$:$C$H(B watch$B$7$F$*$i$l$k$N$G$"$l$P!"0J2<$N%a%C%;!<%8$O(B
$BFI$_$H$P$7$F2<$5$$!#(B


gcc-2.1 Optimizer $B$N%P%0$O$$$/$D$+CN$i$l$F$$$^$9!#%Q%C%A$r$^$H$a$F(B
$B$D$1$F$*$-$^$9!#(B
$B$"$H(B MIPS $B$,$i(B$B$_$N%Q%C%A$r(B hikichi@sra $B$5$s$,%]%9%H$7$F$*$i$l$^$7$?(B
$B$,!"<B:]$K;n$7$F$$$J$$$N$G>JN,$7$^$9!#(B

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[ $B$3$N%Q%C%A$K4X$7$F$O!V$"$F$k$J!W$H$$$&%a%C(B$B%;!<%8$,N.$l$F$$$^$7$?!#(B
$BKM$O$"$F$F(B stage3 $B$^$G(B make$B$7$^$7$?$,!"(BSun4c, Sun3x, NeXT $B$G$O@5>o$K(B
$BF0$$$F$$(B$B$^$9(B. ]
From: chip@tct.COM (Chip Salzenberg)
Newsgroups: gnu.gcc.bug
Subject: FIX FOR: optimization bug
Date: 10 Apr 92 13:31:00 GMT
Distribution: gnu
Organization: TC Telemanagement, Clearwater, FL

A bug report from James Clark <jjc@jclark.com> reports that GCC 2.1
misoptimizes this program:
	main()
	{
	  signed char c = -1;
	  printf("%d\n", c < 0);
	  exit(0);
	}
It prints zero instead of one.

I've found this bug.  The optimizer is noting that "c" equals 0xFF,
but it is forgetting that 0xFF is a _byte_ value (QImode).  So when
the optimizer SIGN_EXTENDs that constant, the constant looks like it
has already been extended.  This bug results in a wrong value of 255
(which is, of course, not less than zero) instead of the correct -1.

The below patch makes GCC generate and retain the correct machine
modes for constants.

----------------------------------------------------------------------------

Thu Apr  9 17:22:19 1992  Chip Salzenberg  (chip at tct.com)

	* emit-rtl.c (gen_rtx): Generate CONST_INT with requested MODE.
	  (gen_lowpart_common): Ditto.

Index: emit-rtl.c
*************** gen_rtx (va_alist)
*** 257,260 ****
--- 257,261 ----
  
        rt_val = rtx_alloc (code);
+       rt_val->mode = mode;
        INTVAL (rt_val) = arg;
      }
*************** gen_lowpart_common (mode, x)
*** 533,537 ****
  	    : (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_INT
  	       && GET_CODE (x) == CONST_INT) ? x
! 	    : gen_rtx (CONST_INT, VOIDmode,
  		       (GET_MODE_MASK (mode)
  			& (GET_CODE (x) == CONST_INT
--- 534,538 ----
  	    : (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_INT
  	       && GET_CODE (x) == CONST_INT) ? x
! 	    : gen_rtx (CONST_INT, mode,
  		       (GET_MODE_MASK (mode)
  			& (GET_CODE (x) == CONST_INT
-- 
Chip Salzenberg at Teltronics/TCT  <chip@tct.com>, <73717.366@compuserve.com>
      "Informix 4GL is not a 4G, and it's barely an L."  -- John Tombs


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
From: chip@tct.COM (Chip Salzenberg)
Newsgroups: gnu.gcc.bug
Subject: Re: FIX FOR: gcc 2.1 post increment bug
Date: 9 Apr 92 21:21:00 GMT
Distribution: gnu
Organization: TC Telemanagement, Clearwater, FL

A bug report from brennan@baker.ds.boeing.COM shows that, under
optimization, "switch (*p++)" may branch to the wrong case in the
switch.  Here is a patch.

----------------------------------------------------------------------------
Thu Apr  9 09:50:26 1992  Chip Salzenberg  (chip at tct.com)

	* stmt.c (expand_end_case): Before using index expression,
	  take care to call copy_to_reg() and protect_from_queue().

Index: stmt.c
*************** expand_end_case (orig_index)
*** 3582,3591 ****
  	    }
  
  	  emit_queue ();
  	  do_pending_stack_adjust ();
  
- 	  index = protect_from_queue (index, 0);
- 	  if (GET_CODE (index) == MEM)
- 	    index = copy_to_reg (index);
  	  if (GET_CODE (index) == CONST_INT
  	      || TREE_CODE (index_expr) == INTEGER_CST)
--- 3582,3591 ----
  	    }
  
+ 	  if (GET_CODE (index) == MEM)
+ 	    index = copy_to_reg (index);
+ 	  index = protect_from_queue (index, 0);
  	  emit_queue ();
  	  do_pending_stack_adjust ();
  
  	  if (GET_CODE (index) == CONST_INT
  	      || TREE_CODE (index_expr) == INTEGER_CST)
*************** expand_end_case (orig_index)
*** 3662,3667 ****
  				      index_expr);
  	      index = expand_expr (index_expr, 0, VOIDmode, 0);
! 	      emit_queue ();
  	      index = protect_from_queue (index, 0);
  	      do_pending_stack_adjust ();
  
--- 3662,3671 ----
  				      index_expr);
  	      index = expand_expr (index_expr, 0, VOIDmode, 0);
! 
! 
! 	      if (GET_CODE (index) == MEM)
! 		index = copy_to_reg (index);
  	      index = protect_from_queue (index, 0);
+ 	      emit_queue ();
  	      do_pending_stack_adjust ();
  
*************** expand_end_case (orig_index)
*** 3681,3686 ****
  	      index = expand_expr (index_expr, 0, VOIDmode, 0);
  	      index = convert_to_mode (Pmode, index, 1);
! 	      emit_queue ();
  	      index = protect_from_queue (index, 0);
  	      do_pending_stack_adjust ();
  
--- 3685,3693 ----
  	      index = expand_expr (index_expr, 0, VOIDmode, 0);
  	      index = convert_to_mode (Pmode, index, 1);
! 
! 	      if (GET_CODE (index) == MEM)
! 		index = copy_to_reg (index);
  	      index = protect_from_queue (index, 0);
+ 	      emit_queue ();
  	      do_pending_stack_adjust ();
  
-- 
Chip Salzenberg at Teltronics/TCT  <chip@tct.com>, <73717.366@compuserve.com>
      "Informix 4GL is not a 4G, and it's barely an L."  -- John Tombs

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
From: eggert@twinsun.COM (Paul Eggert)
Newsgroups: gnu.gcc.bug
Subject: GCC 2.1 misoptimizes (x ? 0.0 : -0.0) to 0.0 on IEEE 754 hosts
Date: 26 Mar 92 04:06:34 GMT
Distribution: gnu
Organization: GNUs Not Usenet

GCC 2.1 (Sparc, SunOS 4.1.2) misoptimizes the expression (x ? 0.0 : -0.0)
to 0.0.  This optimization isn't valid on a host that uses IEEE 754,
where 0.0 and -0.0 are distinct values.  The following shell transcript
illustrates the problem:

$ cat A.c
int i;
int main() { printf("should be -0: %g\n", i ? 0.0 : -0.0); return 0; }
$ gcc -O A.c
$ ./a.out
should be -0: 0

Here is a patch.  This patch assumes several patches for GCC 2.0 that I sent
previously.  For convenience, at the end of this message I enclose all
those patches combined, updated so that they apply to GCC 2.1 instead of
GCC 2.0.

In this patch, I also removed some mistaken invocations of REAL_VALUE_ISINF
and REAL_VALUE_ISNAN, which aren't needed and can cause less optimal code to
be generated.

*** fold-const.c	Wed Mar 25 15:17:48 1992
--- fold-const.c-FIX	Wed Mar 25 19:17:12 1992
***************
*** 1482,1493 ****
      return 1;
  
    /* Detect when real constants are equal.
!      But reject weird values because we can't be sure what to do with them.  */
    if (TREE_CODE (arg0) == TREE_CODE (arg1)
        && TREE_CODE (arg0) == REAL_CST
        && REAL_VALUES_EQUAL (TREE_REAL_CST (arg0), TREE_REAL_CST (arg1))
!       && !REAL_VALUE_ISINF (TREE_REAL_CST (arg0))
!       && !REAL_VALUE_ISNAN (TREE_REAL_CST (arg0)))
      return 1;
  
    if (only_const)
--- 1482,1493 ----
      return 1;
  
    /* Detect when real constants are equal.
!      Make sure the signs match, so that IEEE -0 and 0 are distinguished.  */
    if (TREE_CODE (arg0) == TREE_CODE (arg1)
        && TREE_CODE (arg0) == REAL_CST
        && REAL_VALUES_EQUAL (TREE_REAL_CST (arg0), TREE_REAL_CST (arg1))
!       && REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0))
! 	 == REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
      return 1;
  
    if (only_const)



Here is a combination of all my -0.0 and NaN patches,
including the above patch, updated for GCC 2.1.

Wed Mar 25 19:22:26 1992  Paul Eggert  (eggert@twinsun.com)

	* cse.c (simplify_unary_operation): fabs(-0.0) is 0.0, not -0.0.
	* fold-const.c: Replace target_minus_zero with target_negative.
	(fold_convert): Warn when converting NaN constants to integer.
	(operand_equal_p): Don't optimize (x ? -0.0 : 0.0) to 0.0 if IEEE.
	(fold): fabs(-0.0) is 0.0, not -0.0.  0-x may not equal -x.
	Do not optimize X++ == C to ++X == C+1 if C is floating point,
	because it runs afoul of rounding error.
	* real.h (REAL_VALUE_NEGATIVE): Add.

===================================================================
RCS file: real.h,v
retrieving revision 2.1
diff -u2 -r2.1 real.h
--- real.h	1992/03/19 19:42:28	2.1
+++ real.h	1992/03/26 02:19:41
@@ -143,7 +143,12 @@
 #endif
 
+/* Determine whether a floating-point value X is negative. */
+#ifndef REAL_VALUE_NEGATIVE
+#define REAL_VALUE_NEGATIVE(x) (target_negative (x))
+#endif
+
 /* Determine whether a floating-point value X is minus 0. */
 #ifndef REAL_VALUE_MINUS_ZERO
-#define REAL_VALUE_MINUS_ZERO(x) (target_minus_zero (x))
+#define REAL_VALUE_MINUS_ZERO(x) ((x) == 0 && REAL_VALUE_NEGATIVE (x))
 #endif
 
===================================================================
RCS file: cse.c,v
retrieving revision 2.1
diff -u2 -r2.1 cse.c
--- cse.c	1992/03/24 22:20:30	2.1
+++ cse.c	1992/03/26 01:39:15
@@ -2859,5 +2859,5 @@
 
 	case ABS:
-	  if (REAL_VALUES_LESS (d, 0.0))
+	  if (REAL_VALUE_NEGATIVE (d))
 	    d = REAL_VALUE_NEGATE (d);
 	  break;
===================================================================
RCS file: fold-const.c,v
retrieving revision 2.1
diff -u2 -r2.1 fold-const.c
--- fold-const.c	1992/03/22 05:08:53	2.1
+++ fold-const.c	1992/03/26 03:17:12
@@ -779,16 +779,38 @@
 }
 
-/* Check for minus zero in an IEEE double precision number.  */
+/* Check whether an IEEE double precision number is negative.  */
 
 int
-target_minus_zero (x)
+target_negative (x)
      REAL_VALUE_TYPE x;
 {
-  REAL_VALUE_TYPE d1, d2;
+  /* The IEEE 64-bit double format.  */
+  union {
+    REAL_VALUE_TYPE d;
+    struct {
+      unsigned sign      :  1;
+      unsigned exponent  : 11;
+      unsigned mantissa1 : 20;
+      unsigned mantissa2;
+    } little_endian;
+    struct {
+      unsigned mantissa2;
+      unsigned mantissa1 : 20;
+      unsigned exponent  : 11;
+      unsigned sign      :  1;
+    } big_endian;    
+  } u;
 
-  d1 = REAL_VALUE_NEGATE (x);
-  d2 = dconst0;
-
-  return !bcmp (&d1, &d2, sizeof (d1));
+  u.d = dconstm1;
+  if (u.big_endian.sign == 1)
+    {
+      u.d = x;
+      return u.big_endian.sign;
+    }
+  else
+    {
+      u.d = x;
+      return u.little_endian.sign;
+    }
 }
 #else /* Target not IEEE */
@@ -813,10 +835,10 @@
 
 /* Let's assume other float formats don't have minus zero.
-   (This can be overridden by redefining REAL_VALUE_MINUS_ZERO.)  */
+   (This can be overridden by redefining REAL_VALUE_NEGATIVE.)  */
 
-target_minus_zero (x)
+target_negative (x)
      REAL_VALUE_TYPE x;
 {
-  return 0;
+  return x < 0;
 }
 #endif /* Target not IEEE */
@@ -1348,8 +1370,10 @@
       else if (TREE_CODE (arg1) == REAL_CST)
 	{
-	  if (REAL_VALUES_LESS (real_value_from_int_cst (TYPE_MAX_VALUE (type)),
-				TREE_REAL_CST (arg1))
-	      || REAL_VALUES_LESS (TREE_REAL_CST (arg1),
-				   real_value_from_int_cst (TYPE_MIN_VALUE (type))))
+	  REAL_VALUE_TYPE
+	    l = real_value_from_int_cst (TYPE_MIN_VALUE (type)),
+	    x = TREE_REAL_CST (arg1),
+	    u = real_value_from_int_cst (TYPE_MAX_VALUE (type));
+	  if (! ((REAL_VALUES_LESS (l, x) || REAL_VALUES_EQUAL (l, x))
+		 && (REAL_VALUES_LESS (x, u) || REAL_VALUES_EQUAL (x, u))))
 	    {
 	      warning ("real constant out of range for integer conversion");
@@ -1459,10 +1483,10 @@
 
   /* Detect when real constants are equal.
-     But reject weird values because we can't be sure what to do with them.  */
+     Make sure the signs match, so that IEEE -0 and 0 are distinguished.  */
   if (TREE_CODE (arg0) == TREE_CODE (arg1)
       && TREE_CODE (arg0) == REAL_CST
       && REAL_VALUES_EQUAL (TREE_REAL_CST (arg0), TREE_REAL_CST (arg1))
-      && !REAL_VALUE_ISINF (TREE_REAL_CST (arg0))
-      && !REAL_VALUE_ISNAN (TREE_REAL_CST (arg0)))
+      && REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0))
+	 == REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
     return 1;
 
@@ -2600,5 +2624,5 @@
 	  else if (TREE_CODE (arg0) == REAL_CST)
 	    {
-	      if (REAL_VALUES_LESS (TREE_REAL_CST (arg0), dconst0))
+	      if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0)))
 		t = build_real (type,
 				REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
@@ -2763,10 +2787,11 @@
       else if (TREE_CODE (arg1) == NEGATE_EXPR)
 	return fold (build (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)));
-      else
+      else if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
 	{
+	  /* In IEEE floating point, 0-x may not equal -x.  */
 	  if (! wins && real_zerop (arg0))
 	    return build1 (NEGATE_EXPR, type, arg1);
 	  /* In IEEE floating point, x-0 may not equal x.  */
-	  if (real_zerop (arg1) && TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
+	  if (real_zerop (arg1))
 	    return non_lvalue (convert (type, arg0));
 	}
@@ -2799,13 +2824,11 @@
 				TREE_OPERAND (arg0, 1)));
 	}
-      /* In IEEE floating point, these optimizations are not correct.  */
       else
 	{
+	  /* x*0 is 0, except for IEEE floating point.  */
 	  if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
 	      && real_zerop (arg1))
 	    return omit_one_operand (type, arg1, arg0);
-	  /* In IEEE floating point, x*1 is not equivalent to x for nans.
-	     However, ANSI says we can drop signals,
-	     so we can do this anyway.  */
+	  /* x*1 is x */
 	  if (real_onep (arg1))
 	    return non_lvalue (convert (type, arg0));
@@ -3046,23 +3069,16 @@
 	if (constop && TREE_CODE (varop) == POSTINCREMENT_EXPR)
 	  {
-	    tree newconst
-	      = fold (build (PLUS_EXPR, TREE_TYPE (varop),
-			     constop, TREE_OPERAND (varop, 1)));
 	    /* This optimization is invalid for ordered comparisons
 	       if CONST+INCR overflows or if foo+incr might overflow.
+	       This optimization is invalid for floating point due to rounding.
 	       For pointer types we assume overflow doesn't happen.  */
 	    if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE
-		|| code == EQ_EXPR || code == NE_EXPR)
+		|| (TREE_CODE (TREE_TYPE (varop)) != REAL_TYPE
+		    && (code == EQ_EXPR || code == NE_EXPR)))
 	      {
-		/* This optimization is invalid for floating point
-		   if adding one to the constant does not change it.  */
-		if (TREE_CODE (TREE_TYPE (newconst)) != REAL_TYPE
-		    || !REAL_VALUES_EQUAL (TREE_REAL_CST (newconst),
-					   TREE_REAL_CST (constop)))
-		  {
-		    TREE_SET_CODE (varop, PREINCREMENT_EXPR);
-		    *constoploc = newconst;
-		    return t;
-		  }
+		TREE_SET_CODE (varop, PREINCREMENT_EXPR);
+		*constoploc = fold (build (PLUS_EXPR, TREE_TYPE (varop),
+					   constop, TREE_OPERAND (varop, 1)));
+		return t;
 	      }
 	  }
@@ -3069,18 +3085,12 @@
 	else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
 	  {
-	    tree newconst
-	      = fold (build (MINUS_EXPR, TREE_TYPE (varop),
-			     constop, TREE_OPERAND (varop, 1)));
 	    if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE
-		|| code == EQ_EXPR || code == NE_EXPR)
+		|| (TREE_CODE (TREE_TYPE (varop)) != REAL_TYPE
+		    && (code == EQ_EXPR || code == NE_EXPR)))
 	      {
-		if (TREE_CODE (TREE_TYPE (newconst)) != REAL_TYPE
-		    || !REAL_VALUES_EQUAL (TREE_REAL_CST (newconst),
-					   TREE_REAL_CST (constop)))
-		  {
-		    TREE_SET_CODE (varop, PREDECREMENT_EXPR);
-		    *constoploc = newconst;
-		    return t;
-		  }
+		TREE_SET_CODE (varop, PREDECREMENT_EXPR);
+		*constoploc = fold (build (MINUS_EXPR, TREE_TYPE (varop),
+					   constop, TREE_OPERAND (varop, 1)));
+		return t;
 	      }
 	  }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

--
		$BLgNS(B $BM:4p(B <youki@ics.osaka-u.ac.jp>
		$BBg:eBg3X4pAC9)3XIt>pJs9)3X2J(B
		$B>pJs%M%C%H%o!<%/3X9V:B(B $B=$;N0lG/(B