Subject: /lib/c2 bug fixes plus enhancements
Index:	lib/c2/all 2.11BSD

Description:
	The optimizer (/lib/c2) has several bugs and missed several
	chances to replace code segments with shorter sequences:

	1) running as a filter causes a core dump because the 'setbuf'
	   statements were misplaced.

	2) the 'div' instruction was missing from the opcode table even
	   though the instruction was checked for in rmove().  the check
	   for 'DIV' also used " + 1" instead of " | 1" when marking
	   the second (odd) register as changed.

	3) local and register variable assignments (lines starting
	   with ~ as in "~fs=r4" caused c2 to throw away information
	   about register contents.

	4) extracting the high byte of a word (the major() macro for example)
	   generated a "ash $-10,R; bic $-400,R" which should become 
	   "clrb R; swab R".  a 'clrb' is much faster (as well as shorter) 
	   than the "ash $-10".

	5) extracting the low byte of a word generated "mov X,R; bic $-400,R"
	   which should have been transformed into "clr R; bisb X,R".

	6) the 'changed' flag wasn't set in several places where code
	   was removed/altered.

Repeat-By:
	Examine the generated code from the earlier versions as well as
	looking over the c2 sources.

Fix:
	Apply the patch below, recompile and install /lib/c2

---------------------------------------------------------------------------
*** /usr/src/lib/c2/c20.c.old	Tue Oct 21 01:23:50 1986
--- /usr/src/lib/c2/c20.c	Tue Oct 29 17:09:09 1991
***************
*** 37,42 ****
--- 37,43 ----
  	"bic",	BIC,
  	"bis",	BIS,
  	"mul",	MUL,
+ 	"div",	DIV,
  	"ash",	ASH,
  	"xor",	XOR,
  	".text",TEXT,
***************
*** 57,62 ****
--- 58,64 ----
  	"cfcc",	CFCC,
  	"sob",	SOB,
  	"jsr",	JSR,
+ 	"swab",	SWAB,
  	".end",	END,
  	0,	0};
  
***************
*** 92,106 ****
  			fprintf(stderr, "C2: can't find %s\n", argv[1]);
  			exit(1);
  		}
- 		setbuf(stdin,buf1);		/* sbrk problems */
  	}
  	if (argc>2) {
  		if (freopen(argv[2], "w", stdout) == NULL) {
  			fprintf(stderr, "C2: can't create %s\n", argv[2]);
  			exit(1);
  		}
- 		setbuf(stdout,buf2);		/* sbrk problems */
  	}
  	lasta = firstr = lastr = sbrk(sizeof(char *));
  	maxiter = 0;
  	opsetup();
--- 94,108 ----
  			fprintf(stderr, "C2: can't find %s\n", argv[1]);
  			exit(1);
  		}
  	}
+ 	setbuf(stdin,buf1);		/* sbrk problems */
  	if (argc>2) {
  		if (freopen(argv[2], "w", stdout) == NULL) {
  			fprintf(stderr, "C2: can't create %s\n", argv[2]);
  			exit(1);
  		}
  	}
+ 	setbuf(stdout,buf2);		/* sbrk problems */
  	lasta = firstr = lastr = sbrk(sizeof(char *));
  	maxiter = 0;
  	opsetup();
*** /usr/src/lib/c2/c21.c.old	Sun Oct 20 16:15:12 1991
--- /usr/src/lib/c2/c21.c	Sat Nov  2 19:42:32 1991
***************
*** 31,36 ****
--- 31,37 ----
  				p->forw->back = p->back;
  				p->back->forw = p->forw;
  				redunm++;
+ 				nchange++;
  				continue;
  			}
  		}
***************
*** 39,44 ****
--- 40,46 ----
  			strcpy(regs[RT1], regs[RT2]);
  			regs[RT2][0] = 0;
  			p->code = copy(1, regs[RT1]);
+ 			nchange++;
  			goto sngl;
  		}
  		repladdr(p, 0, flt);
***************
*** 80,85 ****
--- 82,88 ----
  			strcpy(regs[RT1], regs[RT2]);
  			regs[RT2][0] = 0;
  			p->code = copy(1, regs[RT1]);
+ 			nchange++;
  			goto sngl;
  		}
  		if ((p->op==BIC || p->op==BIS) && equstr(regs[RT1], "$0")) {
***************
*** 86,99 ****
  			if (p->forw->op!=CBR) {
  				p->back->forw = p->forw;
  				p->forw->back = p->back;
  				continue;
  			}
  		}
  		repladdr(p, 0, flt);
  		source(regs[RT1]);
  		dest(regs[RT2], flt);
! 		if (p->op==DIV && (r = isreg(regs[RT2])>=0))
! 			regs[r+1][0] = 0;
  		switch	(p->op)
  			{
  			case	ADD:
--- 89,163 ----
  			if (p->forw->op!=CBR) {
  				p->back->forw = p->forw;
  				p->forw->back = p->back;
+ 				nchange++;
  				continue;
  			}
  		}
