[gnu.gcc.bug] bug in m68k gcc 1.32

trq@MOOSE.CITA.UTORONTO.CA (Tom Quinn) (01/17/89)

gcc with the "-O -fomit-frame-pointer" flags compiles the following
code into something which loses track of the stack pointer, and
therefore, returns to never-neverland.  This is gcc version 1.32 on a
Sun 3/50 running SunOS 3.5.

Tom Quinn                 Canadian Institute for Theoretical Astrophysics
trq@moose.cita.utoronto.ca
UUCP   - decvax!utgpu!moose!trq
BITNET - quinn@utorphys.bitnet
ARPA   - trq%moose.cita.toronto.edu@relay.cs.net

The compile:
gcc -S -g -v -O -fomit-frame-pointer -c history.c
gcc version 1.32
 /usr/local/lib/gcc-cpp -v -undef -D__GNUC__ -Dmc68000 -Dsun -Dunix -D__mc68000_
_ -D__sun__ -D__unix__ -D__OPTIMIZE__ -D__HAVE_68881__ -Dmc68020 history.c /tmp/cca28687.cpp
GNU CPP version 1.32
 /usr/local/lib/gcc-cc1 /tmp/cca28687.cpp -quiet -dumpbase history.c -fomit-frame-pointer -g -O -version -o history.s
GNU C version 1.32 (68k, MIT syntax) compiled by GNU C version 1.32.

The offending assembler:
	.stabd 68,0,31
	clrl sp@-
	movel a2,sp@-
	jbsr _edit_line
	movel d0,d1
	moveq #14,d3
	cmpl d1,d3
	jeq L15
	jlt L25
	moveq #13,d3
	cmpl d1,d3
	jeq L6
	addqw #8,sp   ### this should be before the above jumps.
	jra L21
L25:
	moveq #16,d3
	cmpl d1,d3
	jeq L17
	jra L21

The code:
------------------------------------------------------------------------
extern	struct	_iobuf {
	int	_cnt;
	unsigned char *_ptr;
	unsigned char *_base;
	int	_bufsiz;
	short	_flag;
	char	_file;		 
} _iob[];
extern	char	_ctype_[];
typedef struct {
   char line[82	];			 
   int num;				 
} HISTORY;
static char search_str[40] = "";	 
static HISTORY **hist;			 
extern int interrupt;			 
static int hindex,			 
	   hlev,			 
	   hsize;			 
char *
edit_hist()
{
   char *current,			 
   	*strcpy(),
        *strncpy();
   int i,
       index = 0;			 
   current = hist[hindex%hsize]->line;	 
   erase_str(current,82				);
   for(;;) {
      switch(i = edit_line(current,(char **)0 )) {
       case 13  :			 
	 interrupt = 0;
	 search_str[0] = '\0';		 
	 printf("\n");
	 for(i = strlen(current) - 1;i >= 0 && current[i] != '\0';i--) {
	    if(!((_ctype_+1)[current[i]]&010 ) ) break;
	    current[i] = '\0';
	 }
	 if(i < 0) {			 
	    break;
	 }
	 if(hindex == 0 || strcmp(hist[hindex%hsize]->line,
				 hist[(hindex - 1)%hsize]->line) != 0) {
	    hist[hindex++%hsize]->num = hlev++;
	 }
	 return(current);
       case 14  :			 
	 if(index > 0) {
	    index--;
	 }
	 erase_str(current,82				);
	 (void)strcpy(current,hist[(hsize + hindex - index)%hsize]->line);
	 break;
       case 16 :			 
	 if(index <= hsize - 1 &&	 
	       (index == 0 || hist[(hsize + hindex - index)%hsize]->num > 0)) {
	    index++;
	 }
	 erase_str(current,82				);
	 if(hist[(hsize + hindex - index)%hsize]->num > 0) {
	    (void)strcpy(current,hist[(hsize + hindex - index)%hsize]->line);
	 }
	 break;
       default:
	 (--((&_iob[1]) )->_cnt>=0? (int)(*((&_iob[1]) )->_ptr++=(unsigned char)((7 ))):_flsbuf((unsigned char)((7 )),(&_iob[1]) ))  ;
	 break;
      }
      (void)fflush((&_iob[1]) );
   }
}

trq@MOOSE.CITA.UTORONTO.CA (Tom Quinn) (01/20/89)

The following code generates incorrect assembly when compiled with the
"-g -O -fforce-mem" options.  This is gcc version 1.32 on a Sun 3/50
running SunOs 3.5.  The problem is that the assignment on line 117
from the long to the short grabs the wrong half of the long.

Tom Quinn                 Canadian Institute for Theoretical Astrophysics
trq@moose.cita.utoronto.ca
UUCP   - decvax!utgpu!moose!trq
BITNET - quinn@utorphys.bitnet
ARPA   - trq%moose.cita.toronto.edu@relay.cs.net

The compile:

gcc -S -g -v -O -fforce-mem -c XConnDis.c
gcc version 1.32
/usr/local/lib/gcc-cpp -v -undef -D__GNUC__ -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -D__OPTIMIZE__ -D__HAVE_68881__ -Dmc68020 XConnDis.c /tmp/cca15882.cpp
GNU CPP version 1.32
/usr/local/lib/gcc-cc1 /tmp/cca15882.cpp -quiet -dumpbase XConnDis.c -fforce-mem -g -O -version -o XConnDis.s
GNU C version 1.32 (68k, MIT syntax) compiled by GNU C version 1.32.

The offending assembly:
L20:
       .stabd 68,0,117
       movew a0@(8),a6@(-272) # this should be a "movew a0(10),a6@(-272)"
       .stabd 68,0,120

