From e081f25c3e602804fc3bd0780e09bf35d2a098cb Mon Sep 17 00:00:00 2001
From: Ken Thompson <ken@golang.org>
Date: Sat, 22 Nov 2008 17:58:53 -0800
Subject: [PATCH] reg and peep

R=r
OCL=19871
CL=19871
---
 src/cmd/6g/cgen.c  |   8 +-
 src/cmd/6g/gen.c   |  36 ++++++++-
 src/cmd/6g/gsubr.c | 152 +++++++++++++++++++++++--------------
 src/cmd/6g/opt.h   |  25 ++++---
 src/cmd/6g/peep.c  |  30 ++++++--
 src/cmd/6g/reg.c   | 181 +++++++++++++++++++++++++++++++--------------
 src/cmd/gc/go.h    |   1 +
 src/cmd/gc/walk.c  |  15 +++-
 8 files changed, 312 insertions(+), 136 deletions(-)

diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index 4fb9e3415d..d6f27a9296 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -176,12 +176,14 @@ cgen(Node *n, Node *res)
 			gins(optoas(OCMP, types[tptr]), &n1, &n2);
 			p1 = gbranch(optoas(OEQ, types[tptr]), T);
 
-			n1.op = OINDREG;
-			n1.type = types[TINT32];
-			gmove(&n1, res);
+			n2 = n1;
+			n2.op = OINDREG;
+			n2.type = types[TINT32];
+			gmove(&n2, &n1);
 
 			patch(p1, pc);
 
+			gmove(&n1, res);
 			regfree(&n1);
 			break;
 		}
