Subject: bug was introduced in '/lib/c2' a while back
Index:	lib/c2/c21.c 2.11BSD

Description:
	A bug was introduced in the optimizer a while back.  The sequence

		movb	X,rN
		bic	$177400,rN

	was always being transformed into

		clr	rN
		bisb	X,rN

	this is not the correct thing to do when 'X' is the same as 'rN':

		movb	r0,r0
		bic	$177400,r0

	was being turned into:

		clr	r0
		bisb	r0,r0

	which is obviously not correct.  In the case where 'X' is the same
	as 'rN' the optimization should be to remove the 'movb' instruction
	and leave the 'bic' instruction.

	Another pair of optimizations was seen recently.  The sequence

		sxt	X
		clr	X

	is silly, the 'sxt' is not needed since the operand is cleared in
	the very next instruction.

	A fairly common sequence arising from calling a function with two
	arguments and then testing the return value was noticed recently:

	The C code:

			if	(foo(a,b) == 0) 
				...

	generates the following:

			mov	b,(sp)
			mov	a,-(sp)
			jsr	pc,foo
			tst	(sp)+
			tst	r0
			beq	...

	Since the 'tst' instruction clears the C and V bits the branch which
	follows will never rely on those being set.  The two 'tst' statements
	can be combined into a single 'mov' instruction which sets the N and
	Z condition codes and saves 1 instruction at the same time:L

			mov	b,(sp)
			mov	a,-(sp)
			jsr	pc,foo
			mov	r0,(sp)+
			beq	...

	(in case you're interested this saved 256 bytes of text space in
	the kernel)

Repeat-By:
	The 'movb r0,r0' bug was noticed when the 'tcsh' was compiled,
	the bracket9('[ ... ]') construct was causing a core dump in the
	pattern matching sequence.

	Run /lib/c2 interactively and type the two lines

			movb	r0,r0
			bic	$-400,r0
			^D

	to observe the problem.

Fix:
	Apply the following patch, compile and reinstall 'c2'.
------------------------------------------------------------------------------
*** /usr/src/lib/c2/c21.c.old	Sun Dec 29 22:02:02 1991
--- /usr/src/lib/c2/c21.c	Mon Feb  3 10:59:37 1992
***************
*** 140,145 ****
--- 140,157 ----
  				if (isreg(regs[RT2]) == r && natural(regs[RT1])) {
  			 	    if (r < 0 && (!xnatural(regs[RT2]) || !equstr(temp, regs[RT2])))
  					goto out;
+ /*
+  * XXX - the sequence "movb rN,rN; bic $-400,rN" can not be transformed
+  * because the 'clr' would lose all information about 'rN'.  The best that can 
+  * be done is to remove the 'movb' instruction and leave the 'bic'.
+ */
+ 				    if (isreg(regs[RT1]) == r) {
+ 					    p = p->back;
+ 					    p->forw->back = p->back;
+ 					    p->back->forw = p->forw;
+ 					    nchange++;
+ 					    continue;
+ 				    }
  				    dest(regs[RT1], flt);
  				    p->back->op = CLR;
  				    p->back->subop = 0;
***************
*** 172,177 ****
--- 184,199 ----
  			}
  		continue;
  
+ 	case SXT:
+ 		singop(p);
+ 		if (p->forw->op == CLR && p->forw->subop != BYTE &&
+ 			xnatural(regs[RT1]) && !strcmp(p->code, p->forw->code)){
+ 			p->forw->back = p->back;
+ 			p->back->forw = p->forw;
+ 			nchange++;
+ 			continue;
+ 		}
+ 		goto sngl;
  	case CLRF:
  	case NEGF:
  		flt = NREG;
***************
*** 183,189 ****
  	case NEG:
  	case ASR:
  	case ASL:
- 	case SXT:
  	case SWAB:
  		singop(p);
  	sngl:
--- 205,210 ----
***************
*** 207,212 ****
--- 228,250 ----
  		singop(p);
  		repladdr(p, 0, flt);
  		source(regs[RT1]);
+ 		if (p->back->op == TST && !flt && not_sp(regs[RT1])) {
+ 			char rt1[20];
+ 			strcpy(rt1, regs[RT1]);
+ 			singop(p->back);
+ 			if (!strcmp("(sp)+", regs[RT1])) {
+ 				p->back->subop = p->subop;
+ 				p->back->forw = p->forw;
+ 				p->forw->back = p->back;
+ 				p = p->back;
+ 				p->op = MOV;
+ 				p->code = copy(2, rt1, ",(sp)+");
+ 				nrtst++;
+ 				nchange++;
+ 				continue;
+ 			}
+ 		singop(p);
+ 		}
  		if (p->back->op == MOV && p->back->subop == BYTE) {
  			dualop(p->back);
  			setcc(regs[RT2]);
***************
*** 998,1001 ****
--- 1036,1049 ----
  	if (natural(ap))
  		return(1);
  	return(equstr("(sp)", ap));
+ }
+ 
+ not_sp(ap)
+ 	register char *ap;
+ {
+ 	char c;
+ 
+ 	while (c = *ap++)
+ 		if (c == '(') return(*ap == 's' && ap[1] == 'p');
+ 	return(1);
  }
