From: schwab@lamothe.informatik.uni-dortmund.de (Andreas Schwab)
Subject: GCC 2.3.1/m68k: incorrect output
Reply-To: schwab@ls5.informatik.uni-dortmund.de (Andreas Schwab)
Organization: GNUs Not Usenet
Distribution: gnu
Date: Mon, 16 Nov 1992 12:42:11 GMT

GCC 2.3.1/m68k (Atari ST) generates incorrect output for the file test.c
(see below), if compiled with

gcc -O2 -fomit-frame-pointer -m68000 -msoft-float -S test.c

(-m68000 and -msoft-float are not generally required to trigger the
bug; they only make the function more complex)

Here are the relevant parts of the output:

---------- test.s
#NO_APP
gcc2_compiled.:
.text
	.even
_ston:
	addw #-24,sp
	moveml #0x3f3e,sp@-
	movel sp@(72),a3
	clrl sp@(60)
	moveb #43,sp@(59)	| char msign = '+';
	moveb sp@(59),sp@(57)	| char esign = '+';

| lines deleted

	moveq #43,d7		| if (c == '+' || c == '-')
	cmpl a2,d7
	jeq L6
	moveq #45,d7
	cmpl a2,d7
	jne L5

L6:
	movew a2,sp@-		| msign = c;
	moveb sp@(1),sp@(59)	| <---- should be sp@(61)
	addqw #2,sp
	moveb a3@+,d7		| c = *s++;
	extw d7
	movew d7,a0
	movew a0,a2

| many lines deleted

	moveq #101,d7		| if (c == 'e' || c == 'E')
	cmpl a2,d7
	jeq L23
	moveq #69,d7
	cmpl a2,d7
	jne L22
L23:
	addql #1,sp@(60)	| realflag++;
	moveb a3@+,d7		| c = *s++;
	extw d7
	movew d7,a0
	movew a0,a2
	moveq #43,d7		| if (c == '+' || c == '-')
	cmpl a2,d7
	jeq L25
	moveq #45,d7
	cmpl a2,d7
	jne L24
L25:
	movew a2,sp@-		| esign = c;
	moveb sp@(1),sp@(57)	| <---- should be sp@(59)
	addqw #2,sp
	moveb a3@+,d7		| c = *s++;
	extw d7
	movew d7,a0
	movew a0,a2

| rest deleted
----------

Here is the test file:

---------- test.c
double ldexp (double, int);

typedef int word;
typedef struct descrip *dptr;

struct descrip
  {
    word dword;
    word integr;
  };

int makereal (double r, dptr dp);
word bigradix (int sign, int r, char *s, dptr dx);

extern unsigned char *_ctype;

