[net.bugs.4bsd] bug in cc optimizer

archiel@hercules.UUCP (Archie Lachner) (09/27/84)

There in a bug in the way the 4.2bsd C compiler treats bit fields under some
circumstances when optimization is turned on.  If there is a bit field 16 bits
long that falls on a byte boundary, the optimizer issues a "cvtwl," "movwl,"
or "movzwl" instruction instead of an "extv" or "extzv" instruction when
extracting the field, since the former are more efficient than the latter.
However, the address used for the field in any of the former is incorrect.

I have short program that documents this bug, if anyone is interested.
I don't know if this bug is present on other versions of UNIX, since I only
have 4.2 available to me.
-- 

				Archie Lachner
				Logic Design Systems Division
				Tektronix, Inc.

uucp:    {ucbvax,decvax,pur-ee,cbosg,ihnss}!tektronix!teklds!archiel
CSnet:   archiel@tek
ARPAnet: archiel.tek@csnet-relay

chris@umcp-cs.UUCP (Chris Torek) (09/29/84)

(Does this REALLY need to go to net.lang.c?  Oh well...)  Guy Harris
posted a fix for this one long ago.  It seems that Berkeley never
picked up the fix since the bug is still there in the 4.2BSD /lib/c2.
Here's RCS diffs.  (Thanks, Guy.)

[This first one is just to make it use the 4.2 stdio buffering, which
means /tmp will (hopefully) have less disk activity]

RCS file: RCS/c20.c,v
retrieving revision 1.1
diff -b -c1 -r1.1 c20.c
*** /tmp/,RCSt1001443	Sat Sep 29 11:49:05 1984
--- c20.c	Mon Aug  6 15:57:42 1984
***************
*** 57,59
  			}
! 			setbuf(stdin,_sibuf); ++infound;
  		} else if (freopen(*argv, "w", stdout) ==NULL) {

--- 57,60 -----
  			}
! /*			setbuf(stdin,_sibuf); */
! 			++infound;
  		} else if (freopen(*argv, "w", stdout) ==NULL) {
***************
*** 62,64
  		}
! 		setbuf(stdout,_sobuf);
  		argc--; argv++;

--- 63,65 -----
  		}
! /*		setbuf(stdout,_sobuf); */
  		argc--; argv++;

[and here's the real fixes]

RCS file: RCS/c21.c,v
retrieving revision 1.1
diff -b -c1 -r1.1 c21.c
*** /tmp/,RCSt1001448	Sat Sep 29 11:49:19 1984
--- c21.c	Mon Aug  6 13:43:32 1984
***************
*** 277,279
  		**	extv	$n*8,$8,A,B	>	cvtbl	n+A,B
! 		**	extv	$n*16,$16,A,B	>	cvtwl	n+A,B
  		**	extzv	$n*8,$8,A,B	>	movzbl	n+A,B

--- 277,279 -----
  		**	extv	$n*8,$8,A,B	>	cvtbl	n+A,B
! 		**	extv	$n*16,$16,A,B	>	cvtwl	2n+A,B
  		**	extzv	$n*8,$8,A,B	>	movzbl	n+A,B
***************
*** 279,281
  		**	extzv	$n*8,$8,A,B	>	movzbl	n+A,B
! 		**	extzv	$n*16,$16,A,B	>	movzwl	n+A,B
  		*/

--- 279,281 -----
  		**	extzv	$n*8,$8,A,B	>	movzbl	n+A,B
! 		**	extzv	$n*16,$16,A,B	>	movzwl	2n+A,B
  		*/
***************
*** 324,326
  			else
! 				sprintf(regs[RT1], "%d%s%s", coff, regs[RT3][0]=='(' ? "":"+",
  					regs[RT3]);

--- 324,328 -----
  			else
! 				sprintf(regs[RT1], "%d%s%s",
! 					(flen == 8 ? coff : 2*coff),
! 					(regs[RT3][0] == '(' ? "" : "+"),
  					regs[RT3]);
***************
*** 790,791
  	register char *cp1,*cp2; int r;
  	char src[C2_ASIZE];

--- 792,794 -----
  	register char *cp1,*cp2; int r;
+ 	int lhssiz, subop;
  	char src[C2_ASIZE];
***************
*** 806,807
  			}
  			if (p->back->op==CVT || p->back->op==MOVZ) {/* greedy, aren't we? */

--- 809,824 -----
  			}
