cmd/internal/gc: move componentgen into portable code

Change-Id: I652cc7a33a186d1041f62f6e7581421496832a27
Reviewed-on: https://go-review.googlesource.com/7747
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
diff --git a/src/cmd/5g/cgen.go b/src/cmd/5g/cgen.go
index a6cc54d..fae1699 100644
--- a/src/cmd/5g/cgen.go
+++ b/src/cmd/5g/cgen.go
@@ -1530,7 +1530,7 @@
 	}
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(n, res) {
+	if gc.Componentgen(n, res) {
 		return
 	}
 
@@ -1725,268 +1725,3 @@
 	regfree(&src)
 	regfree(&tmp)
 }
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if cant.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
-}
diff --git a/src/cmd/5g/galign.go b/src/cmd/5g/galign.go
index 4b8b82c..c565550 100644
--- a/src/cmd/5g/galign.go
+++ b/src/cmd/5g/galign.go
@@ -61,6 +61,7 @@
 	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Gmove = gmove
 	gc.Thearch.Igen = igen
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
diff --git a/src/cmd/5g/ggen.go b/src/cmd/5g/ggen.go
index 3538177..6eb9501 100644
--- a/src/cmd/5g/ggen.go
+++ b/src/cmd/5g/ggen.go
@@ -657,7 +657,7 @@
 	w := uint32(nl.Type.Width)
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(nil, nl) {
+	if gc.Componentgen(nil, nl) {
 		return
 	}
 
diff --git a/src/cmd/6g/cgen.go b/src/cmd/6g/cgen.go
index b757232..d11f7c7 100644
--- a/src/cmd/6g/cgen.go
+++ b/src/cmd/6g/cgen.go
@@ -1441,7 +1441,7 @@
 	}
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(n, ns) {
+	if gc.Componentgen(n, ns) {
 		return
 	}
 
@@ -1612,268 +1612,3 @@
 
 	restx(&cx, &oldcx)
 }
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) && !gc.Isslice(t) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
-}
diff --git a/src/cmd/6g/galign.go b/src/cmd/6g/galign.go
index 6a2bac8..ca8d387 100644
--- a/src/cmd/6g/galign.go
+++ b/src/cmd/6g/galign.go
@@ -86,6 +86,7 @@
 	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Gmove = gmove
 	gc.Thearch.Igen = igen
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go
index f980593..42bebf8 100644
--- a/src/cmd/6g/ggen.go
+++ b/src/cmd/6g/ggen.go
@@ -950,7 +950,7 @@
 	w := nl.Type.Width
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(nil, nl) {
+	if gc.Componentgen(nil, nl) {
 		return
 	}
 
diff --git a/src/cmd/7g/cgen.go b/src/cmd/7g/cgen.go
index 455113b..b18ba5f 100644
--- a/src/cmd/7g/cgen.go
+++ b/src/cmd/7g/cgen.go
@@ -1424,8 +1424,10 @@
 	}
 
 	// Avoid taking the address for simple enough types.
-	//if(componentgen(n, ns))
-	//	return;
+	//if gc.Componentgen(n, ns) {
+	//	return
+	//}
+
 	if w == 0 {
 		// evaluate side effects only.
 		var dst gc.Node
@@ -1598,268 +1600,3 @@
 	regfree(&src)
 	regfree(&tmp)
 }
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
-}
diff --git a/src/cmd/7g/galign.go b/src/cmd/7g/galign.go
index 52ac23c..19c4d38 100644
--- a/src/cmd/7g/galign.go
+++ b/src/cmd/7g/galign.go
@@ -60,6 +60,7 @@
 	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Gmove = gmove
 	gc.Thearch.Igen = igen
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
diff --git a/src/cmd/7g/ggen.go b/src/cmd/7g/ggen.go
index 7eb913f..cb48663 100644
--- a/src/cmd/7g/ggen.go
+++ b/src/cmd/7g/ggen.go
@@ -720,8 +720,9 @@
 	w := uint64(uint64(nl.Type.Width))
 
 	// Avoid taking the address for simple enough types.
-	//if(componentgen(N, nl))
-	//	return;
+	//if gc.Componentgen(nil, nl) {
+	//	return
+	//}
 
 	c := uint64(w % 8) // bytes
 	q := uint64(w / 8) // dwords