static int 
ston (s, dp)
     register char *s;
     dptr dp;
{
  register int c;
  int realflag = 0;
  char msign = '+';
  char esign = '+';
  double mantissa = 0;
  long lresult = 0;
  int scale = 0;
  int digits = 0;
  int sdigits = 0;
  int exponent = 0;
  double fiveto;
  double power;
  int err_no;
  char *ssave;

  c = *s++;
  while ((_ctype[(unsigned char) (c)] & 0x10))
    c = *s++;
  if (c == '+' || c == '-')
    {
      msign = c;
      c = *s++;
    }
  ssave = s - 1;
  while ((_ctype[(unsigned char) (c)] & 0x02))
    {
      digits++;
      if (mantissa < 9007199254740992.)
	{
	  mantissa = mantissa * 10 + (c - '0');
	  lresult = lresult * 10 + (c - '0');
	  if (mantissa > 0.0)
	    sdigits++;
	}
      else
	scale++;
      c = *s++;
    }
  if (c == 'r' || c == 'R')
    return bigradix (msign, (int) mantissa, s, dp);
  if (c == '.')
    {
      realflag++;
      c = *s++;
      while ((_ctype[(unsigned char) (c)] & 0x02))
	{
	  digits++;
	  if (mantissa < 9007199254740992.)
	    {
	      mantissa = mantissa * 10 + (c - '0');
	      lresult = lresult * 10 + (c - '0');
	      scale--;
	      if (mantissa > 0.0)
		sdigits++;
	    }
	  c = *s++;
	}
    }
  if (digits == 0)
    return -2;
  if (c == 'e' || c == 'E')
    {
      realflag++;
      c = *s++;
      if (c == '+' || c == '-')
	{
	  esign = c;
	  c = *s++;
	}
      if (!(_ctype[(unsigned char) (c)] & 0x02))
	return -2;
      while ((_ctype[(unsigned char) (c)] & 0x02))
	{
	  exponent = exponent * 10 + (c - '0');
	  c = *s++;
	}
      scale += (esign == '+') ? exponent : -exponent;
    }
  while ((_ctype[(unsigned char) (c)] & 0x10))
    c = *s++;
  if (c != '\0')
    return -2;
  if (!realflag && !scale && mantissa >= ((long int) 020000000000L)
      && mantissa <= ((long int) 017777777777L))
    {
      dp->dword = (word) (1 | 0x80000000);
      dp->integr = (msign == '+' ? lresult : -lresult);
      return 1;
    }
  if (!realflag)
    return bigradix (msign, 10, ssave, dp);
  if (!realflag)
    return -2;
  if (sdigits + scale > 309)
    return -2;
  if (sdigits + scale < -309)
    {
      makereal (0.0, dp);
      return 3;
    }
  exponent = (scale > 0) ? scale : -scale;
  fiveto = 1.0;
  power = 5.0;
  for (;;)
    {
      if (exponent & 01)
	fiveto *= power;
      exponent >>= 1;
      if (exponent == 0)
	break;
      power *= power;
    }
  if (scale > 0)
    mantissa *= fiveto;
  else
    mantissa /= fiveto;
  err_no = 0;
  mantissa = ldexp (mantissa, scale);
  if (err_no > 0 && mantissa > 0)
    return -2;
  if (msign == '-')
    mantissa = -mantissa;
  makereal (mantissa, dp);
  return 3;
}
----------

This patch tries to correct the bug.

--- m68k.md~	Fri Nov 13 22:16:12 1992
+++ m68k.md	Sun Nov 15 18:01:18 1992
@@ -921,7 +921,15 @@
       && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
       && XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx)
     {
-      xoperands[1] = operands[1];
+      if (GET_CODE (operands[1]) == MEM
+	  && (XEXP (operands[1], 0) == stack_pointer_rtx
+	      || (GET_CODE (XEXP (operands[1], 0)) == PLUS
+		  && XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx)))
+	xoperands[1]
+	  = gen_rtx (MEM, GET_MODE (operands[1]),
+		     plus_constant (XEXP (operands[1], 0), 2));
+      else
+	xoperands[1] = operands[1];
       xoperands[2]
         = gen_rtx (MEM, QImode,
 		   gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx));
@@ -934,7 +942,14 @@
 
   if (ADDRESS_REG_P (operands[0]) && GET_CODE (operands[1]) == MEM)
     {
-      xoperands[1] = operands[1];
+      if (XEXP (operands[1], 0) == stack_pointer_rtx
+	  || (GET_CODE (XEXP (operands[1], 0)) == PLUS
+	      && XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx))
+	xoperands[1]
+	  = gen_rtx (MEM, GET_MODE (operands[1]),
+		     plus_constant (XEXP (operands[1], 0), 2));
+      else
+	xoperands[1] = operands[1];
       xoperands[2]
         = gen_rtx (MEM, QImode,
 		   gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx));
@@ -946,7 +961,14 @@
     }
   if (ADDRESS_REG_P (operands[1]) && GET_CODE (operands[0]) == MEM)
     {
-      xoperands[0] = operands[0];
+      if (XEXP (operands[0], 0) == stack_pointer_rtx
+	  || (GET_CODE (XEXP (operands[0], 0)) == PLUS
+	      && XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx))
+	xoperands[0]
+	  = gen_rtx (MEM, GET_MODE (operands[0]),
+		     plus_constant (XEXP (operands[0], 0), 2));
+      else
+	xoperands[0] = operands[0];
       xoperands[1] = operands[1];
       xoperands[2]
         = gen_rtx (MEM, QImode,

Newsgroups: gnu.gcc.bug