fix fat copy of overlapping data

R=r
OCL=14417
CL=14417
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index bbd904d..b4ae1df 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -282,13 +282,6 @@
 		fatal("agen: unknown op %N", n);
 		break;
 
-//	case ONAME:
-//		regalloc(&n1, types[tptr], res);
-//		gins(optoas(OADDR, types[tptr]), n, &n1);
-//		gmove(&n1, res);
-//		regfree(&n1);
-//		break;
-
 	case OCALLMETH:
 		cgen_callmeth(n, 0);
 		cgen_aret(n, res);
@@ -330,8 +323,6 @@
 		agen_inter(n, res);
 		break;
 
-//	case OINDREG:
-
 	case OINDEX:
 		w = n->type->width;
 		if(nr->addable)
@@ -585,11 +576,27 @@
 	;
 }
 
+int32
+stkof(Node *n)
+{
+	switch(n->op) {
+	case OS2I:
+		return 2*widthptr;
+	case OI2I:
+		return 1*widthptr;
+	case OINDREG:
+		return n->xoffset;
+	}
+	// botch - probably failing to recognize address
+	// arithmetic on the above. eg INDEX and DOT
+	return -1;
+}
+
 void
 sgen(Node *n, Node *ns, uint32 w)
 {
 	Node nodl, nodr;
-	int32 c;
+	int32 c, q, odst, osrc;
 
 	if(debug['g']) {
 		dump("\nsgen-res", ns);
@@ -601,6 +608,14 @@
 		fatal("sgen UINF");
 	}
 
+	// offset on the stack
+	odst = stkof(ns);
+	osrc = stkof(n);
+	if(osrc < 0)
+		odst = odst;
+	if(odst < 0)
+		osrc = odst;
+
 	nodreg(&nodl, types[tptr], D_DI);
 	nodreg(&nodr, types[tptr], D_SI);
 
@@ -611,20 +626,52 @@
 		agen(ns, &nodl);
 		agen(n, &nodr);
 	}
-	gins(ACLD, N, N);	// clear direction flag
 
-	c = w / 8;
-	if(c > 0) {
-		gconreg(AMOVQ, c, D_CX);
-		gins(AREP, N, N);	// repeat
-		gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
+	c = w % 8;	// bytes
+	q = w / 8;	// quads
+
+	// if we are copying forward on the stack and
+	// the src and dst overlap, then reverse direction
+	if(odst > osrc && odst-osrc < w) {
+		// reverse direction
+		gins(ASTD, N, N);		// set direction flag
+		if(c > 0) {
+			gconreg(AADDQ, w-1, D_SI);
+			gconreg(AADDQ, w-1, D_DI);
+
+			gconreg(AMOVQ, c, D_CX);
+			gins(AREP, N, N);	// repeat
+			gins(AMOVSB, N, N);	// MOVB *(SI)-,*(DI)-
+		}
+
+		if(q > 0) {
+			if(c > 0) {
+				gconreg(AADDQ, -7, D_SI);
+				gconreg(AADDQ, -7, D_DI);
+			} else {
+				gconreg(AADDQ, w-8, D_SI);
+				gconreg(AADDQ, w-8, D_DI);
+			}
+			gconreg(AMOVQ, q, D_CX);
+			gins(AREP, N, N);	// repeat
+			gins(AMOVSQ, N, N);	// MOVQ *(SI)-,*(DI)-
+		}
+		// for future optimization
+		// we leave with the flag clear
+		gins(ACLD, N, N);
+	} else {
+		// normal direction
+		gins(ACLD, N, N);		// clear direction flag
+		if(q > 0) {
+			gconreg(AMOVQ, q, D_CX);
+			gins(AREP, N, N);	// repeat
+			gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
+		}
+
+		if(c > 0) {
+			gconreg(AMOVQ, c, D_CX);
+			gins(AREP, N, N);	// repeat
+			gins(AMOVSB, N, N);	// MOVB *(SI)+,*(DI)+
+		}
 	}
-
-	c = w % 8;
-	if(c > 0) {
-		gconreg(AMOVQ, c, D_CX);
-		gins(AREP, N, N);	// repeat
-		gins(AMOVSB, N, N);	// MOVB *(SI)+,*(DI)+
-	}
-
 }
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 08c3664..8f1b71a 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -28,7 +28,7 @@
 %token			LLSH LRSH LINC LDEC LSEND LRECV
 %token			LIGNORE
 
-%type	<sym>		sym sym1 sym2 key1 key2 laconst lname latype
+%type	<sym>		sym sym1 sym2 key laconst lname latype
 %type	<lint>		chandir
 %type	<node>		xdcl xdcl_list_r oxdcl_list
 %type	<node>		common_dcl Acommon_dcl Bcommon_dcl
@@ -836,18 +836,17 @@
 
 sym1:
 	sym
-|	key1
+|	key
 
 sym2:
 	sym
-|	key1
-|	key2
+|	key
 
 /*
  * keywords that we can
  * use as variable/type names
  */
-key1:
+key:
 	LNIL
 |	LTRUE
 |	LFALSE
@@ -858,38 +857,7 @@
 |	LNEW
 |	LBASETYPE
 |	LTYPEOF
-
-/*
- * keywords that we can
- * use as field names
- */
-key2:
-	LPACKAGE
-|	LIMPORT
-|	LEXPORT
-|	LMAP
-|	LCHAN
-|	LINTERFACE
-|	LFUNC
-|	LSTRUCT
-|	LFALL
-|	LRETURN
-|	LVAR
-|	LTYPE
-|	LCONST
 |	LCONVERT
-|	LSELECT
-|	LFOR
-|	LIF
-|	LELSE
-|	LSWITCH
-|	LCASE
-|	LDEFAULT
-|	LBREAK
-|	LCONTINUE
-|	LGO
-|	LGOTO
-|	LRANGE
 
 name:
 	lname