The code:
------------------------------------------------------------------------
typedef	unsigned char	u_char;
typedef	unsigned short	u_short;
typedef	unsigned long	u_long;
char	*strcat();
int	strcmp();
char	*strcpy();
int	strlen();
struct in_addr {
       union {
	       struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
	       struct { u_short s_w1,s_w2; } S_un_w;
	       u_long S_addr;
       } S_un;
};
struct sockaddr_in {
       short	sin_family;
       u_short	sin_port;
       struct	in_addr sin_addr;
       char	sin_zero[8];
};
struct	hostent {
       char	*h_name;	 
       char	**h_aliases;	 
       int	h_addrtype;	 
       int	h_length;	 
       char	*h_addr;	 
};
char *strncpy();
extern char *index();
extern int errno;
struct sockaddr {
       u_short	sa_family;		 
       char	sa_data[14];		 
};
struct	sockaddr_un {
       short	sun_family;		 
       char	sun_path[109];		 
};
void bcopy();
int _XConnectDisplay (display_name, expanded_name, prop_name, screen_num)
   char *display_name;
   char *expanded_name;	 
   char *prop_name;		 
   int *screen_num;		 
{
       char displaybuf[256];		 	
       register char *display_ptr;	 
       register char *numbuf_ptr;	 
       char *screen_ptr;		 
       int display_num;		 
       struct sockaddr_in inaddr;	 
       unsigned long hostinetaddr;	 
       struct sockaddr_un unaddr;	 
       struct sockaddr *addr;		 
       struct hostent *host_ptr;
       int addrlen;			 
       extern char *getenv();
       extern struct hostent *gethostbyname();
       int fd;				 
       char numberbuf[16];
       char *dot_ptr = 0 ;		 
       (void) strncpy(displaybuf, display_name, sizeof(displaybuf));
       if ((display_ptr = index((displaybuf), (':')) ) == 0 ) return (-1);
       *(display_ptr++) = '\0';
       if (*display_ptr == '\0') return(-1);
       screen_ptr = display_ptr;		 
       numbuf_ptr = numberbuf;			 
       while (*screen_ptr != '\0') {
	   if (*screen_ptr == '.') {		 
	       if (dot_ptr) {			 
		   screen_ptr++;
		   break;
	       }
	       dot_ptr = numbuf_ptr;		 
	       *(screen_ptr++) = '\0';
	       *(numbuf_ptr++) = '.';
	   } else {
	       *(numbuf_ptr++) = *(screen_ptr++);
	   }
       }
       if (dot_ptr == 0 ) {			 
	   dot_ptr = numbuf_ptr;
	   *(numbuf_ptr++) = '.';
	   *(numbuf_ptr++) = '0';
       } else {
	   if (*(numbuf_ptr - 1) == '.')
	       *(numbuf_ptr++) = '0';
       }
       *numbuf_ptr = '\0';
       *screen_num = atoi(dot_ptr + 1);
       strcpy (prop_name, screen_ptr);
       display_num = atoi(display_ptr);
       if (displaybuf[0] == '\0')
	       ;	 
       {
	   if ((displaybuf[0] == '\0') || 
	       (strcmp("unix", displaybuf) == 0)) {
	       unaddr.sun_family = 	1		;
	       (void) strcpy(unaddr.sun_path, "/tmp/.X11-unix/X" );
	       strcat(unaddr.sun_path, display_ptr);
	       addr = (struct sockaddr *) &unaddr;
	       addrlen = strlen(unaddr.sun_path) + 2;
	       if ((fd = socket((int) addr->sa_family, 1		, 0)) < 0)
		   return(-1);	     
	   } else
	   {
	       hostinetaddr = inet_addr (displaybuf);
	       if (hostinetaddr == -1) {
		       if ((host_ptr = gethostbyname(displaybuf)) == 0 ) {
			       errno = 	22		;
			       return(-1);
		       }
		       if (host_ptr->h_addrtype != 	2		) {
			       errno = 41		;
			       return(-1);
		       }
		       inaddr.sin_family = host_ptr->h_addrtype;
		       bcopy((char *)host_ptr->h_addr, 
			     (char *)&inaddr.sin_addr, 
			     sizeof(inaddr.sin_addr));
	       } else {
		       inaddr.sin_addr.S_un.S_addr	 = hostinetaddr;
		       inaddr.sin_family = 	2		;
	       }
	       addr = (struct sockaddr *) &inaddr;
	       addrlen = sizeof (struct sockaddr_in);
	       inaddr.sin_port = display_num;
	       inaddr.sin_port += 6000     ;
	       inaddr.sin_port = (inaddr.sin_port) ;
	       if ((fd = socket((int) addr->sa_family, 1		, 0)) < 0)
		   return(-1);	     
	       {
	       int mi = 1;
	       setsockopt (fd, 	6		, 0x01	, &mi, sizeof (int));
	       }
	   }
	   if (connect(fd, addr, addrlen) == -1) {
	       (void) close (fd);
	       return(-1); 	     
	   }
       }
       (void) fcntl(fd, 4	, 	00004		);
       display_ptr = displaybuf-1;
       while (*(++display_ptr) != '\0')
	   ;
       *(display_ptr++) = ':';
       numbuf_ptr = numberbuf;
       while (*numbuf_ptr != '\0')
	   *(display_ptr++) = *(numbuf_ptr++);
       if (prop_name[0] != '\0') {
	   char *cp;
	   *(display_ptr++) = '.';
	   for (cp = prop_name; *cp; cp++) *(display_ptr++) = *cp;
       }
       *display_ptr = '\0';
       (void) strcpy(expanded_name, displaybuf);
       return(fd);
}