[net.bugs.4bsd] C optimizer can generate incorrect code for "*p++ & 1"

kwlalonde@watmath.UUCP (Ken Lalonde) (04/11/86)

Index: 	lib/c2/c21.c 4.2BSD Fix

Description:
	The optimizer will replace a single bit AND operation
	followed by a jump with a jump-on-bit-set, that is,

		bitb power-of-2,x	=>	jbc log2(p2),x,Label
		jxx Label
	
	C2 also checks for the special case p2 == 1, and replaces

		jbc $0,x,Label	=>	jlbc x,Label
	
	Now, bitb and jbc consider "x" to be a byte quantity,
	but "jlbc" wants a longword.  If "x" involves autoincrement
	or autodecrement, the second optimization is wrong.

Repeat-By:
	Compile this with and without the optimizer:
	
	main()
	{
		register char *p = "01234";

		if (*p++ & 1)
			;
		if (*p != '1')
			printf("p = %c, should be 1\n", *p);
	}

Fix:
	Don't apply the jlbc replacement if autoincrement/decrement is
	used.  The autoid() function below is from a previous
	bug fix by chris@maryland.

*** /usr/distr/4.2/usr/src/lib/c2/c21.c	Tue Jun  8 23:59:06 1982
--- ./c21.c	Thu Apr 10 23:48:51 1986
***************
*** 740,746
  	if (cp1=p->forw->code) {/* destination is not an internal label */
  		cp2=regs[RT3]; while (*cp2++= *cp1++);
  	}
! 	if (b==0 && (p->subop==LONG || !indexa(regs[RT2]))) {/* JLB optimization, ala BLISS */
  		cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++);
  		cp2=regs[RT2]; cp1=regs[RT3]; while (*cp2++= *cp1++);
  		*(regs[RT3])=0; p->forw->subop += JLBC-JBC;

--- 744,750 -----
  	if (cp1=p->forw->code) {/* destination is not an internal label */
  		cp2=regs[RT3]; while (*cp2++= *cp1++);
  	}
! 	if (b==0 && (p->subop==LONG || !autoid(regs[RT2]) && !indexa(regs[RT2]))) {/* JLB optimization, ala BLISS */
  		cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++);
  		cp2=regs[RT2]; cp1=regs[RT3]; while (*cp2++= *cp1++);
  		*(regs[RT3])=0; p->forw->subop += JLBC-JBC;
***************
*** 1361,1366
  
  indexa(p) register char *p; {/* 1-> uses [r] addressing mode; 0->doesn't */
  	while (*p) if (*p++=='[') return(1);
  	return(0);
  }
  

--- 1392,1404 -----
  
  indexa(p) register char *p; {/* 1-> uses [r] addressing mode; 0->doesn't */
  	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);
  }