diff --git a/src/cmd/8g/cgen.go b/src/cmd/8g/cgen.go
index aefae7e..2a10e49 100644
--- a/src/cmd/8g/cgen.go
+++ b/src/cmd/8g/cgen.go
@@ -1332,7 +1332,7 @@
 	}
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(n, res) {
+	if gc.Componentgen(n, res) {
 		return
 	}
 
@@ -1462,268 +1462,3 @@
 		}
 	}
 }
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
-}
diff --git a/src/cmd/8g/galign.go b/src/cmd/8g/galign.go
index 7c462f5..f0c878a 100644
--- a/src/cmd/8g/galign.go
+++ b/src/cmd/8g/galign.go
@@ -61,6 +61,7 @@
 	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Gmove = gmove
 	gc.Thearch.Igen = igen
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
diff --git a/src/cmd/8g/ggen.go b/src/cmd/8g/ggen.go
index 077b657..3a197cd 100644
--- a/src/cmd/8g/ggen.go
+++ b/src/cmd/8g/ggen.go
@@ -112,7 +112,7 @@
 	w := uint32(nl.Type.Width)
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(nil, nl) {
+	if gc.Componentgen(nil, nl) {
 		return
 	}
 
diff --git a/src/cmd/9g/cgen.go b/src/cmd/9g/cgen.go
index 4ab5215..6ab7f35 100644
--- a/src/cmd/9g/cgen.go
+++ b/src/cmd/9g/cgen.go
@@ -1445,8 +1445,10 @@
 	}
 
 	// Avoid taking the address for simple enough types.
-	//if(componentgen(n, ns))
-	//	return;
+	if gc.Componentgen(n, ns) {
+		return
+	}
+
 	if w == 0 {
 		// evaluate side effects only.
 		var dst gc.Node
@@ -1615,268 +1617,3 @@
 	regfree(&src)
 	regfree(&tmp)
 }
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
-}
diff --git a/src/cmd/9g/galign.go b/src/cmd/9g/galign.go
index b39149a..69e6bac 100644
--- a/src/cmd/9g/galign.go
+++ b/src/cmd/9g/galign.go
@@ -69,6 +69,7 @@
 	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Gmove = gmove
 	gc.Thearch.Igen = igen
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
diff --git a/src/cmd/9g/ggen.go b/src/cmd/9g/ggen.go
index 5919a79..dfc54a7 100644
--- a/src/cmd/9g/ggen.go
+++ b/src/cmd/9g/ggen.go
@@ -734,8 +734,9 @@
 	w := uint64(uint64(nl.Type.Width))
 
 	// Avoid taking the address for simple enough types.
-	//if(componentgen(N, nl))
-	//	return;
+	if gc.Componentgen(nil, nl) {
+		return
+	}
 
 	c := uint64(w % 8) // bytes
 	q := uint64(w / 8) // dwords
diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go
index 3777cc3..314f6c1 100644
--- a/src/cmd/internal/gc/gen.go
+++ b/src/cmd/internal/gc/gen.go
@@ -956,3 +956,268 @@
 		}
 	}
 }