+ /*
+  * the next block of code looks for the sequences (which extract the
+  * high byte of a word or the low byte respectively):
+  *	ash $-10,r
+  *	bic $-400,r
+  * or 
+  *	mov natural,r
+  *	bic $-400,r
+  * and transforms them into:
+  *	clrb r
+  *	swab r
+  * or
+  *	clr r
+  *	bisb natural,r
+  * These constructs occur often enough in the kernel (dealing with major/minor 
+  * device numbers, etc) it's worth a little extra work at compile time.
+ */
+ 		if (p->op == BIC && (equstr(regs[RT1],"$-400") || 
+ 			 equstr(regs[RT1],"$-177400"))) {
+ 			if (p->back->op == ASH) {
+ 				r = isreg(regs[RT2]);
+ 				dualop(p->back);
+ 				if ((equstr(regs[RT1], "$-10") || 
+ 				     equstr(regs[RT1], "$177770")) && 
+ 				    r == isreg(regs[RT2])) {
+ 					strcpy(regs[RT1], regs[RT2]);
+ 					regs[RT2][0] = 0;
+ 					p->back->op = CLR;
+ 					p->back->subop = BYTE;
+ 					p->back->code = copy(1, regs[RT1]);
+ 					p->op = SWAB;
+ 					p->code = copy(1, regs[RT1]);
+ 					nchange++;
+ 					goto sngl;
+ 				}
+ 			}
+ 			else if (p->back->op == MOV && p->forw->op != CBR) {
+ 				char temp[50];
+ 
+ 				r = isreg(regs[RT2]);
+ 				if (r < 0 && !xnatural(regs[RT2]))
+ 					goto out;
+ 				strcpy(temp, regs[RT2]);
+ 				dualop(p->back);
+ 				if (isreg(regs[RT2]) == r && natural(regs[RT1])) {
+ 			 	    if (r < 0 && (!xnatural(regs[RT2]) || !equstr(temp, regs[RT2])))
+ 					goto out;
+ 				    dest(regs[RT1], flt);
+ 				    p->back->op = CLR;
+ 				    p->back->subop = 0;
+ 				    p->back->code = copy(1, regs[RT2]);
+ 				    p->op = BIS;
+ 				    p->subop = BYTE;
+ 				    strcat(regs[RT1], ",");
+ 				    p->code = copy(2, regs[RT1], regs[RT2]);
+ 				    nchange++;
+ 				}
+ 			}
+ out:		dualop(p);	/* restore banged up parsed operands */
+ 		}
  		repladdr(p, 0, flt);
  		source(regs[RT1]);
  		dest(regs[RT2], flt);
! 		if (p->op==DIV && (r = isreg(regs[RT2]))>=0)
! 			regs[r|1][0] = 0;
  		switch	(p->op)
  			{
  			case	ADD:
***************
*** 120,125 ****
--- 184,190 ----
  	case ASR:
  	case ASL:
  	case SXT:
+ 	case SWAB:
  		singop(p);
  	sngl:
  		dest(regs[RT1], flt);
***************
*** 253,258 ****
--- 318,334 ----
  		ccloc[0] = 0;
  		continue;
  
+ /*
+  * Unrecognized (unparsed) instructions, assignments (~foo=r2), and
+  * data arrive here.  In order to prevent throwing away information
+  * about register contents just because a local assignment is done
+  * we check for the first character being a tilde.
+ */
+ 	case 0:
+ 		if (p->code[0] != '~')
+ 			clearreg();
+ 		continue;
+ 
  	case JBR:
  		redunbr(p);
  
***************
*** 676,681 ****
--- 752,758 ----
  			rt1[1] = r + '0';
  			rt1[2] = 0;
  			nsaddr++;
+ 			nchange++;
  		}
  		if (r1>=0) {
  			rt2[1] = 'r';
***************
*** 682,687 ****
--- 759,765 ----
  			rt2[2] = r1 + '0';
  			rt2[3] = 0;
  			nsaddr++;
+ 			nchange++;
  		}
  		p->code = copy(2, rt1, rt2);
  	}
***************
*** 907,910 ****
--- 985,996 ----
  	if (*--p == '+' || *p ==')' && *--p != '5')
  		return(0);
  	return(1);
+ }
+ 
+ xnatural(ap)
+ 	char *ap;
+ {
+ 	if (natural(ap))
+ 		return(1);
+ 	return(equstr("(sp)", ap));
  }
*** /usr/src/lib/c2/c2.h.old	Tue Oct 21 01:23:50 1986
--- /usr/src/lib/c2/c2.h	Tue Oct 29 17:08:45 1991
***************
*** 53,59 ****
  #define	CFCC	45
  #define	SOB	46
  #define	JSR	47
! #define	END	48
  
  #define	JEQ	0
  #define	JNE	1
--- 53,60 ----
  #define	CFCC	45
  #define	SOB	46
  #define	JSR	47
! #define	SWAB	48
! #define	END	49
  
  #define	JEQ	0
  #define	JNE	1
