[net.bugs.4bsd] VAX-11 "pcc" can over-optimize

guy (02/15/83)

References: rlgvax.1025

James T. Ellis of the Microelectronics Center of North Carolina submitted a
bug in the VAX-11 "c2" a few months back.  He mentioned it to me; it turns
out it is related to the other problems in "c2" I mentioned in net.bugs.4bsd
and net.bugs.usg.  The original submission included the following:

The 4.1bsd C optimizer breaks when float-to-int conversions are
combined with bit masks. The following program
	main(){
		printf("%d %d\n", (short)(3.4), ( (short)(3.4) ) & 077);
	}
prints "3 25" instead of "3 3".

The compiler constructs a convert/bitmask series of instructions
	cvtdl	L19,r0
	bicl2	$-64,r0
for the latter expression. The optimizer first changes the BIC into an EXT
	cvtdl	L19,r0
	extzv	$0,$6,r0,r0
(anyone know why?). It then thinks that the EXTZV is doing a conversion
to a long already, so it deletes the CVT! This is fine when converting
from a byte or short to a long, but fails on floating point.
	extzv	$0,$6,L19,r0
L19 is masked directly, and the resulting garbage used.

The optimizer turns the BIC into an EXT because the "bicopt" routine is trying
to convert ALL explicit shift and mask operations it finds into MOVZx or EXTZV
instructions (so that even code which doesn't use bit fields can compile into
bit-field instructions).  However, it isn't paying enough attention to the
"left-hand sides" instructions being converted.  The following is an update
to the fix I submitted previously.  It replaces both the first and the second
parts of that fix; since it includes the second part, which has not been
exhaustively tested on our machine, caveat programmator.

----------------- Changes to /usr/src/cmd/c2/c21.c -----------------------------

After line 774, add:

	char lhssiz, subop;

After line 790, add:

			/*
			 * '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 */

Change line 793 from:

				if (equstr(src,cp2) && okio(cp1) && !indexa(cp1)

to:

				/*
				 * 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 != FLOAT && subop != DOUBLE
				  && ((!indexa(cp1) && !autoid(cp1)) || lhssiz == subop)

Change lines 803 and 804 from:

			if (siz==8 && pos==0) {
				p->combop = T(MOVZ,U(BYTE,LONG));

to:

			if ((siz==8 || siz==16) && pos==0) {
				p->combop = T(MOVZ,U(lhssiz,LONG));

After line 1324, add:

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);
}

----------------------- End of changes -----------------------------------------

					Guy Harris
					RLG Corporation
				(...!decvax!duke!mcnc!rlgvax!guy)