+
+/*
+ * copy a composite value by moving its individual components.
+ * Slices, strings and interfaces are supported.
+ * Small structs or arrays with elements of basic type are
+ * also supported.
+ * nr is N when assigning a zero value.
+ * return 1 if can do, 0 if can't.
+ */
+func Componentgen(nr *Node, nl *Node) bool {
+	var nodl Node
+	var nodr Node
+
+	freel := 0
+	freer := 0
+
+	switch nl.Type.Etype {
+	default:
+		goto no
+
+	case TARRAY:
+		t := nl.Type
+
+		// Slices are ok.
+		if Isslice(t) {
+			break
+		}
+
+		// Small arrays are ok.
+		if t.Bound > 0 && t.Bound <= 3 && !Isfat(t.Type) {
+			break
+		}
+
+		goto no
+
+		// Small structs with non-fat types are ok.
+	// Zero-sized structs are treated separately elsewhere.
+	case TSTRUCT:
+		fldcount := int64(0)
+
+		for t := nl.Type.Type; t != nil; t = t.Down {
+			if Isfat(t.Type) && !Isslice(t) {
+				goto no
+			}
+			if t.Etype != TFIELD {
+				Fatal("componentgen: not a TFIELD: %v", Tconv(t, obj.FmtLong))
+			}
+			fldcount++
+		}
+
+		if fldcount == 0 || fldcount > 4 {
+			goto no
+		}
+
+	case TSTRING,
+		TINTER:
+		break
+	}
+
+	nodl = *nl
+	if !cadable(nl) {
+		if nr != nil && !cadable(nr) {
+			goto no
+		}
+		Thearch.Igen(nl, &nodl, nil)
+		freel = 1
+	}
+
+	if nr != nil {
+		nodr = *nr
+		if !cadable(nr) {
+			Thearch.Igen(nr, &nodr, nil)
+			freer = 1
+		}
+	} else {
+		// When zeroing, prepare a register containing zero.
+		var tmp Node
+		Nodconst(&tmp, nl.Type, 0)
+
+		Thearch.Regalloc(&nodr, Types[TUINT], nil)
+		Thearch.Gmove(&tmp, &nodr)
+		freer = 1
+	}
+
+	// nl and nr are 'cadable' which basically means they are names (variables) now.
+	// If they are the same variable, don't generate any code, because the
+	// VARDEF we generate will mark the old value as dead incorrectly.
+	// (And also the assignments are useless.)
+	if nr != nil && nl.Op == ONAME && nr.Op == ONAME && nl == nr {
+		goto yes
+	}
+
+	switch nl.Type.Etype {
+	// componentgen for arrays.
+	case TARRAY:
+		if nl.Op == ONAME {
+			Gvardef(nl)
+		}
+		t := nl.Type
+		if !Isslice(t) {
+			nodl.Type = t.Type
+			nodr.Type = nodl.Type
+			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
+				if nr == nil {
+					Clearslim(&nodl)
+				} else {
+					Thearch.Gmove(&nodr, &nodl)
+				}
+				nodl.Xoffset += t.Type.Width
+				nodr.Xoffset += t.Type.Width
+			}
+
+			goto yes
+		}
+
+		// componentgen for slices.
+		nodl.Xoffset += int64(Array_array)
+
+		nodl.Type = Ptrto(nl.Type.Type)
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
+		nodl.Type = Types[Simtype[TUINT]]
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		nodl.Xoffset += int64(Array_cap) - int64(Array_nel)
+		nodl.Type = Types[Simtype[TUINT]]
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_cap) - int64(Array_nel)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		goto yes
+
+	case TSTRING:
+		if nl.Op == ONAME {
+			Gvardef(nl)
+		}
+		nodl.Xoffset += int64(Array_array)
+		nodl.Type = Ptrto(Types[TUINT8])
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
+		nodl.Type = Types[Simtype[TUINT]]
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		goto yes
+
+	case TINTER:
+		if nl.Op == ONAME {
+			Gvardef(nl)
+		}
+		nodl.Xoffset += int64(Array_array)
+		nodl.Type = Ptrto(Types[TUINT8])
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
+		nodl.Type = Ptrto(Types[TUINT8])
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		goto yes
+
+	case TSTRUCT:
+		if nl.Op == ONAME {
+			Gvardef(nl)
+		}
+		loffset := nodl.Xoffset
+		roffset := nodr.Xoffset
+
+		// funarg structs may not begin at offset zero.
+		if nl.Type.Etype == TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
+			loffset -= nl.Type.Type.Width
+		}
+		if nr != nil && nr.Type.Etype == TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
+			roffset -= nr.Type.Type.Width
+		}
+
+		for t := nl.Type.Type; t != nil; t = t.Down {
+			nodl.Xoffset = loffset + t.Width
+			nodl.Type = t.Type
+
+			if nr == nil {
+				Clearslim(&nodl)
+			} else {
+				nodr.Xoffset = roffset + t.Width
+				nodr.Type = nodl.Type
+				Thearch.Gmove(&nodr, &nodl)
+			}
+		}
+
+		goto yes
+	}
+
+no:
+	if freer != 0 {
+		Thearch.Regfree(&nodr)
+	}
+	if freel != 0 {
+		Thearch.Regfree(&nodl)
+	}
+	return false
+
+yes:
+	if freer != 0 {
+		Thearch.Regfree(&nodr)
+	}
+	if freel != 0 {
+		Thearch.Regfree(&nodl)
+	}
+	return true
+}
+
+func cadable(n *Node) bool {
+	if n.Addable == 0 {
+		// dont know how it happens,
+		// but it does
+		return false
+	}
+
+	switch n.Op {
+	case ONAME:
+		return true
+	}
+
+	return false
+}
diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go
index e33b6f5..67a226e 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/internal/gc/go.go
@@ -790,6 +790,7 @@
 	Ginit          func()
 	Gins           func(int, *Node, *Node) *obj.Prog
 	Ginscall       func(*Node, int)
+	Gmove          func(*Node, *Node)
 	Igen           func(*Node, *Node, *Node)
 	Linkarchinit   func()
 	Peep           func(*obj.Prog)