+ 			/*
+ 			 * 'pos', 'siz' known; find out the size of the
+ 			 * left-hand operand of what the bicl will turn into.
+ 			 */
+ 			if (pos==0) {
+ 				if (siz==8)
+ 					lhssiz = BYTE;/* movzbl */
+ 				else if (siz==16)
+ 					lhssiz = WORD;/* movzwl */
+ 				else
+ 					lhssiz = BYTE;/* extzvl */
+ 			}
+ 			else
+ 				lhssiz = BYTE;/* extzvl */
  			if (p->back->op==CVT || p->back->op==MOVZ) {/* greedy, aren't we? */
***************
*** 808,810
  				splitrand(p->back); cp1=regs[RT1]; cp2=regs[RT2];
! 				if (equstr(src,cp2) && okio(cp1) && !indexa(cp1)
  				  && 0<=(r=isreg(cp2)) && r<NUSE

--- 825,840 -----
  				splitrand(p->back); cp1=regs[RT1]; cp2=regs[RT2];
! 				/*
! 				 * If indexa(cp1) || autoid(cp1), the fold may
! 				 * still be OK if the CVT/MOVZ has the same
! 				 * size operand on its left size as what we
! 				 * will turn the bicl into.
! 				 * However, if the CVT is from a float or
! 				 * double, forget it!
! 				 */
! 				subop = p->back->subop&0xF;/* type of LHS of
! 							      CVT/MOVZ */
! 				if (equstr(src,cp2) && okio(cp1)
! 				  && subop != FFLOAT && subop != DFLOAT
! 				  && subop != GFLOAT && subop != HFLOAT
! 				  && ((!indexa(cp1) && !autoid(cp1)) || lhssiz == subop)
  				  && 0<=(r=isreg(cp2)) && r<NUSE
***************
*** 810,812
  				  && 0<=(r=isreg(cp2)) && r<NUSE
! 				  && bitsize[p->back->subop&0xF]>=(pos+siz)
  				  && bitsize[p->back->subop>>4]>=(pos+siz)) {/* good CVT */

--- 840,842 -----
  				  && 0<=(r=isreg(cp2)) && r<NUSE
! 				  && bitsize[subop]>=(pos+siz)
  				  && bitsize[p->back->subop>>4]>=(pos+siz)) {/* good CVT */
***************
*** 818,821
  			splitrand(p); /* retrieve destination of BICL */
! 			if (siz==8 && pos==0) {
! 				p->combop = T(MOVZ,U(BYTE,LONG));
  				sprintf(line,"%s,%s",src,lastrand);

--- 848,851 -----
  			splitrand(p); /* retrieve destination of BICL */
! 			if ((siz==8 || siz == 16) && pos==0) {
! 				p->combop = T(MOVZ,U(lhssiz,LONG));
  				sprintf(line,"%s,%s",src,lastrand);
***************
*** 1363,1364
  	while (*p) if (*p++=='[') return(1);
  	return(0);

--- 1393,1402 -----
  	while (*p) if (*p++=='[') return(1);
+ 	return(0);
+ }
+ 
+ autoid(p) register char *p; {	/* 1-> uses autoincrement/autodecrement;
+ 				   0-> doesn't */
+ 	if (*p == '-' && *(p+1) == '(') return(1);
+ 	while (*p) p++;
+ 	if (*--p == '+' && *--p == ')') return(1);
  	return(0);
-- 
(This page accidently left blank.)

In-Real-Life: Chris Torek, Univ of MD Comp Sci (301) 454-7690
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

guy@rlgvax.UUCP (Guy Harris) (09/30/84)

> (Does this REALLY need to go to net.lang.c?  Oh well...)  Guy Harris
> posted a fix for this one long ago.  It seems that Berkeley never
> picked up the fix since the bug is still there in the 4.2BSD /lib/c2.
> Here's RCS diffs.  (Thanks, Guy.)

That diff listing actually includes about 3 bug fixes.  To be fair, the only
one that's actually mine is the one which keeps the optimizer from merging

	cvtwl	(r11)+,r0
	movzbl	r0,r0

into

	movzbl	(r11)+,r0

which sequence gets generated by code like

	register short *sp;
	register int c;

	c = (*sp++)&0377;

The other fixes are the one to the "extzv" instructions, and one that kept
the compiler from merging floating and non-floating convert instructions.

I'm told lots of other fixes posted to net.bugs.4bsd but not mailed to
4bsd-bugs@berkeley haven't been picked up by Berkeley yet.  These bugs exist
in the System III version of the optimizer as well, and some of them might
even still be around in System V Release 2.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy