[net.lang.c] 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