diff --git a/src/cmd/6g/gen.c b/src/cmd/6g/gen.c
index 4851f5ad9c..3d47360be8 100644
--- a/src/cmd/6g/gen.c
+++ b/src/cmd/6g/gen.c
@@ -100,9 +100,8 @@ if(throwreturn == N) {
 	pc->as = ARET;	// overwrite AEND
 	pc->lineno = lineno;
 
-	if(debug['N']) {
+	if(!debug['N'] || debug['R'] || debug['P'])
 		regopt(ptxt);
-	}
 
 	// fill in argument size
 	ptxt->to.offset = rnd(curfn->type->argwid, maxround);
@@ -918,6 +917,33 @@ cgen_asop(Node *n)
 	nl = n->left;
 	nr = n->right;
 
+	if(nl->addable && nr->op == OLITERAL)
+	switch(n->etype) {
+	case OADD:
+		if(!isint[nl->type->etype])
+			goto com;
+		if(mpgetfix(nr->val.u.xval) != 1)
+			goto com;
+		gins(optoas(OINC, nl->type), N, nl);
+		goto ret;
+	case OSUB:
+		if(!isint[nl->type->etype])
+			goto com;
+		if(mpgetfix(nr->val.u.xval) != 1)
+			goto com;
+		gins(optoas(ODEC, nl->type), N, nl);
+		goto ret;
+
+	com:
+	case OXOR:
+	case OAND:
+	case OOR:
+		if(!isint[nl->type->etype])
+			break;
+		gins(optoas(n->etype, nl->type), nr, nl);
+		goto ret;
+	}
+
 	if(nr->ullman >= UINF && nl->ullman >= UINF) {
 		tempname(&n1, nr->type);
 		cgen(nr, &n1);
@@ -960,10 +986,12 @@ cgen_as(Node *nl, Node *nr, int op)
 	Node nc, n1;
 	Type *tl;
 	uint32 w, c;
+	int iszer;
 
 	if(nl == N)
 		return;
 
+	iszer = 0;
 	if(nr == N || isnil(nr)) {
 		if(nl->op == OLIST) {
 			cgen_as(nl->left, nr, op);
@@ -1008,6 +1036,7 @@ cgen_as(Node *nl, Node *nr, int op)
 		}
 
 		/* invent a "zero" for the rhs */
+		iszer = 1;
 		nr = &nc;
 		memset(nr, 0, sizeof(*nr));
 		switch(tl->etype) {
@@ -1062,6 +1091,9 @@ cgen_as(Node *nl, Node *nr, int op)
 		return;
 
 	cgen(nr, nl);
+	if(iszer && nl->addable)
+		gins(ANOP, nl, N);	// used
+		
 
 ret:
 	;
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 62e986a169..273e10f873 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -383,7 +383,7 @@ gmove(Node *f, Node *t)
 	case TPTR32:
 		a = AMOVL;
 		if(t64)
-			a = AMOVLQZX;	/* could probably use plain MOVL */
+			a = AMOVLQZX;
 		goto ld;
 	case TINT64:
 		if(isfloat[tt]) {
@@ -480,50 +480,50 @@ gmove(Node *f, Node *t)
 /*
  * integer to integer
  ********
-		a = AGOK;	break;
-
-	case CASE(TBOOL, TBOOL):
-	case CASE(TINT8, TBOOL):
-	case CASE(TUINT8, TBOOL):
-	case CASE(TINT16, TBOOL):
-	case CASE(TUINT16, TBOOL):
-	case CASE(TINT32, TBOOL):
-	case CASE(TUINT32, TBOOL):
-	case CASE(TPTR64, TBOOL):
-
-	case CASE(TBOOL, TINT8):
-	case CASE(TINT8, TINT8):
-	case CASE(TUINT8, TINT8):
-	case CASE(TINT16, TINT8):
-	case CASE(TUINT16, TINT8):
-	case CASE(TINT32, TINT8):
-	case CASE(TUINT32, TINT8):
-	case CASE(TPTR64, TINT8):
-
-	case CASE(TBOOL, TUINT8):
-	case CASE(TINT8, TUINT8):
-	case CASE(TUINT8, TUINT8):
-	case CASE(TINT16, TUINT8):
-	case CASE(TUINT16, TUINT8):
-	case CASE(TINT32, TUINT8):
-	case CASE(TUINT32, TUINT8):
-	case CASE(TPTR64, TUINT8):
-
-	case CASE(TINT16, TINT16):
-	case CASE(TUINT16, TINT16):
-	case CASE(TINT32, TINT16):
-	case CASE(TUINT32, TINT16):
-	case CASE(TPTR64, TINT16):
-
-	case CASE(TINT16, TUINT16):
-	case CASE(TUINT16, TUINT16):
-	case CASE(TINT32, TUINT16):
-	case CASE(TUINT32, TUINT16):
-	case CASE(TPTR64, TUINT16):
-
-	case CASE(TINT64, TUINT):
-	case CASE(TINT64, TUINT32):
-	case CASE(TUINT64, TUINT32):
+ *		a = AGOK;	break;
+
+ *	case CASE(TBOOL, TBOOL):
+ *	case CASE(TINT8, TBOOL):
+ *	case CASE(TUINT8, TBOOL):
+ *	case CASE(TINT16, TBOOL):
+ *	case CASE(TUINT16, TBOOL):
+ *	case CASE(TINT32, TBOOL):
+ *	case CASE(TUINT32, TBOOL):
+ *	case CASE(TPTR64, TBOOL):
+
+ *	case CASE(TBOOL, TINT8):
+ *	case CASE(TINT8, TINT8):
+ *	case CASE(TUINT8, TINT8):
+ *	case CASE(TINT16, TINT8):
+ *	case CASE(TUINT16, TINT8):
+ *	case CASE(TINT32, TINT8):
+ *	case CASE(TUINT32, TINT8):
+ *	case CASE(TPTR64, TINT8):
+
+ *	case CASE(TBOOL, TUINT8):
+ *	case CASE(TINT8, TUINT8):
+ *	case CASE(TUINT8, TUINT8):
+ *	case CASE(TINT16, TUINT8):
+ *	case CASE(TUINT16, TUINT8):
+ *	case CASE(TINT32, TUINT8):
+ *	case CASE(TUINT32, TUINT8):
+ *	case CASE(TPTR64, TUINT8):
+
+ *	case CASE(TINT16, TINT16):
+ *	case CASE(TUINT16, TINT16):
+ *	case CASE(TINT32, TINT16):
+ *	case CASE(TUINT32, TINT16):
+ *	case CASE(TPTR64, TINT16):
+
+ *	case CASE(TINT16, TUINT16):
+ *	case CASE(TUINT16, TUINT16):
+ *	case CASE(TINT32, TUINT16):
+ *	case CASE(TUINT32, TUINT16):
+ *	case CASE(TPTR64, TUINT16):
+
+ *	case CASE(TINT64, TUINT):
+ *	case CASE(TINT64, TUINT32):
+ *	case CASE(TUINT64, TUINT32):
  *****/
 		a = AMOVL;
 		break;
@@ -534,25 +534,21 @@ gmove(Node *f, Node *t)
 	case CASE(TUINT64, TINT8):
 	case CASE(TUINT64, TINT16):
 	case CASE(TUINT64, TINT32):
+		a = AMOVLQSX;		// this looks bad
+		break;
+
 	case CASE(TINT32, TINT64):
 	case CASE(TINT32, TPTR64):
 		a = AMOVLQSX;
-//		if(f->op == OCONST) {
-//			f->val.vval &= (uvlong)0xffffffffU;
-//			if(f->val.vval & 0x80000000)
-//				f->val.vval |= (vlong)0xffffffff << 32;
-//			a = AMOVQ;
-//		}
 		break;
 
 	case CASE(TUINT32, TINT64):
 	case CASE(TUINT32, TUINT64):
 	case CASE(TUINT32, TPTR64):
-		a = AMOVL;	/* same effect as AMOVLQZX */
-//		if(f->op == OCONST) {
-//			f->val.vval &= (uvlong)0xffffffffU;
-//			a = AMOVQ;
-//		}
+	case CASE(TPTR32, TINT64):
+	case CASE(TPTR32, TUINT64):
+	case CASE(TPTR32, TPTR64):
+		a = AMOVLQZX;
 		break;
 
 	case CASE(TPTR64, TINT64):
@@ -1239,6 +1235,50 @@ optoas(int op, Type *t)
 		a = ASUBSD;
 		break;
 
+	case CASE(OINC, TINT8):
+	case CASE(OINC, TUINT8):
+		a = AINCB;
+		break;
+
+	case CASE(OINC, TINT16):
+	case CASE(OINC, TUINT16):
+		a = AINCW;
+		break;
+
+	case CASE(OINC, TINT32):
+	case CASE(OINC, TUINT32):
+	case CASE(OINC, TPTR32):
+		a = AINCL;
+		break;
+
+	case CASE(OINC, TINT64):
+	case CASE(OINC, TUINT64):
+	case CASE(OINC, TPTR64):
+		a = AINCQ;
+		break;
+
+	case CASE(ODEC, TINT8):
+	case CASE(ODEC, TUINT8):
+		a = ADECB;
+		break;
+
+	case CASE(ODEC, TINT16):
+	case CASE(ODEC, TUINT16):
+		a = ADECW;
+		break;
+
+	case CASE(ODEC, TINT32):
+	case CASE(ODEC, TUINT32):
+	case CASE(ODEC, TPTR32):
+		a = ADECL;
+		break;
+
+	case CASE(ODEC, TINT64):
+	case CASE(ODEC, TUINT64):
+	case CASE(ODEC, TPTR64):
+		a = ADECQ;
+		break;
+
 	case CASE(OMINUS, TINT8):
 	case CASE(OMINUS, TUINT8):
 		a = ANEGB;
diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h
index a73e45ffc7..571bcd6cb7 100644
--- a/src/cmd/6g/opt.h
+++ b/src/cmd/6g/opt.h
@@ -60,7 +60,6 @@ struct	Bits
 	uint32	b[BITS];
 };
 
-
 struct	Reg
 {
 
@@ -75,14 +74,12 @@ struct	Reg
 	Bits	regdiff;
 	Bits	act;
 
-	int32	regu;
-	int32	loop;		/* could be shorter */
-	int32	rpo;		/* reverse post ordering */
+	int32	regu;		// register used bitmap
+	int32	rpo;		// reverse post ordering
 	int32	active;
 
-//	uint32	magic;
-//	int32	pc;
-//	Reg*	log5;
+	uint16	loop;		// x5 for every loop
+	uchar	refset;		// diagnostic generated
 
 	Reg*	p1;
 	Reg*	p2;
@@ -130,10 +127,9 @@ EXTERN	Bits	externs;
 EXTERN	Bits	params;
 EXTERN	Bits	consts;
 EXTERN	Bits	addrs;
+EXTERN	Bits	ovar;
 EXTERN	int	change;
 EXTERN	Bits	zbits;
-EXTERN	uchar	typechlpfd[NTYPE];	// botch
-EXTERN	uchar	typev[NTYPE];		// botch
 EXTERN	int32	maxnr;
 EXTERN	int32*	idom;
 
@@ -150,6 +146,15 @@ int	beq(Bits, Bits);
 int	bset(Bits, uint);
 int	Qconv(Fmt *fp);
 int	bitno(int32);
+struct
+{
+	int32	ncvtreg;
+	int32	nspill;
+	int32	nreload;
+	int32	ndelmov;
+	int32	nvar;
+	int32	naddr;
+} ostats;
 
 /*
  * reg.c
@@ -167,6 +172,8 @@ void	paint1(Reg*, int);
 uint32	paint2(Reg*, int);
 void	paint3(Reg*, int, int32, int);
 void	addreg(Adr*, int);
+void	dumpit(char *str, Reg *r0);
+int	noreturn(Prog *p);
 
 /*
  * peep.c
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
index b85e88d158..cdf8a8bc35 100644
--- a/src/cmd/6g/peep.c
+++ b/src/cmd/6g/peep.c
@@ -31,6 +31,7 @@
 #include "gg.h"
 #include "opt.h"
 
+
 static int
 needc(Prog *p)
 {
@@ -67,7 +68,7 @@ rnops(Reg *r)
 	Reg *r1;
 
 	if(r != R)
-	for(;;){
+	for(;;) {
 		p = r->prog;
 		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
 			break;
@@ -103,6 +104,8 @@ peep(void)
 			r2->link = r1;
 
 			r2->prog = p;
+			p->reg = r2;
+
 			r2->p1 = r;
 			r->s1 = r2;
 			r2->s1 = r1;
@@ -119,10 +122,11 @@ peep(void)
 		}
 	}
 
-	pc = 0;	/* speculating it won't kill */
-
 loop1:
 
+	if(debug['P'] && debug['v'])
+		dumpit("loop1", firstr);
+
 	t = 0;
 	for(r=firstr; r!=R; r=r->link) {
 		p = r->prog;
@@ -186,13 +190,15 @@ loop1:
 			if(p->from.offset == -1){
 				if(p->as == AADDQ)
 					p->as = ADECQ;
-				else if(p->as == AADDL)
+				else
+				if(p->as == AADDL)
 					p->as = ADECL;
 				else
 					p->as = ADECW;
 				p->from = zprog.from;
 			}
-			else if(p->from.offset == 1){
+			else
+			if(p->from.offset == 1){
 				if(p->as == AADDQ)
 					p->as = AINCQ;
 				else if(p->as == AADDL)
@@ -211,16 +217,19 @@ loop1:
 			if(p->from.offset == -1) {
 				if(p->as == ASUBQ)
 					p->as = AINCQ;
-				else if(p->as == ASUBL)
+				else
+				if(p->as == ASUBL)
 					p->as = AINCL;
 				else
 					p->as = AINCW;
 				p->from = zprog.from;
 			}
-			else if(p->from.offset == 1){
+			else
+			if(p->from.offset == 1){
 				if(p->as == ASUBQ)
 					p->as = ADECQ;
-				else if(p->as == ASUBL)
+				else
+				if(p->as == ASUBL)
 					p->as = ADECL;
 				else
 					p->as = ADECW;
@@ -239,9 +248,14 @@ excise(Reg *r)
 	Prog *p;
 
 	p = r->prog;
+	if(debug['P'] && debug['v'])
+		print("%P ===delete===\n", p);
+
 	p->as = ANOP;
 	p->from = zprog.from;
 	p->to = zprog.to;
+
+	ostats.ndelmov++;
 }
 
 Reg*
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 3e319919db..0715faa097 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -34,11 +34,8 @@
 #include "opt.h"
 
 #define	P2R(p)	(Reg*)(p->reg)
-#define	MAGIC	0xb00fbabe
 
 static	int	first	= 1;
-static	void	dumpit(char *str, Reg *r0);
-static	int	noreturn(Prog *p);
 
 Reg*
 rega(void)
@@ -70,6 +67,30 @@ rcmp(const void *a1, const void *a2)
 	return p2->varno - p1->varno;
 }
 
+void
+setoutvar(void)
+{
+	Type *t;
+	Node *n;
+	Addr a;
+	Iter save;
+	Bits bit;
+	int z;
+
+	t = structfirst(&save, getoutarg(curfn->type));
+	while(t != T) {
+		n = nodarg(t, 1);
+		a = zprog.from;
+		naddr(n, &a);
+		bit = mkvar(R, &a);
+		for(z=0; z<BITS; z++)
+			ovar.b[z] |= bit.b[z];
+		t = structnext(&save);
+	}
+//if(bany(b))
+//print("ovars = %Q\n", &ovar);
+}
+
 void
 regopt(Prog *firstp)
 {
@@ -93,8 +114,12 @@ regopt(Prog *firstp)
 		params.b[z] = 0;
 		consts.b[z] = 0;
 		addrs.b[z] = 0;
+		ovar.b[z] = 0;
 	}
 
+	// build list of return variables
+	setoutvar();
+
 	/*
 	 * pass 1
 	 * build aux data structure
@@ -221,6 +246,15 @@ regopt(Prog *firstp)
 		/*
 		 * right side read+write
 		 */
+		case AINCB:
+		case AINCL:
+		case AINCQ:
+		case AINCW:
+		case ADECB:
+		case ADECL:
+		case ADECQ:
+		case ADECW:
+
 		case AADDB:
 		case AADDL:
 		case AADDQ:
@@ -380,7 +414,9 @@ regopt(Prog *firstp)
 	}
 	if(firstr == R)
 		return;
-//dumpit("pass1", firstr);
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass1", firstr);
 
 	/*
 	 * pass 2
@@ -396,7 +432,7 @@ regopt(Prog *firstp)
 			if(r1 == R)
 				fatal("rnil %P", p);
 			if(r1 == r) {
-				fatal("ref to self %P", p);
+				//fatal("ref to self %P", p);
 				continue;
 			}
 			r->s2 = r1;
@@ -404,7 +440,9 @@ regopt(Prog *firstp)
 			r1->p2 = r;
 		}
 	}
-//dumpit("pass2", firstr);
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass2", firstr);
 
 	/*
 	 * pass 2.5
@@ -414,7 +452,9 @@ regopt(Prog *firstp)
 		r->active = 0;
 	change = 0;
 	loopit(firstr, nr);
-//dumpit("pass2.5", firstr);
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass2.5", firstr);
 
 	/*
 	 * pass 3
@@ -443,7 +483,8 @@ loop11:
 	if(change)
 		goto loop1;
 
-//dumpit("pass3", firstr);
+	if(debug['R'] && debug['v'])
+		dumpit("pass3", firstr);
 
 	/*
 	 * pass 4
@@ -458,7 +499,8 @@ loop2:
 	if(change)
 		goto loop2;
 
-//dumpit("pass4", firstr);
+	if(debug['R'] && debug['v'])
+		dumpit("pass4", firstr);
 
 	/*
 	 * pass 5
@@ -470,10 +512,11 @@ loop2:
 		for(z=0; z<BITS; z++)
 			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
 			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
-		if(bany(&bit)) {
-			warn("used and not set: %Q", bit);
-			if(debug['R'] && !debug['w'])
-				print("used and not set: %Q\n", bit);
+		if(bany(&bit) && !r->refset) {
+			// should never happen - all variables are preset
+			if(debug['w'])
+				print("%L: used and not set: %Q\n", r->prog->lineno, bit);
+			r->refset = 1;
 		}
 	}
 	for(r = firstr; r != R; r = r->link)
@@ -484,10 +527,10 @@ loop2:
 		for(z=0; z<BITS; z++)
 			bit.b[z] = r->set.b[z] &
 			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
-		if(bany(&bit)) {
-			warn("set and not used: %Q", bit);
-			if(debug['R'])
-				print("set and not used: %Q\n", bit);
+		if(bany(&bit) && !r->refset) {
+			if(debug['w'])
+				print("%L: set and not used: %Q\n", r->prog->lineno, bit);
+			r->refset = 1;
 			excise(r);
 		}
 		for(z=0; z<BITS; z++)
@@ -497,20 +540,15 @@ loop2:
 			rgp->enter = r;
 			rgp->varno = i;
 			change = 0;
-			if(debug['R'] && debug['v'])
-				print("\n");
 			paint1(r, i);
 			bit.b[i/32] &= ~(1L<<(i%32));
-			if(change <= 0) {
-				if(debug['R'])
-					print("%L$%d: %Q\n",
-						r->prog->lineno, change, blsh(i));
+			if(change <= 0)
 				continue;
-			}
 			rgp->cost = change;
 			nregion++;
 			if(nregion >= NRGN) {
-				fatal("too many regions");
+				if(debug['R'] && debug['v'])
+					print("too many regions\n");
 				goto brk;
 			}
 			rgp++;
@@ -534,11 +572,14 @@ brk:
 		rgp++;
 	}
 
+	if(debug['R'] && debug['v'])
+		dumpit("pass6", firstr);
+
 	/*
 	 * pass 7
 	 * peep-hole on basic block
 	 */
-	if(debug['P']) {
+	if(!debug['R'] || debug['P']) {
 		peep();
 	}
 
@@ -547,14 +588,43 @@ brk:
 	 * free aux structures
 	 */
 	for(p=firstp; p!=P; p=p->link) {
-		while(p->link && p->link->as == ANOP)
+		while(p->link != P && p->link->as == ANOP)
 			p->link = p->link->link;
+		if(p->to.type == D_BRANCH)
+			while(p->to.branch != P && p->to.branch->as == ANOP)
+				p->to.branch = p->to.branch->link;
 	}
 
 	if(r1 != R) {
 		r1->link = freer;
 		freer = firstr;
 	}
+
+	if(debug['R']) {
+		if(ostats.ncvtreg ||
+		   ostats.nspill ||
+		   ostats.nreload ||
+		   ostats.ndelmov ||
+		   ostats.nvar ||
+		   ostats.naddr ||
+		   0)
+			print("\nstats\n");
+
+		if(ostats.ncvtreg)
+			print("	%4ld cvtreg\n", ostats.ncvtreg);
+		if(ostats.nspill)
+			print("	%4ld spill\n", ostats.nspill);
+		if(ostats.nreload)
+			print("	%4ld reload\n", ostats.nreload);
+		if(ostats.ndelmov)
+			print("	%4ld delmov\n", ostats.ndelmov);
+		if(ostats.nvar)
+			print("	%4ld delmov\n", ostats.nvar);
+		if(ostats.naddr)
+			print("	%4ld delmov\n", ostats.naddr);
+
+		memset(&ostats, 0, sizeof(ostats));
+	}
 }
 
 /*
@@ -585,7 +655,7 @@ addmove(Reg *r, int bn, int rn, int f)
 	a->etype = v->etype;
 	a->type = v->name;
 
-	// need to chean this up with wptr and
+	// need to clean this up with wptr and
 	// some of the defaults
 	p1->as = AMOVL;
 	switch(v->etype) {
@@ -611,7 +681,7 @@ addmove(Reg *r, int bn, int rn, int f)
 		p1->as = AMOVSS;
 		break;
 	case TFLOAT64:
-		p1->as = AMOVSS;
+		p1->as = AMOVSD;
 		break;
 	case TINT:
 	case TUINT:
@@ -631,8 +701,9 @@ addmove(Reg *r, int bn, int rn, int f)
 		if(v->etype == TUINT16)
 			p1->as = AMOVW;
 	}
-//	if(debug['R'])
-		print("%P\t.a%P\n", p, p1);
+	if(debug['R'] && debug['v'])
+		print("%P ===add=== %P\n", p, p1);
+	ostats.nspill++;
 }
 
 uint32
@@ -670,8 +741,10 @@ mkvar(Reg *r, Adr *a)
 	 * mark registers used
 	 */
 	t = a->type;
-	r->regu |= doregbits(t);
-	r->regu |= doregbits(a->index);
+	if(r != R) {
+		r->regu |= doregbits(t);
+		r->regu |= doregbits(a->index);
+	}
 
 	switch(t) {
 	default:
@@ -682,6 +755,7 @@ mkvar(Reg *r, Adr *a)
 		for(z=0; z<BITS; z++)
 			addrs.b[z] |= bit.b[z];
 		a->type = t;
+		ostats.naddr++;
 		goto none;
 	case D_EXTERN:
 	case D_STATIC:
@@ -727,6 +801,7 @@ mkvar(Reg *r, Adr *a)
 	v->etype = et;
 	if(debug['R'])
 		print("bit=%2d et=%2d %D\n", i, et, a);
+	ostats.nvar++;
 
 out:
 	bit = blsh(i);
@@ -738,7 +813,8 @@ out:
 			params.b[z] |= bit.b[z];
 	if(v->etype != et) {
 		/* funny punning */
-print("pun %d %d %S\n", v->etype, et, s);
+		if(debug['R'])
+			print("pun %d %d %S\n", v->etype, et, s);
 		for(z=0; z<BITS; z++)
 			addrs.b[z] |= bit.b[z];
 	}
@@ -787,9 +863,10 @@ prop(Reg *r, Bits ref, Bits cal)
 
 		case ARET:
 			for(z=0; z<BITS; z++) {
-				cal.b[z] = externs.b[z];
+				cal.b[z] = externs.b[z] | ovar.b[z];
 				ref.b[z] = 0;
 			}
+			break;
 		}
 		for(z=0; z<BITS; z++) {
 			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@@ -1044,9 +1121,6 @@ paint1(Reg *r, int bn)
 
 	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
 		change -= CLOAD * r->loop;
-		if(debug['R'] && debug['v'])
-			print("%ld%P\tld %Q $%d\n", r->loop,
-				r->prog, blsh(bn), change);
 	}
 	for(;;) {
 		r->act.b[z] |= bb;
@@ -1054,23 +1128,14 @@ paint1(Reg *r, int bn)
 
 		if(r->use1.b[z] & bb) {
 			change += CREF * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%ld%P\tu1 %Q $%d\n", r->loop,
-					p, blsh(bn), change);
 		}
 
 		if((r->use2.b[z]|r->set.b[z]) & bb) {
 			change += CREF * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%ld%P\tu2 %Q $%d\n", r->loop,
-					p, blsh(bn), change);
 		}
 
 		if(STORE(r) & r->regdiff.b[z] & bb) {
 			change -= CLOAD * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%ld%P\tst %Q $%d\n", r->loop,
-					p, blsh(bn), change);
 		}
 
 		if(r->refbehind.b[z] & bb)
@@ -1226,18 +1291,18 @@ paint3(Reg *r, int bn, int32 rb, int rn)
 		p = r->prog;
 
 		if(r->use1.b[z] & bb) {
-			if(debug['R'])
+			if(debug['R'] && debug['v'])
 				print("%P", p);
 			addreg(&p->from, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
+			if(debug['R'] && debug['v'])
+				print(" ===change== %P\n", p);
 		}
 		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			if(debug['R'])
+			if(debug['R'] && debug['v'])
 				print("%P", p);
 			addreg(&p->to, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
+			if(debug['R'] && debug['v'])
+				print(" ===change== %P\n", p);
 		}
 
 		if(STORE(r) & r->regdiff.b[z] & bb)
@@ -1272,6 +1337,8 @@ addreg(Adr *a, int rn)
 	a->sym = 0;
 	a->offset = 0;
 	a->type = rn;
+
+	ostats.ncvtreg++;
 }
 
 int32
@@ -1286,8 +1353,7 @@ RtoB(int r)
 int
 BtoR(int32 b)
 {
-
-	b &= 0xffffL;
+	b &= 0x3fffL;		// no R14 or R15
 	if(b == 0)
 		return 0;
 	return bitno(b) + D_AX;
@@ -1317,7 +1383,7 @@ BtoF(int32 b)
 	return bitno(b) - 16 + FREGMIN;
 }
 
-static void
+void
 dumpit(char *str, Reg *r0)
 {
 	Reg *r, *r1;
@@ -1380,7 +1446,7 @@ dumpit(char *str, Reg *r0)
 
 static Sym*	symlist[10];
 
-static int
+int
 noreturn(Prog *p)
 {
 	Sym *s;
@@ -1388,6 +1454,7 @@ noreturn(Prog *p)
 
 	if(symlist[0] == S) {
 		symlist[0] = pkglookup("throwindex", "sys");
+		symlist[1] = pkglookup("panicl", "sys");
 	}
 
 	s = p->to.sym;
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index c5e35a1e48..ce1d4cee50 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -284,6 +284,7 @@ enum
 	OEQ, ONE, OLT, OLE, OGE, OGT,
 	OADD, OSUB, OOR, OXOR,
 	OMUL, ODIV, OMOD, OLSH, ORSH, OAND,
+	OINC, ODEC,	// placeholders - not used
 	OFUNC,
 	OLABEL,
 	OBREAK,
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 685267c279..1c87e05eb0 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -1094,7 +1094,20 @@ loop:
 	goto ret;
 
 nottop:
-	yyerror("didn't expect %O here", n->op);
+	switch(top) {
+	default:
+		yyerror("didn't expect %O here", n->op);
+		break;
+	case Etop:
+		yyerror("operation %O not allowed in statement context", n->op);
+		break;
+	case Elv:
+		yyerror("operation %O not allowed in assignment context", n->op);
+		break;
+	case Erv:
+		yyerror("operation %O not allowed in expression context", n->op);
+		break;
+	}
 	goto ret;
 
 badt:
-- 
2.30.9