cmd/internal/gc: move cgen, regalloc, et al to portable code

This CL moves the bulk of the code that has been copy-and-pasted
since the initial 386 port back into a shared place, cutting 5 copies to 1.

The motivation here is not cleanup per se but instead to reduce the
cost of introducing changes in shared concepts like regalloc or general
expression evaluation. For example, a change after this one will
implement x.(*T) without a call into the runtime. This CL makes that
followup work 5x easier.

The single copy still has more special cases for architecture details
than I'd like, but having them called out explicitly like this at least
opens the door to generalizing the conditions and smoothing out
the distinctions in the future.

This is a LARGE CL. I started by trying to pull in one function at a time
in a sequence of CLs and it became clear that everything was so
interrelated that it had to be moved as a whole. Apologies for the size.

It is not clear how many more releases this code will matter for;
eventually it will be replaced by Keith's SSA work. But as noted above,
the deduplication was necessary to reduce the cost of working on
the current code while we have it.

Passes tests on amd64, 386, arm, and ppc64le.
Can build arm64 binaries but not tested there.
Being able to build binaries means it is probably very close.

Change-Id: I735977f04c0614f80215fb12966dfe9bbd1f5861
Reviewed-on: https://go-review.googlesource.com/7853
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/5g/cgen.go b/src/cmd/5g/cgen.go
index fae1699..07ced87 100644
--- a/src/cmd/5g/cgen.go
+++ b/src/cmd/5g/cgen.go
@@ -8,614 +8,22 @@
 	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
-	"fmt"
 )
 
 /*
- * peep.c
- */
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- */
-func cgen(n *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\ncgen-n", n)
-		gc.Dump("cgen-res", res)
-	}
-
-	if n == nil || n.Type == nil {
-		return
-	}
-
-	if res == nil || res.Type == nil {
-		gc.Fatal("cgen: res nil")
-	}
-
-	switch n.Op {
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_slice(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_slice(n, res)
-		}
-		return
-
-	case gc.OEFACE:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_eface(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_eface(n, res)
-		}
-		return
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	if n.Ullman >= gc.UINF {
-		if n.Op == gc.OINDREG {
-			gc.Fatal("cgen: this is going to misscompile")
-		}
-		if res.Ullman >= gc.UINF {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			cgen(n, &n1)
-			cgen(&n1, res)
-			return
-		}
-	}
-
-	if gc.Isfat(n.Type) {
-		if n.Type.Width < 0 {
-			gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0))
-		}
-		sgen(n, res, n.Type.Width)
-		return
-	}
-
-	// update addressability for string, slice
-	// can't do in walk because n->left->addable
-	// changes if n->left is an escaping local variable.
-	switch n.Op {
-	case gc.OSPTR,
-		gc.OLEN:
-		if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OCAP:
-		if gc.Isslice(n.Left.Type) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OITAB:
-		n.Addable = n.Left.Addable
-	}
-
-	// if both are addressable, move
-	if n.Addable != 0 && res.Addable != 0 {
-		if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Op == gc.OREGISTER || res.Op == gc.OREGISTER || gc.Iscomplex[n.Type.Etype] || gc.Iscomplex[res.Type.Etype] {
-			gmove(n, res)
-		} else {
-			var n1 gc.Node
-			regalloc(&n1, n.Type, nil)
-			gmove(n, &n1)
-			cgen(&n1, res)
-			regfree(&n1)
-		}
-
-		return
-	}
-
-	// if both are not addressable, use a temporary.
-	if n.Addable == 0 && res.Addable == 0 {
-		// could use regalloc here sometimes,
-		// but have to check for ullman >= UINF.
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-
-		cgen(n, &n1)
-		cgen(&n1, res)
-		return
-	}
-
-	// if result is not addressable directly but n is,
-	// compute its address and then store via the address.
-	if res.Addable == 0 {
-		var n1 gc.Node
-		igen(res, &n1, nil)
-		cgen(n, &n1)
-		regfree(&n1)
-		return
-	}
-
-	if gc.Complexop(n, res) {
-		gc.Complexgen(n, res)
-		return
-	}
-
-	// if n is sudoaddable generate addr and move
-	if !gc.Is64(n.Type) && !gc.Is64(res.Type) && !gc.Iscomplex[n.Type.Etype] && !gc.Iscomplex[res.Type.Etype] {
-		a := optoas(gc.OAS, n.Type)
-		var w int
-		var addr obj.Addr
-		if sudoaddable(a, n, &addr, &w) {
-			if res.Op != gc.OREGISTER {
-				var n2 gc.Node
-				regalloc(&n2, res.Type, nil)
-				p1 := gins(a, nil, &n2)
-				p1.From = addr
-				if gc.Debug['g'] != 0 {
-					fmt.Printf("%v [ignore previous line]\n", p1)
-				}
-				gmove(&n2, res)
-				regfree(&n2)
-			} else {
-				p1 := gins(a, nil, res)
-				p1.From = addr
-				if gc.Debug['g'] != 0 {
-					fmt.Printf("%v [ignore previous line]\n", p1)
-				}
-			}
-
-			sudoclean()
-			return
-		}
-	}
-
-	// otherwise, the result is addressable but n is not.
-	// let's do some computation.
-
-	nl := n.Left
-
-	nr := n.Right
-
-	if nl != nil && nl.Ullman >= gc.UINF {
-		if nr != nil && nr.Ullman >= gc.UINF {
-			var n1 gc.Node
-			gc.Tempname(&n1, nl.Type)
-			cgen(nl, &n1)
-			n2 := *n
-			n2.Left = &n1
-			cgen(&n2, res)
-			return
-		}
-	}
-
-	// 64-bit ops are hard on 32-bit machine.
-	if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Left != nil && gc.Is64(n.Left.Type) {
-		switch n.Op {
-		// math goes to cgen64.
-		case gc.OMINUS,
-			gc.OCOM,
-			gc.OADD,
-			gc.OSUB,
-			gc.OMUL,
-			gc.OLROT,
-			gc.OLSH,
-			gc.ORSH,
-			gc.OAND,
-			gc.OOR,
-			gc.OXOR:
-			cgen64(n, res)
-
-			return
-		}
-	}
-
-	var a int
-	var f0 gc.Node
-	var n1 gc.Node
-	var n2 gc.Node
-	if nl != nil && gc.Isfloat[n.Type.Etype] && gc.Isfloat[nl.Type.Etype] {
-		// floating-point.
-		regalloc(&f0, nl.Type, res)
-
-		if nr != nil {
-			goto flt2
-		}
-
-		if n.Op == gc.OMINUS {
-			nr = gc.Nodintconst(-1)
-			gc.Convlit(&nr, n.Type)
-			n.Op = gc.OMUL
-			goto flt2
-		}
-
-		// unary
-		cgen(nl, &f0)
-
-		if n.Op != gc.OCONV && n.Op != gc.OPLUS {
-			gins(optoas(int(n.Op), n.Type), &f0, &f0)
-		}
-		gmove(&f0, res)
-		regfree(&f0)
-		return
-	}
-	switch n.Op {
-	default:
-		gc.Dump("cgen", n)
-		gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign))
-
-	case gc.OREAL,
-		gc.OIMAG,
-		gc.OCOMPLEX:
-		gc.Fatal("unexpected complex")
-
-		// these call bgen to get a bool value
-	case gc.OOROR,
-		gc.OANDAND,
-		gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OLE,
-		gc.OGE,
-		gc.OGT,
-		gc.ONOT:
-		p1 := gc.Gbranch(arm.AB, nil, 0)
-
-		p2 := gc.Pc
-		gmove(gc.Nodbool(true), res)
-		p3 := gc.Gbranch(arm.AB, nil, 0)
-		gc.Patch(p1, gc.Pc)
-		bgen(n, true, 0, p2)
-		gmove(gc.Nodbool(false), res)
-		gc.Patch(p3, gc.Pc)
-		return
-
-	case gc.OPLUS:
-		cgen(nl, res)
-		return
-
-		// unary
-	case gc.OCOM:
-		a := optoas(gc.OXOR, nl.Type)
-
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-		gc.Nodconst(&n2, nl.Type, -1)
-		gins(a, &n2, &n1)
-		goto norm
-
-	case gc.OMINUS:
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-		gc.Nodconst(&n2, nl.Type, 0)
-		gins(optoas(gc.OMINUS, nl.Type), &n2, &n1)
-		goto norm
-
-		// symmetric binary
-	case gc.OAND,
-		gc.OOR,
-		gc.OXOR,
-		gc.OADD,
-		gc.OMUL:
-		a = optoas(int(n.Op), nl.Type)
-
-		// symmetric binary
-		if nl.Ullman < nr.Ullman {
-			r := nl
-			nl = nr
-			nr = r
-		}
-		goto abop
-
-		// asymmetric binary
-	case gc.OSUB:
-		a = optoas(int(n.Op), nl.Type)
-
-		goto abop
-
-	case gc.OHMUL:
-		cgen_hmul(nl, nr, res)
-
-	case gc.OLROT,
-		gc.OLSH,
-		gc.ORSH:
-		cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
-
-	case gc.OCONV:
-		if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) {
-			cgen(nl, res)
-			break
-		}
-
-		var n1 gc.Node
-		if nl.Addable != 0 && !gc.Is64(nl.Type) {
-			regalloc(&n1, nl.Type, res)
-			gmove(nl, &n1)
-		} else {
-			if n.Type.Width > int64(gc.Widthptr) || gc.Is64(nl.Type) || gc.Isfloat[nl.Type.Etype] {
-				gc.Tempname(&n1, nl.Type)
-			} else {
-				regalloc(&n1, nl.Type, res)
-			}
-			cgen(nl, &n1)
-		}
-
-		var n2 gc.Node
-		if n.Type.Width > int64(gc.Widthptr) || gc.Is64(n.Type) || gc.Isfloat[n.Type.Etype] {
-			gc.Tempname(&n2, n.Type)
-		} else {
-			regalloc(&n2, n.Type, nil)
-		}
-		gmove(&n1, &n2)
-		gmove(&n2, res)
-		if n1.Op == gc.OREGISTER {
-			regfree(&n1)
-		}
-		if n2.Op == gc.OREGISTER {
-			regfree(&n2)
-		}
-
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OIND,
-		gc.ONAME: // PHEAP or PPARAMREF var
-		var n1 gc.Node
-		igen(n, &n1, res)
-
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// interface table is first word of interface value
-	case gc.OITAB:
-		var n1 gc.Node
-		igen(nl, &n1, res)
-
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// pointer is the first word of string or slice.
-	case gc.OSPTR:
-		if gc.Isconst(nl, gc.CTSTR) {
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-			p1 := gins(arm.AMOVW, nil, &n1)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		var n1 gc.Node
-		igen(nl, &n1, res)
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-	case gc.OLEN:
-		if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) {
-			// map has len in the first 32-bit word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-
-			cgen(nl, &n1)
-
-			var n2 gc.Node
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Type = gc.Types[gc.TINT32]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) {
-			// both slice and string have len one pointer into the struct.
-			var n1 gc.Node
-			igen(nl, &n1, res)
-
-			n1.Type = gc.Types[gc.TUINT32]
-			n1.Xoffset += int64(gc.Array_nel)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OCAP:
-		if gc.Istype(nl.Type, gc.TCHAN) {
-			// chan has cap in the second 32-bit word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-
-			cgen(nl, &n1)
-
-			var n2 gc.Node
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Xoffset = 4
-			n2.Type = gc.Types[gc.TINT32]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isslice(nl.Type) {
-			var n1 gc.Node
-			igen(nl, &n1, res)
-			n1.Type = gc.Types[gc.TUINT32]
-			n1.Xoffset += int64(gc.Array_cap)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OADDR:
-		agen(nl, res)
-
-		// Release res so that it is available for cgen_call.
-	// Pick it up again after the call.
-	case gc.OCALLMETH,
-		gc.OCALLFUNC:
-		rg := -1
-
-		if n.Ullman >= gc.UINF {
-			if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) {
-				rg = int(res.Val.U.Reg)
-				reg[rg]--
-			}
-		}
-
-		if n.Op == gc.OCALLMETH {
-			gc.Cgen_callmeth(n, 0)
-		} else {
-			cgen_call(n, 0)
-		}
-		if rg >= 0 {
-			reg[rg]++
-		}
-		cgen_callret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_callret(n, res)
-
-	case gc.OMOD,
-		gc.ODIV:
-		a = optoas(int(n.Op), nl.Type)
-		goto abop
-	}
-
-	return
-
-	// TODO(kaib): use fewer registers here.
-abop: // asymmetric binary
-	if nl.Ullman >= nr.Ullman {
-		regalloc(&n1, nl.Type, res)
-		cgen(nl, &n1)
-		switch n.Op {
-		case gc.OADD,
-			gc.OSUB,
-			gc.OAND,
-			gc.OOR,
-			gc.OXOR:
-			if gc.Smallintconst(nr) {
-				n2 = *nr
-				break
-			}
-			fallthrough
-
-		default:
-			regalloc(&n2, nr.Type, nil)
-			cgen(nr, &n2)
-		}
-	} else {
-		switch n.Op {
-		case gc.OADD,
-			gc.OSUB,
-			gc.OAND,
-			gc.OOR,
-			gc.OXOR:
-			if gc.Smallintconst(nr) {
-				n2 = *nr
-				break
-			}
-			fallthrough
-
-		default:
-			regalloc(&n2, nr.Type, res)
-			cgen(nr, &n2)
-		}
-
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-	}
-
-	gins(a, &n2, &n1)
-
-	// Normalize result for types smaller than word.
-norm:
-	if n.Type.Width < int64(gc.Widthptr) {
-		switch n.Op {
-		case gc.OADD,
-			gc.OSUB,
-			gc.OMUL,
-			gc.OCOM,
-			gc.OMINUS:
-			gins(optoas(gc.OAS, n.Type), &n1, &n1)
-		}
-	}
-
-	gmove(&n1, res)
-	regfree(&n1)
-	if n2.Op != gc.OLITERAL {
-		regfree(&n2)
-	}
-	return
-
-flt2: // binary
-	var f1 gc.Node
-	if nl.Ullman >= nr.Ullman {
-		cgen(nl, &f0)
-		regalloc(&f1, n.Type, nil)
-		gmove(&f0, &f1)
-		cgen(nr, &f0)
-		gins(optoas(int(n.Op), n.Type), &f0, &f1)
-	} else {
-		cgen(nr, &f0)
-		regalloc(&f1, n.Type, nil)
-		cgen(nl, &f1)
-		gins(optoas(int(n.Op), n.Type), &f0, &f1)
-	}
-
-	gmove(&f1, res)
-	regfree(&f0)
-	regfree(&f1)
-	return
-}
-
-/*
  * generate array index into res.
  * n might be any size; res is 32-bit.
  * returns Prog* to patch to panic call.
  */
 func cgenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
 	if !gc.Is64(n.Type) {
-		cgen(n, res)
+		gc.Cgen(n, res)
 		return nil
 	}
 
 	var tmp gc.Node
 	gc.Tempname(&tmp, gc.Types[gc.TINT64])
-	cgen(n, &tmp)
+	gc.Cgen(n, &tmp)
 	var lo gc.Node
 	var hi gc.Node
 	split64(&tmp, &lo, &hi)
@@ -626,914 +34,48 @@
 	}
 
 	var n1 gc.Node
-	regalloc(&n1, gc.Types[gc.TINT32], nil)
+	gc.Regalloc(&n1, gc.Types[gc.TINT32], nil)
 	var n2 gc.Node
-	regalloc(&n2, gc.Types[gc.TINT32], nil)
+	gc.Regalloc(&n2, gc.Types[gc.TINT32], nil)
 	var zero gc.Node
 	gc.Nodconst(&zero, gc.Types[gc.TINT32], 0)
 	gmove(&hi, &n1)
 	gmove(&zero, &n2)
-	gcmp(arm.ACMP, &n1, &n2)
-	regfree(&n2)
-	regfree(&n1)
+	gins(arm.ACMP, &n1, &n2)
+	gc.Regfree(&n2)
+	gc.Regfree(&n1)
 	splitclean()
 	return gc.Gbranch(arm.ABNE, nil, -1)
 }
 
-/*
- * generate:
- *	res = &n;
- * The generated code checks that the result is not nil.
- */
-func agen(n *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nagen-res", res)
-		gc.Dump("agen-r", n)
-	}
-
-	if n == nil || n.Type == nil || res == nil || res.Type == nil {
-		gc.Fatal("agen")
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) {
-		// Use of a nil interface or nil slice.
-		// Create a temporary we can take the address of and read.
-		// The generated code is just going to panic, so it need not
-		// be terribly efficient. See issue 3670.
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-
-		gc.Gvardef(&n1)
-		clearfat(&n1)
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.Tptr], res)
-		gins(arm.AMOVW, &n1, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		return
-	}
-
-	if n.Addable != 0 {
-		var n1 gc.Node
-		n1.Op = gc.OADDR
-		n1.Left = n
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.Tptr], res)
-		gins(arm.AMOVW, &n1, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		return
-	}
-
-	nl := n.Left
-
-	switch n.Op {
-	default:
-		gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign))
-
-		// Release res so that it is available for cgen_call.
-	// Pick it up again after the call.
-	case gc.OCALLMETH,
-		gc.OCALLFUNC:
-		r := -1
-
-		if n.Ullman >= gc.UINF {
-			if res.Op == gc.OREGISTER || res.Op == gc.OINDREG {
-				r = int(res.Val.U.Reg)
-				reg[r]--
-			}
-		}
-
-		if n.Op == gc.OCALLMETH {
-			gc.Cgen_callmeth(n, 0)
-		} else {
-			cgen_call(n, 0)
-		}
-		if r >= 0 {
-			reg[r]++
-		}
-		cgen_aret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_aret(n, res)
-
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_slice(n, &n1)
-		agen(&n1, res)
-
-	case gc.OEFACE:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_eface(n, &n1)
-		agen(&n1, res)
-
-	case gc.OINDEX:
-		var n1 gc.Node
-		agenr(n, &n1, res)
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// should only get here with names in this func.
-	case gc.ONAME:
-		if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth)
-		}
-
-		// should only get here for heap vars or paramref
-		if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME class %#x", n.Class)
-		}
-
-		cgen(n.Heapaddr, res)
-		if n.Xoffset != 0 {
-			var n1 gc.Node
-			gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset)
-			var n2 gc.Node
-			regalloc(&n2, n1.Type, nil)
-			var n3 gc.Node
-			regalloc(&n3, gc.Types[gc.TINT32], nil)
-			gmove(&n1, &n2)
-			gmove(res, &n3)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			gmove(&n3, res)
-			regfree(&n2)
-			regfree(&n3)
-		}
-
-	case gc.OIND:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-
-	case gc.ODOT:
-		agen(nl, res)
-		if n.Xoffset != 0 {
-			var n1 gc.Node
-			gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset)
-			var n2 gc.Node
-			regalloc(&n2, n1.Type, nil)
-			var n3 gc.Node
-			regalloc(&n3, gc.Types[gc.TINT32], nil)
-			gmove(&n1, &n2)
-			gmove(res, &n3)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			gmove(&n3, res)
-			regfree(&n2)
-			regfree(&n3)
-		}
-
-	case gc.ODOTPTR:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-		if n.Xoffset != 0 {
-			var n1 gc.Node
-			gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset)
-			var n2 gc.Node
-			regalloc(&n2, n1.Type, nil)
-			var n3 gc.Node
-			regalloc(&n3, gc.Types[gc.Tptr], nil)
-			gmove(&n1, &n2)
-			gmove(res, &n3)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			gmove(&n3, res)
-			regfree(&n2)
-			regfree(&n3)
-		}
-	}
-}
-
-/*
- * generate:
- *	newreg = &n;
- *	res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- * The generated code checks that the result is not *nil.
- */
-func igen(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nigen-n", n)
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF {
-			break
-		}
-		*a = *n
-		return
-
-		// Increase the refcount of the register so that igen's caller
-	// has to call regfree.
-	case gc.OINDREG:
-		if n.Val.U.Reg != arm.REGSP {
-			reg[n.Val.U.Reg]++
-		}
-		*a = *n
-		return
-
-	case gc.ODOT:
-		igen(n.Left, a, res)
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		return
-
-	case gc.ODOTPTR:
-		if n.Left.Addable != 0 || n.Left.Op == gc.OCALLFUNC || n.Left.Op == gc.OCALLMETH || n.Left.Op == gc.OCALLINTER {
-			// igen-able nodes.
-			var n1 gc.Node
-			igen(n.Left, &n1, res)
-
-			regalloc(a, gc.Types[gc.Tptr], &n1)
-			gmove(&n1, a)
-			regfree(&n1)
-		} else {
-			regalloc(a, gc.Types[gc.Tptr], res)
-			cgen(n.Left, a)
-		}
-
-		gc.Cgen_checknil(a)
-		a.Op = gc.OINDREG
-		a.Xoffset = n.Xoffset
-		a.Type = n.Type
-		return
-
-		// Release res so that it is available for cgen_call.
-	// Pick it up again after the call.
-	case gc.OCALLMETH,
-		gc.OCALLFUNC,
-		gc.OCALLINTER:
-		r := -1
-
-		if n.Ullman >= gc.UINF {
-			if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) {
-				r = int(res.Val.U.Reg)
-				reg[r]--
-			}
-		}
-
-		switch n.Op {
-		case gc.OCALLMETH:
-			gc.Cgen_callmeth(n, 0)
-
-		case gc.OCALLFUNC:
-			cgen_call(n, 0)
-
-		case gc.OCALLINTER:
-			cgen_callinter(n, nil, 0)
-		}
-
-		if r >= 0 {
-			reg[r]++
-		}
-		regalloc(a, gc.Types[gc.Tptr], res)
-		cgen_aret(n, a)
-		a.Op = gc.OINDREG
-		a.Type = n.Type
-		return
-	}
-
-	agenr(n, a, res)
-	a.Op = gc.OINDREG
-	a.Type = n.Type
-}
-
-/*
- * allocate a register in res and generate
- *  newreg = &n
- * The caller must call regfree(a).
- */
-func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("cgenr-n", n)
-	}
-
-	if gc.Isfat(n.Type) {
-		gc.Fatal("cgenr on fat node")
-	}
-
-	if n.Addable != 0 {
-		regalloc(a, gc.Types[gc.Tptr], res)
-		gmove(n, a)
-		return
-	}
-
-	switch n.Op {
-	case gc.ONAME,
-		gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		var n1 gc.Node
-		igen(n, &n1, res)
-		regalloc(a, gc.Types[gc.Tptr], &n1)
-		gmove(&n1, a)
-		regfree(&n1)
-
-	default:
-		regalloc(a, n.Type, res)
-		cgen(n, a)
-	}
-}
-
-/*
- * generate:
- *	newreg = &n;
- *
- * caller must regfree(a).
- * The generated code checks that the result is not nil.
- */
-func agenr(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("agenr-n", n)
-	}
-
-	nl := n.Left
-	nr := n.Right
-
-	switch n.Op {
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		var n1 gc.Node
-		igen(n, &n1, res)
-		regalloc(a, gc.Types[gc.Tptr], &n1)
-		agen(&n1, a)
-		regfree(&n1)
-
-	case gc.OIND:
-		cgenr(n.Left, a, res)
-		gc.Cgen_checknil(a)
-
-	case gc.OINDEX:
-		var p2 *obj.Prog // to be patched to panicindex.
-		w := uint32(n.Type.Width)
-		bounded := gc.Debug['B'] != 0 || n.Bounded
-		var n1 gc.Node
-		var n3 gc.Node
-		if nr.Addable != 0 {
-			var tmp gc.Node
-			if !gc.Isconst(nr, gc.CTINT) {
-				gc.Tempname(&tmp, gc.Types[gc.TINT32])
-			}
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-			if !gc.Isconst(nr, gc.CTINT) {
-				p2 = cgenindex(nr, &tmp, bounded)
-				regalloc(&n1, tmp.Type, nil)
-				gmove(&tmp, &n1)
-			}
-		} else if nl.Addable != 0 {
-			if !gc.Isconst(nr, gc.CTINT) {
-				var tmp gc.Node
-				gc.Tempname(&tmp, gc.Types[gc.TINT32])
-				p2 = cgenindex(nr, &tmp, bounded)
-				regalloc(&n1, tmp.Type, nil)
-				gmove(&tmp, &n1)
-			}
-
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-		} else {
-			var tmp gc.Node
-			gc.Tempname(&tmp, gc.Types[gc.TINT32])
-			p2 = cgenindex(nr, &tmp, bounded)
-			nr = &tmp
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-			regalloc(&n1, tmp.Type, nil)
-			gins(optoas(gc.OAS, tmp.Type), &tmp, &n1)
-		}
-
-		// &a is in &n3 (allocated in res)
-		// i is in &n1 (if not constant)
-		// w is width
-
-		// constant index
-		if gc.Isconst(nr, gc.CTINT) {
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Fatal("constant string constant index")
-			}
-			v := uint64(gc.Mpgetfix(nr.Val.U.Xval))
-			var n2 gc.Node
-			if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				if gc.Debug['B'] == 0 && !n.Bounded {
-					n1 = n3
-					n1.Op = gc.OINDREG
-					n1.Type = gc.Types[gc.Tptr]
-					n1.Xoffset = int64(gc.Array_nel)
-					var n4 gc.Node
-					regalloc(&n4, n1.Type, nil)
-					gmove(&n1, &n4)
-					gc.Nodconst(&n2, gc.Types[gc.TUINT32], int64(v))
-					gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n4, &n2)
-					regfree(&n4)
-					p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1)
-					ginscall(gc.Panicindex, 0)
-					gc.Patch(p1, gc.Pc)
-				}
-
-				n1 = n3
-				n1.Op = gc.OINDREG
-				n1.Type = gc.Types[gc.Tptr]
-				n1.Xoffset = int64(gc.Array_array)
-				gmove(&n1, &n3)
-			}
-
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], int64(v*uint64(w)))
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			*a = n3
-			break
-		}
-
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.TINT32], &n1) // i
-		gmove(&n1, &n2)
-		regfree(&n1)
-
-		var n4 gc.Node
-		if gc.Debug['B'] == 0 && !n.Bounded {
-			// check bounds
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Nodconst(&n4, gc.Types[gc.TUINT32], int64(len(nl.Val.U.Sval)))
-			} else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				n1 = n3
-				n1.Op = gc.OINDREG
-				n1.Type = gc.Types[gc.Tptr]
-				n1.Xoffset = int64(gc.Array_nel)
-				regalloc(&n4, gc.Types[gc.TUINT32], nil)
-				gmove(&n1, &n4)
-			} else {
-				gc.Nodconst(&n4, gc.Types[gc.TUINT32], nl.Type.Bound)
-			}
-
-			gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n2, &n4)
-			if n4.Op == gc.OREGISTER {
-				regfree(&n4)
-			}
-			p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
-			if p2 != nil {
-				gc.Patch(p2, gc.Pc)
-			}
-			ginscall(gc.Panicindex, 0)
-			gc.Patch(p1, gc.Pc)
-		}
-
-		if gc.Isconst(nl, gc.CTSTR) {
-			regalloc(&n3, gc.Types[gc.Tptr], res)
-			p1 := gins(arm.AMOVW, nil, &n3)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			p1.From.Type = obj.TYPE_ADDR
-		} else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-			n1 = n3
-			n1.Op = gc.OINDREG
-			n1.Type = gc.Types[gc.Tptr]
-			n1.Xoffset = int64(gc.Array_array)
-			gmove(&n1, &n3)
-		}
-
-		if w == 0 {
-		} else // nothing to do
-		if w == 1 || w == 2 || w == 4 || w == 8 {
-			n4 = gc.Node{}
-			n4.Op = gc.OADDR
-			n4.Left = &n2
-			cgen(&n4, &n3)
-			if w == 1 {
-				gins(arm.AADD, &n2, &n3)
-			} else if w == 2 {
-				gshift(arm.AADD, &n2, arm.SHIFT_LL, 1, &n3)
-			} else if w == 4 {
-				gshift(arm.AADD, &n2, arm.SHIFT_LL, 2, &n3)
-			} else if w == 8 {
-				gshift(arm.AADD, &n2, arm.SHIFT_LL, 3, &n3)
-			}
-		} else {
-			regalloc(&n4, gc.Types[gc.TUINT32], nil)
-			gc.Nodconst(&n1, gc.Types[gc.TUINT32], int64(w))
-			gmove(&n1, &n4)
-			gins(optoas(gc.OMUL, gc.Types[gc.TUINT32]), &n4, &n2)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			regfree(&n4)
-		}
-
-		*a = n3
-		regfree(&n2)
-
-	default:
-		regalloc(a, gc.Types[gc.Tptr], res)
-		agen(n, a)
-	}
+func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
+	gc.Tempname(res, n.Type)
+	return cgenindex(n, res, bounded)
 }
 
 func gencmp0(n *gc.Node, t *gc.Type, o int, likely int, to *obj.Prog) {
 	var n1 gc.Node
 
-	regalloc(&n1, t, nil)
-	cgen(n, &n1)
+	gc.Regalloc(&n1, t, nil)
+	gc.Cgen(n, &n1)
 	a := optoas(gc.OCMP, t)
 	if a != arm.ACMP {
 		var n2 gc.Node
 		gc.Nodconst(&n2, t, 0)
 		var n3 gc.Node
-		regalloc(&n3, t, nil)
+		gc.Regalloc(&n3, t, nil)
 		gmove(&n2, &n3)
-		gcmp(a, &n1, &n3)
-		regfree(&n3)
+		gins(a, &n1, &n3)
+		gc.Regfree(&n3)
 	} else {
 		gins(arm.ATST, &n1, nil)
 	}
 	a = optoas(o, t)
 	gc.Patch(gc.Gbranch(a, t, likely), to)
-	regfree(&n1)
+	gc.Regfree(&n1)
 }
 
-/*
- * generate:
- *	if(n == true) goto to;
- */
-func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nbgen", n)
-	}
-
-	if n == nil {
-		n = gc.Nodbool(true)
-	}
-
-	if n.Ninit != nil {
-		gc.Genlist(n.Ninit)
-	}
-
-	if n.Type == nil {
-		gc.Convlit(&n, gc.Types[gc.TBOOL])
-		if n.Type == nil {
-			return
-		}
-	}
-
-	et := int(n.Type.Etype)
-	if et != gc.TBOOL {
-		gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0))
-		gc.Patch(gins(obj.AEND, nil, nil), to)
-		return
-	}
-
-	var nr *gc.Node
-
-	var nl *gc.Node
-	switch n.Op {
-	default:
-		a := gc.ONE
-		if !true_ {
-			a = gc.OEQ
-		}
-		gencmp0(n, n.Type, a, likely, to)
-		return
-
-		// need to ask if it is bool?
-	case gc.OLITERAL:
-		if !true_ == (n.Val.U.Bval == 0) {
-			gc.Patch(gc.Gbranch(arm.AB, nil, 0), to)
-		}
-		return
-
-	case gc.OANDAND,
-		gc.OOROR:
-		if (n.Op == gc.OANDAND) == true_ {
-			p1 := gc.Gbranch(obj.AJMP, nil, 0)
-			p2 := gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, gc.Pc)
-			bgen(n.Left, !true_, -likely, p2)
-			bgen(n.Right, !true_, -likely, p2)
-			p1 = gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, to)
-			gc.Patch(p2, gc.Pc)
-		} else {
-			bgen(n.Left, true_, likely, to)
-			bgen(n.Right, true_, likely, to)
-		}
-
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			return
-		}
-		fallthrough
-
-	case gc.ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
-			return
-		}
-	}
-
-	switch n.Op {
-	case gc.ONOT:
-		bgen(nl, !true_, likely, to)
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		a := int(n.Op)
-		if !true_ {
-			if gc.Isfloat[nl.Type.Etype] {
-				// brcom is not valid on floats when NaN is involved.
-				p1 := gc.Gbranch(arm.AB, nil, 0)
-
-				p2 := gc.Gbranch(arm.AB, nil, 0)
-				gc.Patch(p1, gc.Pc)
-				ll := n.Ninit
-				n.Ninit = nil
-				bgen(n, true, -likely, p2)
-				n.Ninit = ll
-				gc.Patch(gc.Gbranch(arm.AB, nil, 0), to)
-				gc.Patch(p2, gc.Pc)
-				return
-			}
-
-			a = gc.Brcom(a)
-			true_ = !true_
-		}
-
-		// make simplest on right
-		if nl.Op == gc.OLITERAL || (nl.Ullman < gc.UINF && nl.Ullman < nr.Ullman) {
-			a = gc.Brrev(a)
-			r := nl
-			nl = nr
-			nr = r
-		}
-
-		if gc.Isslice(nl.Type) {
-			// only valid to cmp darray to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal array comparison")
-				break
-			}
-
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Xoffset += int64(gc.Array_array)
-			n1.Type = gc.Types[gc.Tptr]
-			gencmp0(&n1, gc.Types[gc.Tptr], a, likely, to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isinter(nl.Type) {
-			// front end shold only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal interface comparison")
-				break
-			}
-
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Type = gc.Types[gc.Tptr]
-			n1.Xoffset += 0
-			gencmp0(&n1, gc.Types[gc.Tptr], a, likely, to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Iscomplex[nl.Type.Etype] {
-			gc.Complexbool(a, nl, nr, true_, likely, to)
-			break
-		}
-
-		if gc.Is64(nr.Type) {
-			if nl.Addable == 0 {
-				var n1 gc.Node
-				gc.Tempname(&n1, nl.Type)
-				cgen(nl, &n1)
-				nl = &n1
-			}
-
-			if nr.Addable == 0 {
-				var n2 gc.Node
-				gc.Tempname(&n2, nr.Type)
-				cgen(nr, &n2)
-				nr = &n2
-			}
-
-			cmp64(nl, nr, a, likely, to)
-			break
-		}
-
-		if nr.Op == gc.OLITERAL {
-			if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) == 0 {
-				gencmp0(nl, nl.Type, a, likely, to)
-				break
-			}
-
-			if nr.Val.Ctype == gc.CTNIL {
-				gencmp0(nl, nl.Type, a, likely, to)
-				break
-			}
-		}
-
-		a = optoas(a, nr.Type)
-
-		if nr.Ullman >= gc.UINF {
-			var n1 gc.Node
-			regalloc(&n1, nl.Type, nil)
-			cgen(nl, &n1)
-
-			var tmp gc.Node
-			gc.Tempname(&tmp, nl.Type)
-			gmove(&n1, &tmp)
-			regfree(&n1)
-
-			var n2 gc.Node
-			regalloc(&n2, nr.Type, nil)
-			cgen(nr, &n2)
-
-			regalloc(&n1, nl.Type, nil)
-			cgen(&tmp, &n1)
-
-			gcmp(optoas(gc.OCMP, nr.Type), &n1, &n2)
-			gc.Patch(gc.Gbranch(a, nr.Type, likely), to)
-
-			regfree(&n1)
-			regfree(&n2)
-			break
-		}
-
-		var n3 gc.Node
-		gc.Tempname(&n3, nl.Type)
-		cgen(nl, &n3)
-
-		var tmp gc.Node
-		gc.Tempname(&tmp, nr.Type)
-		cgen(nr, &tmp)
-
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, nil)
-		gmove(&n3, &n1)
-
-		var n2 gc.Node
-		regalloc(&n2, nr.Type, nil)
-		gmove(&tmp, &n2)
-
-		gcmp(optoas(gc.OCMP, nr.Type), &n1, &n2)
-		if gc.Isfloat[nl.Type.Etype] {
-			if n.Op == gc.ONE {
-				p1 := gc.Gbranch(arm.ABVS, nr.Type, likely)
-				gc.Patch(gc.Gbranch(a, nr.Type, likely), to)
-				gc.Patch(p1, to)
-			} else {
-				p1 := gc.Gbranch(arm.ABVS, nr.Type, -likely)
-				gc.Patch(gc.Gbranch(a, nr.Type, likely), to)
-				gc.Patch(p1, gc.Pc)
-			}
-		} else {
-			gc.Patch(gc.Gbranch(a, nr.Type, likely), to)
-		}
-
-		regfree(&n1)
-		regfree(&n2)
-	}
-
-	return
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-func stkof(n *gc.Node) int32 {
-	switch n.Op {
-	case gc.OINDREG:
-		return int32(n.Xoffset)
-
-	case gc.ODOT:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		return int32(int64(off) + n.Xoffset)
-
-	case gc.OINDEX:
-		t := n.Left.Type
-		if !gc.Isfixedarray(t) {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		if gc.Isconst(n.Right, gc.CTINT) {
-			return int32(int64(off) + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval))
-		}
-		return 1000
-
-	case gc.OCALLMETH,
-		gc.OCALLINTER,
-		gc.OCALLFUNC:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			t = t.Type
-		}
-
-		var flist gc.Iter
-		t = gc.Structfirst(&flist, gc.Getoutarg(t))
-		if t != nil {
-			return int32(t.Width + 4) // correct for LR
-		}
-	}
-
-	// botch - probably failing to recognize address
-	// arithmetic on the above. eg INDEX and DOT
-	return -1000
-}
-
-/*
- * block copy:
- *	memmove(&res, &n, w);
- * NB: character copy assumed little endian architecture
- */
-func sgen(n *gc.Node, res *gc.Node, w int64) {
-	if gc.Debug['g'] != 0 {
-		fmt.Printf("\nsgen w=%d\n", w)
-		gc.Dump("r", n)
-		gc.Dump("res", res)
-	}
-
-	if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF {
-		gc.Fatal("sgen UINF")
-	}
-
-	if w < 0 || int64(int32(w)) != w {
-		gc.Fatal("sgen copy %d", w)
-	}
-
-	if n.Type == nil {
-		gc.Fatal("sgen: missing type")
-	}
-
-	if w == 0 {
-		// evaluate side effects only.
-		var dst gc.Node
-		regalloc(&dst, gc.Types[gc.Tptr], nil)
-
-		agen(res, &dst)
-		agen(n, &dst)
-		regfree(&dst)
-		return
-	}
-
-	// If copying .args, that's all the results, so record definition sites
-	// for them for the liveness analysis.
-	if res.Op == gc.ONAME && res.Sym.Name == ".args" {
-		for l := gc.Curfn.Dcl; l != nil; l = l.Next {
-			if l.N.Class == gc.PPARAMOUT {
-				gc.Gvardef(l.N)
-			}
-		}
-	}
-
-	// Avoid taking the address for simple enough types.
-	if gc.Componentgen(n, res) {
-		return
-	}
-
+func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// determine alignment.
 	// want to avoid unaligned access, so have to use
 	// smaller operations for less aligned types.
@@ -1560,31 +102,13 @@
 	}
 	c := int32(w / int64(align))
 
-	// offset on the stack
-	osrc := stkof(n)
-
-	odst := stkof(res)
-	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
-		// osrc and odst both on stack, and at least one is in
-		// an unknown position.  Could generate code to test
-		// for forward/backward copy, but instead just copy
-		// to a temporary location first.
-		var tmp gc.Node
-		gc.Tempname(&tmp, n.Type)
-
-		sgen(n, &tmp, w)
-		sgen(&tmp, res, w)
-		return
-	}
-
-	if osrc%int32(align) != 0 || odst%int32(align) != 0 {
+	if osrc%int64(align) != 0 || odst%int64(align) != 0 {
 		gc.Fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align)
 	}
 
 	// if we are copying forward on the stack and
 	// the src and dst overlap, then reverse direction
 	dir := align
-
 	if osrc < odst && int64(odst) < int64(osrc)+w {
 		dir = -dir
 	}
@@ -1592,37 +116,37 @@
 	if op == arm.AMOVW && !gc.Nacl && dir > 0 && c >= 4 && c <= 128 {
 		var r0 gc.Node
 		r0.Op = gc.OREGISTER
-		r0.Val.U.Reg = REGALLOC_R0
+		r0.Val.U.Reg = arm.REG_R0
 		var r1 gc.Node
 		r1.Op = gc.OREGISTER
-		r1.Val.U.Reg = REGALLOC_R0 + 1
+		r1.Val.U.Reg = arm.REG_R0 + 1
 		var r2 gc.Node
 		r2.Op = gc.OREGISTER
-		r2.Val.U.Reg = REGALLOC_R0 + 2
+		r2.Val.U.Reg = arm.REG_R0 + 2
 
 		var src gc.Node
-		regalloc(&src, gc.Types[gc.Tptr], &r1)
+		gc.Regalloc(&src, gc.Types[gc.Tptr], &r1)
 		var dst gc.Node
-		regalloc(&dst, gc.Types[gc.Tptr], &r2)
+		gc.Regalloc(&dst, gc.Types[gc.Tptr], &r2)
 		if n.Ullman >= res.Ullman {
 			// eval n first
-			agen(n, &src)
+			gc.Agen(n, &src)
 
 			if res.Op == gc.ONAME {
 				gc.Gvardef(res)
 			}
-			agen(res, &dst)
+			gc.Agen(res, &dst)
 		} else {
 			// eval res first
 			if res.Op == gc.ONAME {
 				gc.Gvardef(res)
 			}
-			agen(res, &dst)
-			agen(n, &src)
+			gc.Agen(res, &dst)
+			gc.Agen(n, &src)
 		}
 
 		var tmp gc.Node
-		regalloc(&tmp, gc.Types[gc.Tptr], &r0)
+		gc.Regalloc(&tmp, gc.Types[gc.Tptr], &r0)
 		f := gc.Sysfunc("duffcopy")
 		p := gins(obj.ADUFFCOPY, nil, f)
 		gc.Afunclit(&p.To, f)
@@ -1630,38 +154,38 @@
 		// 8 and 128 = magic constants: see ../../runtime/asm_arm.s
 		p.To.Offset = 8 * (128 - int64(c))
 
-		regfree(&tmp)
-		regfree(&src)
-		regfree(&dst)
+		gc.Regfree(&tmp)
+		gc.Regfree(&src)
+		gc.Regfree(&dst)
 		return
 	}
 
 	var dst gc.Node
 	var src gc.Node
 	if n.Ullman >= res.Ullman {
-		agenr(n, &dst, res) // temporarily use dst
-		regalloc(&src, gc.Types[gc.Tptr], nil)
+		gc.Agenr(n, &dst, res) // temporarily use dst
+		gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
 		gins(arm.AMOVW, &dst, &src)
 		if res.Op == gc.ONAME {
 			gc.Gvardef(res)
 		}
-		agen(res, &dst)
+		gc.Agen(res, &dst)
 	} else {
 		if res.Op == gc.ONAME {
 			gc.Gvardef(res)
 		}
-		agenr(res, &dst, res)
-		agenr(n, &src, nil)
+		gc.Agenr(res, &dst, res)
+		gc.Agenr(n, &src, nil)
 	}
 
 	var tmp gc.Node
-	regalloc(&tmp, gc.Types[gc.TUINT32], nil)
+	gc.Regalloc(&tmp, gc.Types[gc.TUINT32], nil)
 
 	// set up end marker
 	var nend gc.Node
 
 	if c >= 4 {
-		regalloc(&nend, gc.Types[gc.TUINT32], nil)
+		gc.Regalloc(&nend, gc.Types[gc.TUINT32], nil)
 
 		p := gins(arm.AMOVW, &src, &nend)
 		p.From.Type = obj.TYPE_ADDR
@@ -1700,7 +224,7 @@
 		raddr(&nend, p)
 
 		gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), ploop)
-		regfree(&nend)
+		gc.Regfree(&nend)
 	} else {
 		var p *obj.Prog
 		for {
@@ -1721,7 +245,7 @@
 		}
 	}
 
-	regfree(&dst)
-	regfree(&src)
-	regfree(&tmp)
+	gc.Regfree(&dst)
+	gc.Regfree(&src)
+	gc.Regfree(&tmp)
 }
diff --git a/src/cmd/5g/cgen64.go b/src/cmd/5g/cgen64.go
index 8c2f360..05f2e1e 100644
--- a/src/cmd/5g/cgen64.go
+++ b/src/cmd/5g/cgen64.go
@@ -26,7 +26,7 @@
 	var t1 gc.Node
 	if l.Addable == 0 {
 		gc.Tempname(&t1, l.Type)
-		cgen(l, &t1)
+		gc.Cgen(l, &t1)
 		l = &t1
 	}
 
@@ -42,11 +42,11 @@
 		var hi2 gc.Node
 		split64(res, &lo2, &hi2)
 
-		regalloc(&t1, lo1.Type, nil)
+		gc.Regalloc(&t1, lo1.Type, nil)
 		var al gc.Node
-		regalloc(&al, lo1.Type, nil)
+		gc.Regalloc(&al, lo1.Type, nil)
 		var ah gc.Node
-		regalloc(&ah, hi1.Type, nil)
+		gc.Regalloc(&ah, hi1.Type, nil)
 
 		gins(arm.AMOVW, &lo1, &al)
 		gins(arm.AMOVW, &hi1, &ah)
@@ -60,22 +60,22 @@
 		gins(arm.ASBC, &ah, &t1)
 		gins(arm.AMOVW, &t1, &hi2)
 
-		regfree(&t1)
-		regfree(&al)
-		regfree(&ah)
+		gc.Regfree(&t1)
+		gc.Regfree(&al)
+		gc.Regfree(&ah)
 		splitclean()
 		splitclean()
 		return
 
 	case gc.OCOM:
-		regalloc(&t1, lo1.Type, nil)
+		gc.Regalloc(&t1, lo1.Type, nil)
 		gmove(ncon(^uint32(0)), &t1)
 
 		var lo2 gc.Node
 		var hi2 gc.Node
 		split64(res, &lo2, &hi2)
 		var n1 gc.Node
-		regalloc(&n1, lo1.Type, nil)
+		gc.Regalloc(&n1, lo1.Type, nil)
 
 		gins(arm.AMOVW, &lo1, &n1)
 		gins(arm.AEOR, &t1, &n1)
@@ -85,8 +85,8 @@
 		gins(arm.AEOR, &t1, &n1)
 		gins(arm.AMOVW, &n1, &hi2)
 
-		regfree(&t1)
-		regfree(&n1)
+		gc.Regfree(&t1)
+		gc.Regfree(&n1)
 		splitclean()
 		splitclean()
 		return
@@ -111,7 +111,7 @@
 	if r != nil && r.Addable == 0 {
 		var t2 gc.Node
 		gc.Tempname(&t2, r.Type)
-		cgen(r, &t2)
+		gc.Cgen(r, &t2)
 		r = &t2
 	}
 
@@ -122,9 +122,9 @@
 	}
 
 	var al gc.Node
-	regalloc(&al, lo1.Type, nil)
+	gc.Regalloc(&al, lo1.Type, nil)
 	var ah gc.Node
-	regalloc(&ah, hi1.Type, nil)
+	gc.Regalloc(&ah, hi1.Type, nil)
 
 	// Do op.  Leave result in ah:al.
 	switch n.Op {
@@ -134,10 +134,10 @@
 		// TODO: Constants
 	case gc.OADD:
 		var bl gc.Node
-		regalloc(&bl, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
 
 		var bh gc.Node
-		regalloc(&bh, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
 		gins(arm.AMOVW, &hi1, &ah)
 		gins(arm.AMOVW, &lo1, &al)
 		gins(arm.AMOVW, &hi2, &bh)
@@ -145,16 +145,16 @@
 		p1 := gins(arm.AADD, &bl, &al)
 		p1.Scond |= arm.C_SBIT
 		gins(arm.AADC, &bh, &ah)
-		regfree(&bl)
-		regfree(&bh)
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
 
 		// TODO: Constants.
 	case gc.OSUB:
 		var bl gc.Node
-		regalloc(&bl, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
 
 		var bh gc.Node
-		regalloc(&bh, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
 		gins(arm.AMOVW, &lo1, &al)
 		gins(arm.AMOVW, &hi1, &ah)
 		gins(arm.AMOVW, &lo2, &bl)
@@ -162,20 +162,20 @@
 		p1 := gins(arm.ASUB, &bl, &al)
 		p1.Scond |= arm.C_SBIT
 		gins(arm.ASBC, &bh, &ah)
-		regfree(&bl)
-		regfree(&bh)
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
 
 		// TODO(kaib): this can be done with 4 regs and does not need 6
 	case gc.OMUL:
 		var bl gc.Node
-		regalloc(&bl, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
 
 		var bh gc.Node
-		regalloc(&bh, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
 		var cl gc.Node
-		regalloc(&cl, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&cl, gc.Types[gc.TPTR32], nil)
 		var ch gc.Node
-		regalloc(&ch, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&ch, gc.Types[gc.TPTR32], nil)
 
 		// load args into bh:bl and bh:bl.
 		gins(arm.AMOVW, &hi1, &bh)
@@ -220,11 +220,11 @@
 
 		//print("%P\n", p1);
 
-		regfree(&bh)
+		gc.Regfree(&bh)
 
-		regfree(&bl)
-		regfree(&ch)
-		regfree(&cl)
+		gc.Regfree(&bl)
+		gc.Regfree(&ch)
+		gc.Regfree(&cl)
 
 		// We only rotate by a constant c in [0,64).
 	// if c >= 32:
@@ -240,9 +240,9 @@
 		v := uint64(gc.Mpgetfix(r.Val.U.Xval))
 
 		var bl gc.Node
-		regalloc(&bl, lo1.Type, nil)
+		gc.Regalloc(&bl, lo1.Type, nil)
 		var bh gc.Node
-		regalloc(&bh, hi1.Type, nil)
+		gc.Regalloc(&bh, hi1.Type, nil)
 		if v >= 32 {
 			// reverse during load to do the first 32 bits of rotate
 			v -= 32
@@ -270,14 +270,14 @@
 			gshift(arm.AORR, &bh, arm.SHIFT_LR, int32(32-v), &al)
 		}
 
-		regfree(&bl)
-		regfree(&bh)
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
 
 	case gc.OLSH:
 		var bl gc.Node
-		regalloc(&bl, lo1.Type, nil)
+		gc.Regalloc(&bl, lo1.Type, nil)
 		var bh gc.Node
-		regalloc(&bh, hi1.Type, nil)
+		gc.Regalloc(&bh, hi1.Type, nil)
 		gins(arm.AMOVW, &hi1, &bh)
 		gins(arm.AMOVW, &lo1, &bl)
 
@@ -323,8 +323,8 @@
 			goto olsh_break
 		}
 
-		regalloc(&s, gc.Types[gc.TUINT32], nil)
-		regalloc(&creg, gc.Types[gc.TUINT32], nil)
+		gc.Regalloc(&s, gc.Types[gc.TUINT32], nil)
+		gc.Regalloc(&creg, gc.Types[gc.TUINT32], nil)
 		if gc.Is64(r.Type) {
 			// shift is >= 1<<32
 			var cl gc.Node
@@ -355,7 +355,7 @@
 		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32)
 
 		gmove(&n1, &creg)
-		gcmp(arm.ACMP, &s, &creg)
+		gins(arm.ACMP, &s, &creg)
 
 		//	MOVW.LO		bl<<s, al
 		p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &al)
@@ -392,7 +392,7 @@
 		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64)
 
 		gmove(&n1, &creg)
-		gcmp(arm.ACMP, &s, &creg)
+		gins(arm.ACMP, &s, &creg)
 
 		//	EOR.LO	al, al
 		p1 = gins(arm.AEOR, &al, &al)
@@ -427,18 +427,18 @@
 		gc.Patch(p3, gc.Pc)
 		gc.Patch(p4, gc.Pc)
 		gc.Patch(p5, gc.Pc)
-		regfree(&s)
-		regfree(&creg)
+		gc.Regfree(&s)
+		gc.Regfree(&creg)
 
 	olsh_break:
-		regfree(&bl)
-		regfree(&bh)
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
 
 	case gc.ORSH:
 		var bl gc.Node
-		regalloc(&bl, lo1.Type, nil)
+		gc.Regalloc(&bl, lo1.Type, nil)
 		var bh gc.Node
-		regalloc(&bh, hi1.Type, nil)
+		gc.Regalloc(&bh, hi1.Type, nil)
 		gins(arm.AMOVW, &hi1, &bh)
 		gins(arm.AMOVW, &lo1, &bl)
 
@@ -507,8 +507,8 @@
 			goto orsh_break
 		}
 
-		regalloc(&s, gc.Types[gc.TUINT32], nil)
-		regalloc(&creg, gc.Types[gc.TUINT32], nil)
+		gc.Regalloc(&s, gc.Types[gc.TUINT32], nil)
+		gc.Regalloc(&creg, gc.Types[gc.TUINT32], nil)
 		if gc.Is64(r.Type) {
 			// shift is >= 1<<32
 			var ch gc.Node
@@ -546,7 +546,7 @@
 		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32)
 
 		gmove(&n1, &creg)
-		gcmp(arm.ACMP, &s, &creg)
+		gins(arm.ACMP, &s, &creg)
 
 		//	MOVW.LO		bl>>s, al
 		p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LR, &s, &al)
@@ -591,7 +591,7 @@
 		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64)
 
 		gmove(&n1, &creg)
-		gcmp(arm.ACMP, &s, &creg)
+		gins(arm.ACMP, &s, &creg)
 
 		//	MOVW.LO		creg>>1, creg
 		p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg)
@@ -633,12 +633,12 @@
 		gc.Patch(p3, gc.Pc)
 		gc.Patch(p4, gc.Pc)
 		gc.Patch(p5, gc.Pc)
-		regfree(&s)
-		regfree(&creg)
+		gc.Regfree(&s)
+		gc.Regfree(&creg)
 
 	orsh_break:
-		regfree(&bl)
-		regfree(&bh)
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
 
 		// TODO(kaib): literal optimizations
 	// make constant the right side (it usually is anyway).
@@ -736,7 +736,7 @@
 		gc.OAND,
 		gc.OOR:
 		var n1 gc.Node
-		regalloc(&n1, lo1.Type, nil)
+		gc.Regalloc(&n1, lo1.Type, nil)
 
 		gins(arm.AMOVW, &lo1, &al)
 		gins(arm.AMOVW, &hi1, &ah)
@@ -744,7 +744,7 @@
 		gins(optoas(int(n.Op), lo1.Type), &n1, &al)
 		gins(arm.AMOVW, &hi2, &n1)
 		gins(optoas(int(n.Op), lo1.Type), &n1, &ah)
-		regfree(&n1)
+		gc.Regfree(&n1)
 	}
 
 	if gc.Is64(r.Type) {
@@ -758,9 +758,9 @@
 	splitclean()
 
 	//out:
-	regfree(&al)
+	gc.Regfree(&al)
 
-	regfree(&ah)
+	gc.Regfree(&ah)
 }
 
 /*
@@ -782,13 +782,13 @@
 	// if they differ, we're done.
 	t := hi1.Type
 
-	regalloc(&r1, gc.Types[gc.TINT32], nil)
-	regalloc(&r2, gc.Types[gc.TINT32], nil)
+	gc.Regalloc(&r1, gc.Types[gc.TINT32], nil)
+	gc.Regalloc(&r2, gc.Types[gc.TINT32], nil)
 	gins(arm.AMOVW, &hi1, &r1)
 	gins(arm.AMOVW, &hi2, &r2)
-	gcmp(arm.ACMP, &r1, &r2)
-	regfree(&r1)
-	regfree(&r2)
+	gins(arm.ACMP, &r1, &r2)
+	gc.Regfree(&r1)
+	gc.Regfree(&r2)
 
 	var br *obj.Prog
 	switch op {
@@ -838,13 +838,13 @@
 	// compare least significant word
 	t = lo1.Type
 
-	regalloc(&r1, gc.Types[gc.TINT32], nil)
-	regalloc(&r2, gc.Types[gc.TINT32], nil)
+	gc.Regalloc(&r1, gc.Types[gc.TINT32], nil)
+	gc.Regalloc(&r2, gc.Types[gc.TINT32], nil)
 	gins(arm.AMOVW, &lo1, &r1)
 	gins(arm.AMOVW, &lo2, &r2)
-	gcmp(arm.ACMP, &r1, &r2)
-	regfree(&r1)
-	regfree(&r2)
+	gins(arm.ACMP, &r1, &r2)
+	gc.Regfree(&r1)
+	gc.Regfree(&r2)
 
 	// jump again
 	gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
diff --git a/src/cmd/5g/galign.go b/src/cmd/5g/galign.go
index c565550..1b349e1 100644
--- a/src/cmd/5g/galign.go
+++ b/src/cmd/5g/galign.go
@@ -45,33 +45,40 @@
 	gc.Thearch.Typedefs = typedefs
 	gc.Thearch.REGSP = arm.REGSP
 	gc.Thearch.REGCTXT = arm.REGCTXT
+	gc.Thearch.REGCALLX = arm.REG_R1
+	gc.Thearch.REGCALLX2 = arm.REG_R2
+	gc.Thearch.REGRETURN = arm.REG_R0
+	gc.Thearch.REGMIN = arm.REG_R0
+	gc.Thearch.REGMAX = arm.REGEXT
+	gc.Thearch.FREGMIN = arm.REG_F0
+	gc.Thearch.FREGMAX = arm.FREGEXT
 	gc.Thearch.MAXWIDTH = MAXWIDTH
-	gc.Thearch.Anyregalloc = anyregalloc
+	gc.Thearch.ReservedRegs = resvd
+
 	gc.Thearch.Betypeinit = betypeinit
-	gc.Thearch.Bgen = bgen
-	gc.Thearch.Cgen = cgen
-	gc.Thearch.Cgen_call = cgen_call
-	gc.Thearch.Cgen_callinter = cgen_callinter
-	gc.Thearch.Cgen_ret = cgen_ret
+	gc.Thearch.Cgen64 = cgen64
+	gc.Thearch.Cgen_hmul = cgen_hmul
+	gc.Thearch.Cgen_shift = cgen_shift
 	gc.Thearch.Clearfat = clearfat
+	gc.Thearch.Cmp64 = cmp64
 	gc.Thearch.Defframe = defframe
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
-	gc.Thearch.Gclean = gclean
-	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
-	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
-	gc.Thearch.Igen = igen
+	gc.Thearch.Cgenindex = cgenindex
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
 	gc.Thearch.Proginfo = proginfo
-	gc.Thearch.Regalloc = regalloc
-	gc.Thearch.Regfree = regfree
 	gc.Thearch.Regtyp = regtyp
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
+	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Sudoaddable = sudoaddable
+	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
 	gc.Thearch.RtoB = RtoB
 	gc.Thearch.FtoB = RtoB
diff --git a/src/cmd/5g/gg.go b/src/cmd/5g/gg.go
deleted file mode 100644
index 7a7fb3b..0000000
--- a/src/cmd/5g/gg.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import "cmd/internal/obj/arm"
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-const (
-	REGALLOC_R0   = arm.REG_R0
-	REGALLOC_RMAX = arm.REGEXT
-	REGALLOC_F0   = arm.REG_F0
-	REGALLOC_FMAX = arm.FREGEXT
-)
-
-var reg [REGALLOC_FMAX + 1]uint8
-
-/*
- * cgen
- */
-
-/*
- * list.c
- */
-
-/*
- * reg.c
- */
diff --git a/src/cmd/5g/ggen.go b/src/cmd/5g/ggen.go
index 6eb9501..0fc6297 100644
--- a/src/cmd/5g/ggen.go
+++ b/src/cmd/5g/ggen.go
@@ -115,324 +115,6 @@
 }
 
 /*
- * generate:
- *	call f
- *	proc=-1	normal call but no return
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
-  *	proc=3	normal call to C pointer (not Go func value)
-*/
-func ginscall(f *gc.Node, proc int) {
-	if f.Type != nil {
-		extra := int32(0)
-		if proc == 1 || proc == 2 {
-			extra = 2 * int32(gc.Widthptr)
-		}
-		gc.Setmaxarg(f.Type, extra)
-	}
-
-	switch proc {
-	default:
-		gc.Fatal("ginscall: bad proc %d", proc)
-
-	case 0, // normal call
-		-1: // normal call but no return
-		if f.Op == gc.ONAME && f.Class == gc.PFUNC {
-			if f == gc.Deferreturn {
-				// Deferred calls will appear to be returning to
-				// the BL deferreturn(SB) that we are about to emit.
-				// However, the stack trace code will show the line
-				// of the instruction before that return PC.
-				// To avoid that instruction being an unrelated instruction,
-				// insert a NOP so that we will have the right line number.
-				// ARM NOP 0x00000000 is really AND.EQ R0, R0, R0.
-				// Use the latter form because the NOP pseudo-instruction
-				// would be removed by the linker.
-				var r gc.Node
-				gc.Nodreg(&r, gc.Types[gc.TINT], arm.REG_R0)
-
-				p := gins(arm.AAND, &r, &r)
-				p.Scond = arm.C_SCOND_EQ
-			}
-
-			p := gins(arm.ABL, nil, f)
-			gc.Afunclit(&p.To, f)
-			if proc == -1 || gc.Noreturn(p) {
-				gins(obj.AUNDEF, nil, nil)
-			}
-			break
-		}
-
-		var r gc.Node
-		gc.Nodreg(&r, gc.Types[gc.Tptr], arm.REG_R7)
-		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[gc.Tptr], arm.REG_R1)
-		gmove(f, &r)
-		r.Op = gc.OINDREG
-		gmove(&r, &r1)
-		r.Op = gc.OREGISTER
-		r1.Op = gc.OINDREG
-		gins(arm.ABL, &r, &r1)
-
-	case 3: // normal call of c function pointer
-		gins(arm.ABL, nil, f)
-
-	case 1, // call in new proc (go)
-		2: // deferred call (defer)
-		var r gc.Node
-		regalloc(&r, gc.Types[gc.Tptr], nil)
-
-		var con gc.Node
-		gc.Nodconst(&con, gc.Types[gc.TINT32], int64(gc.Argsize(f.Type)))
-		gins(arm.AMOVW, &con, &r)
-		p := gins(arm.AMOVW, &r, nil)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = arm.REGSP
-		p.To.Offset = 4
-
-		gins(arm.AMOVW, f, &r)
-		p = gins(arm.AMOVW, &r, nil)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = arm.REGSP
-		p.To.Offset = 8
-
-		regfree(&r)
-
-		if proc == 1 {
-			ginscall(gc.Newproc, 0)
-		} else {
-			ginscall(gc.Deferproc, 0)
-		}
-
-		if proc == 2 {
-			gc.Nodconst(&con, gc.Types[gc.TINT32], 0)
-			p := gins(arm.ACMP, &con, nil)
-			p.Reg = arm.REG_R0
-			p = gc.Gbranch(arm.ABEQ, nil, +1)
-			cgen_ret(nil)
-			gc.Patch(p, gc.Pc)
-		}
-	}
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-func cgen_callinter(n *gc.Node, res *gc.Node, proc int) {
-	i := n.Left
-	if i.Op != gc.ODOTINTER {
-		gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0))
-	}
-
-	f := i.Right // field
-	if f.Op != gc.ONAME {
-		gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0))
-	}
-
-	i = i.Left // interface
-
-	// Release res register during genlist and cgen,
-	// which might have their own function calls.
-	r := -1
-
-	if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) {
-		r = int(res.Val.U.Reg)
-		reg[r]--
-	}
-
-	if i.Addable == 0 {
-		var tmpi gc.Node
-		gc.Tempname(&tmpi, i.Type)
-		cgen(i, &tmpi)
-		i = &tmpi
-	}
-
-	gc.Genlist(n.List) // args
-	if r >= 0 {
-		reg[r]++
-	}
-
-	var nodr gc.Node
-	regalloc(&nodr, gc.Types[gc.Tptr], res)
-	var nodo gc.Node
-	regalloc(&nodo, gc.Types[gc.Tptr], &nodr)
-	nodo.Op = gc.OINDREG
-
-	agen(i, &nodr) // REG = &inter
-
-	var nodsp gc.Node
-	gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], arm.REGSP)
-
-	nodsp.Xoffset = int64(gc.Widthptr)
-	if proc != 0 {
-		nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn
-	}
-	nodo.Xoffset += int64(gc.Widthptr)
-	cgen(&nodo, &nodsp) // {4 or 12}(SP) = 4(REG) -- i.data
-
-	nodo.Xoffset -= int64(gc.Widthptr)
-
-	cgen(&nodo, &nodr)      // REG = 0(REG) -- i.tab
-	gc.Cgen_checknil(&nodr) // in case offset is huge
-
-	nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8
-
-	if proc == 0 {
-		// plain call: use direct c function pointer - more efficient
-		cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f]
-		nodr.Op = gc.OINDREG
-		proc = 3
-	} else {
-		// go/defer. generate go func value.
-		p := gins(arm.AMOVW, &nodo, &nodr)
-
-		p.From.Type = obj.TYPE_ADDR // REG = &(20+offset(REG)) -- i.tab->fun[f]
-	}
-
-	nodr.Type = n.Left.Type
-	ginscall(&nodr, proc)
-
-	regfree(&nodr)
-	regfree(&nodo)
-}
-
-/*
- * generate function call;
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
- */
-func cgen_call(n *gc.Node, proc int) {
-	if n == nil {
-		return
-	}
-
-	var afun gc.Node
-	if n.Left.Ullman >= gc.UINF {
-		// if name involves a fn call
-		// precompute the address of the fn
-		gc.Tempname(&afun, gc.Types[gc.Tptr])
-
-		cgen(n.Left, &afun)
-	}
-
-	gc.Genlist(n.List) // assign the args
-	t := n.Left.Type
-
-	// call tempname pointer
-	if n.Left.Ullman >= gc.UINF {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, &afun)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call pointer
-	if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, n.Left)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call direct
-	n.Left.Method = 1
-
-	ginscall(n.Left, proc)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = return value from call.
- */
-func cgen_callret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_callret: nil")
-	}
-
-	var nod gc.Node
-	nod.Op = gc.OINDREG
-	nod.Val.U.Reg = arm.REGSP
-	nod.Addable = 1
-
-	nod.Xoffset = fp.Width + 4 // +4: saved lr at 0(SP)
-	nod.Type = fp.Type
-	gc.Cgen_as(res, &nod)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = &return value from call.
- */
-func cgen_aret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if gc.Isptr[t.Etype] {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	var nod1 gc.Node
-	nod1.Op = gc.OINDREG
-	nod1.Val.U.Reg = arm.REGSP
-	nod1.Addable = 1
-
-	nod1.Xoffset = fp.Width + 4 // +4: saved lr at 0(SP)
-	nod1.Type = fp.Type
-
-	if res.Op != gc.OREGISTER {
-		var nod2 gc.Node
-		regalloc(&nod2, gc.Types[gc.Tptr], res)
-		agen(&nod1, &nod2)
-		gins(arm.AMOVW, &nod2, res)
-		regfree(&nod2)
-	} else {
-		agen(&nod1, res)
-	}
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-func cgen_ret(n *gc.Node) {
-	if n != nil {
-		gc.Genlist(n.List) // copy out args
-	}
-	if gc.Hasdefer != 0 {
-		ginscall(gc.Deferreturn, 0)
-	}
-	gc.Genlist(gc.Curfn.Exit)
-	p := gins(obj.ARET, nil, nil)
-	if n != nil && n.Op == gc.ORETJMP {
-		p.To.Name = obj.NAME_EXTERN
-		p.To.Type = obj.TYPE_ADDR
-		p.To.Sym = gc.Linksym(n.Left.Sym)
-	}
-}
-
-/*
  * generate high multiply
  *  res = (nl * nr) >> wordsize
  */
@@ -446,11 +128,11 @@
 	t := nl.Type
 	w := int(t.Width * 8)
 	var n1 gc.Node
-	regalloc(&n1, t, res)
-	cgen(nl, &n1)
+	gc.Regalloc(&n1, t, res)
+	gc.Cgen(nl, &n1)
 	var n2 gc.Node
-	regalloc(&n2, t, nil)
-	cgen(nr, &n2)
+	gc.Regalloc(&n2, t, nil)
+	gc.Cgen(nr, &n2)
 	switch gc.Simtype[t.Etype] {
 	case gc.TINT8,
 		gc.TINT16:
@@ -483,9 +165,9 @@
 		gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
 	}
 
-	cgen(&n1, res)
-	regfree(&n1)
-	regfree(&n2)
+	gc.Cgen(&n1, res)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 /*
@@ -503,31 +185,31 @@
 	if op == gc.OLROT {
 		v := int(gc.Mpgetfix(nr.Val.U.Xval))
 		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
+		gc.Regalloc(&n1, nl.Type, res)
 		if w == 32 {
-			cgen(nl, &n1)
+			gc.Cgen(nl, &n1)
 			gshift(arm.AMOVW, &n1, arm.SHIFT_RR, int32(w)-int32(v), &n1)
 		} else {
 			var n2 gc.Node
-			regalloc(&n2, nl.Type, nil)
-			cgen(nl, &n2)
+			gc.Regalloc(&n2, nl.Type, nil)
+			gc.Cgen(nl, &n2)
 			gshift(arm.AMOVW, &n2, arm.SHIFT_LL, int32(v), &n1)
 			gshift(arm.AORR, &n2, arm.SHIFT_LR, int32(w)-int32(v), &n1)
-			regfree(&n2)
+			gc.Regfree(&n2)
 
 			// Ensure sign/zero-extended result.
 			gins(optoas(gc.OAS, nl.Type), &n1, &n1)
 		}
 
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
 	if nr.Op == gc.OLITERAL {
 		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-		cgen(nl, &n1)
+		gc.Regalloc(&n1, nl.Type, res)
+		gc.Cgen(nl, &n1)
 		sc := uint64(gc.Mpgetfix(nr.Val.U.Xval))
 		if sc == 0 {
 		} else // nothing to do
@@ -551,7 +233,7 @@
 			gins(optoas(gc.OAS, nl.Type), &n1, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
@@ -564,21 +246,21 @@
 		var nt gc.Node
 		gc.Tempname(&nt, nr.Type)
 		if nl.Ullman >= nr.Ullman {
-			regalloc(&n2, nl.Type, res)
-			cgen(nl, &n2)
-			cgen(nr, &nt)
+			gc.Regalloc(&n2, nl.Type, res)
+			gc.Cgen(nl, &n2)
+			gc.Cgen(nr, &nt)
 			n1 = nt
 		} else {
-			cgen(nr, &nt)
-			regalloc(&n2, nl.Type, res)
-			cgen(nl, &n2)
+			gc.Cgen(nr, &nt)
+			gc.Regalloc(&n2, nl.Type, res)
+			gc.Cgen(nl, &n2)
 		}
 
 		var hi gc.Node
 		var lo gc.Node
 		split64(&nt, &lo, &hi)
-		regalloc(&n1, gc.Types[gc.TUINT32], nil)
-		regalloc(&n3, gc.Types[gc.TUINT32], nil)
+		gc.Regalloc(&n1, gc.Types[gc.TUINT32], nil)
+		gc.Regalloc(&n3, gc.Types[gc.TUINT32], nil)
 		gmove(&lo, &n1)
 		gmove(&hi, &n3)
 		splitclean()
@@ -587,18 +269,18 @@
 		p1 := gins(arm.AMOVW, &t, &n1)
 		p1.Scond = arm.C_SCOND_NE
 		tr = gc.Types[gc.TUINT32]
-		regfree(&n3)
+		gc.Regfree(&n3)
 	} else {
 		if nl.Ullman >= nr.Ullman {
-			regalloc(&n2, nl.Type, res)
-			cgen(nl, &n2)
-			regalloc(&n1, nr.Type, nil)
-			cgen(nr, &n1)
+			gc.Regalloc(&n2, nl.Type, res)
+			gc.Cgen(nl, &n2)
+			gc.Regalloc(&n1, nr.Type, nil)
+			gc.Cgen(nr, &n1)
 		} else {
-			regalloc(&n1, nr.Type, nil)
-			cgen(nr, &n1)
-			regalloc(&n2, nl.Type, res)
-			cgen(nl, &n2)
+			gc.Regalloc(&n1, nr.Type, nil)
+			gc.Cgen(nr, &n1)
+			gc.Regalloc(&n2, nl.Type, res)
+			gc.Cgen(nl, &n2)
 		}
 	}
 
@@ -609,11 +291,11 @@
 
 	// test and fix up large shifts
 	// TODO: if(!bounded), don't emit some of this.
-	regalloc(&n3, tr, nil)
+	gc.Regalloc(&n3, tr, nil)
 
 	gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w))
 	gmove(&t, &n3)
-	gcmp(arm.ACMP, &n1, &n3)
+	gins(arm.ACMP, &n1, &n3)
 	if op == gc.ORSH {
 		var p1 *obj.Prog
 		var p2 *obj.Prog
@@ -634,7 +316,7 @@
 		p2.Scond = arm.C_SCOND_LO
 	}
 
-	regfree(&n3)
+	gc.Regfree(&n3)
 
 	gc.Patch(p3, gc.Pc)
 
@@ -644,8 +326,8 @@
 	}
 	gmove(&n2, res)
 
-	regfree(&n1)
-	regfree(&n2)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 func clearfat(nl *gc.Node) {
@@ -667,22 +349,22 @@
 	var r0 gc.Node
 	r0.Op = gc.OREGISTER
 
-	r0.Val.U.Reg = REGALLOC_R0
+	r0.Val.U.Reg = arm.REG_R0
 	var r1 gc.Node
 	r1.Op = gc.OREGISTER
-	r1.Val.U.Reg = REGALLOC_R0 + 1
+	r1.Val.U.Reg = arm.REG_R1
 	var dst gc.Node
-	regalloc(&dst, gc.Types[gc.Tptr], &r1)
-	agen(nl, &dst)
+	gc.Regalloc(&dst, gc.Types[gc.Tptr], &r1)
+	gc.Agen(nl, &dst)
 	var nc gc.Node
 	gc.Nodconst(&nc, gc.Types[gc.TUINT32], 0)
 	var nz gc.Node
-	regalloc(&nz, gc.Types[gc.TUINT32], &r0)
-	cgen(&nc, &nz)
+	gc.Regalloc(&nz, gc.Types[gc.TUINT32], &r0)
+	gc.Cgen(&nc, &nz)
 
 	if q > 128 {
 		var end gc.Node
-		regalloc(&end, gc.Types[gc.Tptr], nil)
+		gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
 		p := gins(arm.AMOVW, &dst, &end)
 		p.From.Type = obj.TYPE_ADDR
 		p.From.Offset = int64(q) * 4
@@ -697,7 +379,7 @@
 		raddr(&end, p)
 		gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl)
 
-		regfree(&end)
+		gc.Regfree(&end)
 	} else if q >= 4 && !gc.Nacl {
 		f := gc.Sysfunc("duffzero")
 		p := gins(obj.ADUFFZERO, nil, f)
@@ -729,8 +411,8 @@
 		c--
 	}
 
-	regfree(&dst)
-	regfree(&nz)
+	gc.Regfree(&dst)
+	gc.Regfree(&nz)
 }
 
 // Called after regopt and peep have run.
@@ -775,3 +457,40 @@
 		p.Reg = int16(reg)
 	}
 }
+
+func ginsnop() {
+	var r gc.Node
+	gc.Nodreg(&r, gc.Types[gc.TINT], arm.REG_R0)
+	p := gins(arm.AAND, &r, &r)
+	p.Scond = arm.C_SCOND_EQ
+}
+
+/*
+ * generate
+ *	as $c, n
+ */
+func ginscon(as int, c int64, n *gc.Node) {
+	var n1 gc.Node
+	gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
+	var n2 gc.Node
+	gc.Regalloc(&n2, gc.Types[gc.TINT32], nil)
+	gmove(&n1, &n2)
+	gins(as, &n2, n)
+	gc.Regfree(&n2)
+}
+
+// addr += index*width if possible.
+func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
+	switch width {
+	case 2:
+		gshift(arm.AADD, index, arm.SHIFT_LL, 1, addr)
+		return true
+	case 4:
+		gshift(arm.AADD, index, arm.SHIFT_LL, 2, addr)
+		return true
+	case 8:
+		gshift(arm.AADD, index, arm.SHIFT_LL, 3, addr)
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/5g/gsubr.go b/src/cmd/5g/gsubr.go
index 29dc958..0d22f74 100644
--- a/src/cmd/5g/gsubr.go
+++ b/src/cmd/5g/gsubr.go
@@ -43,185 +43,8 @@
 var unmappedzero int = 4096
 
 var resvd = []int{
-	9,         // reserved for m
-	10,        // reserved for g
-	arm.REGSP, // reserved for SP
-}
-
-func ginit() {
-	for i := 0; i < len(reg); i++ {
-		reg[i] = 0
-	}
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]]++
-	}
-}
-
-func gclean() {
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]]--
-	}
-
-	for i := 0; i < len(reg); i++ {
-		if reg[i] != 0 {
-			gc.Yyerror("reg %v left allocated\n", obj.Rconv(i))
-		}
-	}
-}
-
-func anyregalloc() bool {
-	var j int
-
-	for i := 0; i < len(reg); i++ {
-		if reg[i] == 0 {
-			goto ok
-		}
-		for j = 0; j < len(resvd); j++ {
-			if resvd[j] == i {
-				goto ok
-			}
-		}
-		return true
-	ok:
-	}
-
-	return false
-}
-
-var regpc [REGALLOC_FMAX + 1]uint32
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) {
-	if false && gc.Debug['r'] != 0 {
-		fixfree := 0
-		for i := REGALLOC_R0; i <= REGALLOC_RMAX; i++ {
-			if reg[i] == 0 {
-				fixfree++
-			}
-		}
-		floatfree := 0
-		for i := REGALLOC_F0; i <= REGALLOC_FMAX; i++ {
-			if reg[i] == 0 {
-				floatfree++
-			}
-		}
-		fmt.Printf("regalloc fix %d float %d\n", fixfree, floatfree)
-	}
-
-	if t == nil {
-		gc.Fatal("regalloc: t nil")
-	}
-	et := int(gc.Simtype[t.Etype])
-	if gc.Is64(t) {
-		gc.Fatal("regalloc: 64 bit type %v")
-	}
-
-	var i int
-	switch et {
-	case gc.TINT8,
-		gc.TUINT8,
-		gc.TINT16,
-		gc.TUINT16,
-		gc.TINT32,
-		gc.TUINT32,
-		gc.TPTR32,
-		gc.TBOOL:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= REGALLOC_R0 && i <= REGALLOC_RMAX {
-				goto out
-			}
-		}
-
-		for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ {
-			if reg[i] == 0 {
-				regpc[i] = uint32(obj.Getcallerpc(&n))
-				goto out
-			}
-		}
-
-		fmt.Printf("registers allocated at\n")
-		for i := REGALLOC_R0; i <= REGALLOC_RMAX; i++ {
-			fmt.Printf("%d %p\n", i, regpc[i])
-		}
-		gc.Fatal("out of fixed registers")
-		goto err
-
-	case gc.TFLOAT32,
-		gc.TFLOAT64:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= REGALLOC_F0 && i <= REGALLOC_FMAX {
-				goto out
-			}
-		}
-
-		for i = REGALLOC_F0; i <= REGALLOC_FMAX; i++ {
-			if reg[i] == 0 {
-				goto out
-			}
-		}
-		gc.Fatal("out of floating point registers")
-		goto err
-
-	case gc.TCOMPLEX64,
-		gc.TCOMPLEX128:
-		gc.Tempname(n, t)
-		return
-	}
-
-	gc.Yyerror("regalloc: unknown type %v", gc.Tconv(t, 0))
-
-err:
-	gc.Nodreg(n, t, arm.REG_R0)
-	return
-
-out:
-	reg[i]++
-	gc.Nodreg(n, t, i)
-}
-
-func regfree(n *gc.Node) {
-	if false && gc.Debug['r'] != 0 {
-		fixfree := 0
-		for i := REGALLOC_R0; i <= REGALLOC_RMAX; i++ {
-			if reg[i] == 0 {
-				fixfree++
-			}
-		}
-		floatfree := 0
-		for i := REGALLOC_F0; i <= REGALLOC_FMAX; i++ {
-			if reg[i] == 0 {
-				floatfree++
-			}
-		}
-		fmt.Printf("regalloc fix %d float %d\n", fixfree, floatfree)
-	}
-
-	if n.Op == gc.ONAME {
-		return
-	}
-	if n.Op != gc.OREGISTER && n.Op != gc.OINDREG {
-		gc.Fatal("regfree: not a register")
-	}
-	i := int(n.Val.U.Reg)
-	if i == arm.REGSP {
-		return
-	}
-	if i < 0 || i >= len(reg) || i >= len(regpc) {
-		gc.Fatal("regfree: reg out of range")
-	}
-	if reg[i] <= 0 {
-		gc.Fatal("regfree: reg %v not allocated", obj.Rconv(i))
-	}
-	reg[i]--
-	if reg[i] == 0 {
-		regpc[i] = 0
-	}
+	arm.REG_R9,  // formerly reserved for m; might be okay to reuse now; not sure about NaCl
+	arm.REG_R10, // reserved for g
 }
 
 /*
@@ -262,7 +85,7 @@
 		default:
 			var n1 gc.Node
 			if !dotaddable(n, &n1) {
-				igen(n, &n1, nil)
+				gc.Igen(n, &n1, nil)
 				sclean[nsclean-1] = n1
 			}
 
@@ -271,7 +94,7 @@
 		case gc.ONAME:
 			if n.Class == gc.PPARAMREF {
 				var n1 gc.Node
-				cgen(n.Heapaddr, &n1)
+				gc.Cgen(n.Heapaddr, &n1)
 				sclean[nsclean-1] = n1
 				n = &n1
 			}
@@ -311,7 +134,7 @@
 	}
 	nsclean--
 	if sclean[nsclean].Op != gc.OEMPTY {
-		regfree(&sclean[nsclean])
+		gc.Regfree(&sclean[nsclean])
 	}
 }
 
@@ -349,10 +172,10 @@
 			var con gc.Node
 			gc.Convconst(&con, gc.Types[gc.TINT32], &f.Val)
 			var r1 gc.Node
-			regalloc(&r1, con.Type, t)
+			gc.Regalloc(&r1, con.Type, t)
 			gins(arm.AMOVW, &con, &r1)
 			gmove(&r1, t)
-			regfree(&r1)
+			gc.Regfree(&r1)
 			return
 
 		case gc.TUINT16,
@@ -360,10 +183,10 @@
 			var con gc.Node
 			gc.Convconst(&con, gc.Types[gc.TUINT32], &f.Val)
 			var r1 gc.Node
-			regalloc(&r1, con.Type, t)
+			gc.Regalloc(&r1, con.Type, t)
 			gins(arm.AMOVW, &con, &r1)
 			gmove(&r1, t)
-			regfree(&r1)
+			gc.Regfree(&r1)
 			return
 		}
 
@@ -481,10 +304,10 @@
 		split64(f, &flo, &fhi)
 
 		var r1 gc.Node
-		regalloc(&r1, t.Type, nil)
+		gc.Regalloc(&r1, t.Type, nil)
 		gins(arm.AMOVW, &flo, &r1)
 		gins(arm.AMOVW, &r1, t)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		splitclean()
 		return
 
@@ -500,15 +323,15 @@
 		var thi gc.Node
 		split64(t, &tlo, &thi)
 		var r1 gc.Node
-		regalloc(&r1, flo.Type, nil)
+		gc.Regalloc(&r1, flo.Type, nil)
 		var r2 gc.Node
-		regalloc(&r2, fhi.Type, nil)
+		gc.Regalloc(&r2, fhi.Type, nil)
 		gins(arm.AMOVW, &flo, &r1)
 		gins(arm.AMOVW, &fhi, &r2)
 		gins(arm.AMOVW, &r1, &tlo)
 		gins(arm.AMOVW, &r2, &thi)
-		regfree(&r1)
-		regfree(&r2)
+		gc.Regfree(&r1)
+		gc.Regfree(&r2)
 		splitclean()
 		splitclean()
 		return
@@ -575,9 +398,9 @@
 		split64(t, &tlo, &thi)
 
 		var r1 gc.Node
-		regalloc(&r1, tlo.Type, nil)
+		gc.Regalloc(&r1, tlo.Type, nil)
 		var r2 gc.Node
-		regalloc(&r2, thi.Type, nil)
+		gc.Regalloc(&r2, thi.Type, nil)
 		gmove(f, &r1)
 		p1 := gins(arm.AMOVW, &r1, &r2)
 		p1.From.Type = obj.TYPE_SHIFT
@@ -588,8 +411,8 @@
 		gins(arm.AMOVW, &r1, &tlo)
 
 		gins(arm.AMOVW, &r2, &thi)
-		regfree(&r1)
-		regfree(&r2)
+		gc.Regfree(&r1)
+		gc.Regfree(&r2)
 		splitclean()
 		return
 
@@ -601,10 +424,10 @@
 
 		gmove(f, &tlo)
 		var r1 gc.Node
-		regalloc(&r1, thi.Type, nil)
+		gc.Regalloc(&r1, thi.Type, nil)
 		gins(arm.AMOVW, ncon(0), &r1)
 		gins(arm.AMOVW, &r1, &thi)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		splitclean()
 		return
 
@@ -651,9 +474,9 @@
 		}
 
 		var r1 gc.Node
-		regalloc(&r1, gc.Types[ft], f)
+		gc.Regalloc(&r1, gc.Types[ft], f)
 		var r2 gc.Node
-		regalloc(&r2, gc.Types[tt], t)
+		gc.Regalloc(&r2, gc.Types[tt], t)
 		gins(fa, f, &r1)        // load to fpu
 		p1 := gins(a, &r1, &r1) // convert to w
 		switch tt {
@@ -665,8 +488,8 @@
 
 		gins(arm.AMOVW, &r1, &r2) // copy to cpu
 		gins(ta, &r2, t)          // store
-		regfree(&r1)
-		regfree(&r2)
+		gc.Regfree(&r1)
+		gc.Regfree(&r2)
 		return
 
 		/*
@@ -708,9 +531,9 @@
 		}
 
 		var r1 gc.Node
-		regalloc(&r1, gc.Types[ft], f)
+		gc.Regalloc(&r1, gc.Types[ft], f)
 		var r2 gc.Node
-		regalloc(&r2, gc.Types[tt], t)
+		gc.Regalloc(&r2, gc.Types[tt], t)
 		gins(fa, f, &r1)          // load to cpu
 		gins(arm.AMOVW, &r1, &r2) // copy to fpu
 		p1 := gins(a, &r2, &r2)   // convert
@@ -722,8 +545,8 @@
 		}
 
 		gins(ta, &r2, t) // store
-		regfree(&r1)
-		regfree(&r2)
+		gc.Regfree(&r1)
+		gc.Regfree(&r2)
 		return
 
 	case gc.TUINT64<<16 | gc.TFLOAT32,
@@ -742,20 +565,20 @@
 
 	case gc.TFLOAT32<<16 | gc.TFLOAT64:
 		var r1 gc.Node
-		regalloc(&r1, gc.Types[gc.TFLOAT64], t)
+		gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], t)
 		gins(arm.AMOVF, f, &r1)
 		gins(arm.AMOVFD, &r1, &r1)
 		gins(arm.AMOVD, &r1, t)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		return
 
 	case gc.TFLOAT64<<16 | gc.TFLOAT32:
 		var r1 gc.Node
-		regalloc(&r1, gc.Types[gc.TFLOAT64], t)
+		gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], t)
 		gins(arm.AMOVD, f, &r1)
 		gins(arm.AMOVDF, &r1, &r1)
 		gins(arm.AMOVF, &r1, t)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		return
 	}
 
@@ -767,21 +590,21 @@
 	// requires register destination
 rdst:
 	{
-		regalloc(&r1, t.Type, t)
+		gc.Regalloc(&r1, t.Type, t)
 
 		gins(a, f, &r1)
 		gmove(&r1, t)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		return
 	}
 
 	// requires register intermediate
 hard:
-	regalloc(&r1, cvt, t)
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 
 	// truncate 64 bit integer
@@ -790,10 +613,10 @@
 	var flo gc.Node
 	split64(f, &flo, &fhi)
 
-	regalloc(&r1, t.Type, nil)
+	gc.Regalloc(&r1, t.Type, nil)
 	gins(a, &flo, &r1)
 	gins(a, &r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	splitclean()
 	return
 }
@@ -826,27 +649,67 @@
 		gc.Fatal("gins OINDEX not implemented")
 	}
 
-	//		regalloc(&nod, &regnode, Z);
+	//		gc.Regalloc(&nod, &regnode, Z);
 	//		v = constnode.vconst;
-	//		cgen(f->right, &nod);
+	//		gc.Cgen(f->right, &nod);
 	//		constnode.vconst = v;
 	//		idx.reg = nod.reg;
-	//		regfree(&nod);
+	//		gc.Regfree(&nod);
 	if t != nil && t.Op == gc.OINDEX {
 		gc.Fatal("gins OINDEX not implemented")
 	}
 
-	//		regalloc(&nod, &regnode, Z);
+	//		gc.Regalloc(&nod, &regnode, Z);
 	//		v = constnode.vconst;
-	//		cgen(t->right, &nod);
+	//		gc.Cgen(t->right, &nod);
 	//		constnode.vconst = v;
 	//		idx.reg = nod.reg;
-	//		regfree(&nod);
+	//		gc.Regfree(&nod);
 
 	p := gc.Prog(as)
 	gc.Naddr(&p.From, f)
 	gc.Naddr(&p.To, t)
 
+	switch as {
+	case arm.ABL:
+		if p.To.Type == obj.TYPE_REG {
+			p.To.Type = obj.TYPE_MEM
+		}
+
+	case arm.ACMP, arm.ACMPF, arm.ACMPD:
+		if t != nil {
+			if f.Op != gc.OREGISTER {
+				/* generate a comparison
+				TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
+				*/
+				gc.Fatal("bad operands to gcmp")
+			}
+			p.From = p.To
+			p.To = obj.Addr{}
+			raddr(f, p)
+		}
+
+	case arm.AMULU:
+		if f != nil && f.Op != gc.OREGISTER {
+			gc.Fatal("bad operands to mul")
+		}
+
+	case arm.AMOVW:
+		if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR || p.From.Type == obj.TYPE_CONST) && (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) {
+			gc.Fatal("gins double memory")
+		}
+
+	case arm.AADD:
+		if p.To.Type == obj.TYPE_MEM {
+			gc.Fatal("gins arith to mem")
+		}
+
+	case arm.ARSB:
+		if p.From.Type == obj.TYPE_NONE {
+			gc.Fatal("rsb with no from")
+		}
+	}
+
 	if gc.Debug['g'] != 0 {
 		fmt.Printf("%v\n", p)
 	}
@@ -871,19 +734,6 @@
 	}
 }
 
-/* generate a comparison
-TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
-*/
-func gcmp(as int, lhs *gc.Node, rhs *gc.Node) *obj.Prog {
-	if lhs.Op != gc.OREGISTER {
-		gc.Fatal("bad operands to gcmp: %v %v", gc.Oconv(int(lhs.Op), 0), gc.Oconv(int(rhs.Op), 0))
-	}
-
-	p := gins(as, rhs, nil)
-	raddr(lhs, p)
-	return p
-}
-
 /* generate a constant shift
  * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
  */
@@ -1033,6 +883,10 @@
 	case gc.OCMP<<16 | gc.TFLOAT64:
 		a = arm.ACMPD
 
+	case gc.OPS<<16 | gc.TFLOAT32,
+		gc.OPS<<16 | gc.TFLOAT64:
+		a = arm.ABVS
+
 	case gc.OAS<<16 | gc.TBOOL:
 		a = arm.AMOVB
 
@@ -1217,10 +1071,10 @@
 
 func sudoclean() {
 	if clean[cleani-1].Op != gc.OEMPTY {
-		regfree(&clean[cleani-1])
+		gc.Regfree(&clean[cleani-1])
 	}
 	if clean[cleani-2].Op != gc.OEMPTY {
-		regfree(&clean[cleani-2])
+		gc.Regfree(&clean[cleani-2])
 	}
 	cleani -= 2
 }
@@ -1254,7 +1108,7 @@
  * after successful sudoaddable,
  * to release the register used for a.
  */
-func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool {
+func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
 	if n.Type == nil {
 		return false
 	}
@@ -1322,14 +1176,14 @@
 			return true
 		}
 
-		regalloc(reg, gc.Types[gc.Tptr], nil)
+		gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
 		n1 := *reg
 		n1.Op = gc.OINDREG
 		if oary[0] >= 0 {
-			agen(nn, reg)
+			gc.Agen(nn, reg)
 			n1.Xoffset = oary[0]
 		} else {
-			cgen(nn, reg)
+			gc.Cgen(nn, reg)
 			gc.Cgen_checknil(reg)
 			n1.Xoffset = -(oary[0] + 1)
 		}
diff --git a/src/cmd/5g/peep.go b/src/cmd/5g/peep.go
index 6d864da..5305e4b 100644
--- a/src/cmd/5g/peep.go
+++ b/src/cmd/5g/peep.go
@@ -1330,10 +1330,10 @@
 	// R1 is ptr to memory, used and set, cannot be substituted.
 	case obj.ADUFFZERO:
 		if v.Type == obj.TYPE_REG {
-			if v.Reg == REGALLOC_R0 {
+			if v.Reg == arm.REG_R0 {
 				return 1
 			}
-			if v.Reg == REGALLOC_R0+1 {
+			if v.Reg == arm.REG_R0+1 {
 				return 2
 			}
 		}
@@ -1344,10 +1344,10 @@
 	// R1, R2 areptr to src, dst, used and set, cannot be substituted.
 	case obj.ADUFFCOPY:
 		if v.Type == obj.TYPE_REG {
-			if v.Reg == REGALLOC_R0 {
+			if v.Reg == arm.REG_R0 {
 				return 3
 			}
-			if v.Reg == REGALLOC_R0+1 || v.Reg == REGALLOC_R0+2 {
+			if v.Reg == arm.REG_R0+1 || v.Reg == arm.REG_R0+2 {
 				return 2
 			}
 		}
diff --git a/src/cmd/6g/cgen.go b/src/cmd/6g/cgen.go
index d11f7c7..41ed363 100644
--- a/src/cmd/6g/cgen.go
+++ b/src/cmd/6g/cgen.go
@@ -8,1472 +8,9 @@
 	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
-	"fmt"
 )
 
-/*
- * reg.c
- */
-
-/*
- * peep.c
- */
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- */
-func cgen(n *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\ncgen-n", n)
-		gc.Dump("cgen-res", res)
-	}
-
-	if n == nil || n.Type == nil {
-		return
-	}
-
-	if res == nil || res.Type == nil {
-		gc.Fatal("cgen: res nil")
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	switch n.Op {
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_slice(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_slice(n, res)
-		}
-		return
-
-	case gc.OEFACE:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_eface(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_eface(n, res)
-		}
-		return
-	}
-
-	if n.Ullman >= gc.UINF {
-		if n.Op == gc.OINDREG {
-			gc.Fatal("cgen: this is going to misscompile")
-		}
-		if res.Ullman >= gc.UINF {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			cgen(n, &n1)
-			cgen(&n1, res)
-			return
-		}
-	}
-
-	if gc.Isfat(n.Type) {
-		if n.Type.Width < 0 {
-			gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0))
-		}
-		sgen(n, res, n.Type.Width)
-		return
-	}
-
-	if res.Addable == 0 {
-		if n.Ullman > res.Ullman {
-			var n1 gc.Node
-			regalloc(&n1, n.Type, res)
-			cgen(n, &n1)
-			if n1.Ullman > res.Ullman {
-				gc.Dump("n1", &n1)
-				gc.Dump("res", res)
-				gc.Fatal("loop in cgen")
-			}
-
-			cgen(&n1, res)
-			regfree(&n1)
-			return
-		}
-
-		var f int
-		if res.Ullman >= gc.UINF {
-			goto gen
-		}
-
-		if gc.Complexop(n, res) {
-			gc.Complexgen(n, res)
-			return
-		}
-
-		f = 1 // gen thru register
-		switch n.Op {
-		case gc.OLITERAL:
-			if gc.Smallintconst(n) {
-				f = 0
-			}
-
-		case gc.OREGISTER:
-			f = 0
-		}
-
-		if !gc.Iscomplex[n.Type.Etype] {
-			a := optoas(gc.OAS, res.Type)
-			var addr obj.Addr
-			if sudoaddable(a, res, &addr) {
-				var p1 *obj.Prog
-				if f != 0 {
-					var n2 gc.Node
-					regalloc(&n2, res.Type, nil)
-					cgen(n, &n2)
-					p1 = gins(a, &n2, nil)
-					regfree(&n2)
-				} else {
-					p1 = gins(a, n, nil)
-				}
-				p1.To = addr
-				if gc.Debug['g'] != 0 {
-					fmt.Printf("%v [ignore previous line]\n", p1)
-				}
-				sudoclean()
-				return
-			}
-		}
-
-	gen:
-		var n1 gc.Node
-		igen(res, &n1, nil)
-		cgen(n, &n1)
-		regfree(&n1)
-		return
-	}
-
-	// update addressability for string, slice
-	// can't do in walk because n->left->addable
-	// changes if n->left is an escaping local variable.
-	switch n.Op {
-	case gc.OSPTR,
-		gc.OLEN:
-		if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OCAP:
-		if gc.Isslice(n.Left.Type) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OITAB:
-		n.Addable = n.Left.Addable
-	}
-
-	if gc.Complexop(n, res) {
-		gc.Complexgen(n, res)
-		return
-	}
-
-	if n.Addable != 0 {
-		gmove(n, res)
-		return
-	}
-
-	nl := n.Left
-	nr := n.Right
-
-	if nl != nil && nl.Ullman >= gc.UINF {
-		if nr != nil && nr.Ullman >= gc.UINF {
-			var n1 gc.Node
-			gc.Tempname(&n1, nl.Type)
-			cgen(nl, &n1)
-			n2 := *n
-			n2.Left = &n1
-			cgen(&n2, res)
-			return
-		}
-	}
-
-	if !gc.Iscomplex[n.Type.Etype] {
-		a := optoas(gc.OAS, n.Type)
-		var addr obj.Addr
-		if sudoaddable(a, n, &addr) {
-			if res.Op == gc.OREGISTER {
-				p1 := gins(a, nil, res)
-				p1.From = addr
-			} else {
-				var n2 gc.Node
-				regalloc(&n2, n.Type, nil)
-				p1 := gins(a, nil, &n2)
-				p1.From = addr
-				gins(a, &n2, res)
-				regfree(&n2)
-			}
-
-			sudoclean()
-			return
-		}
-	}
-
-	var a int
-	switch n.Op {
-	default:
-		gc.Dump("cgen", n)
-		gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign))
-
-		// these call bgen to get a bool value
-	case gc.OOROR,
-		gc.OANDAND,
-		gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OLE,
-		gc.OGE,
-		gc.OGT,
-		gc.ONOT:
-		p1 := gc.Gbranch(obj.AJMP, nil, 0)
-
-		p2 := gc.Pc
-		gmove(gc.Nodbool(true), res)
-		p3 := gc.Gbranch(obj.AJMP, nil, 0)
-		gc.Patch(p1, gc.Pc)
-		bgen(n, true, 0, p2)
-		gmove(gc.Nodbool(false), res)
-		gc.Patch(p3, gc.Pc)
-		return
-
-	case gc.OPLUS:
-		cgen(nl, res)
-		return
-
-		// unary
-	case gc.OCOM:
-		a := optoas(gc.OXOR, nl.Type)
-
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-		var n2 gc.Node
-		gc.Nodconst(&n2, nl.Type, -1)
-		gins(a, &n2, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		return
-
-	case gc.OMINUS:
-		if gc.Isfloat[nl.Type.Etype] {
-			nr = gc.Nodintconst(-1)
-			gc.Convlit(&nr, n.Type)
-			a = optoas(gc.OMUL, nl.Type)
-			goto sbop
-		}
-
-		a := optoas(int(n.Op), nl.Type)
-		// unary
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-
-		cgen(nl, &n1)
-		gins(a, nil, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		return
-
-		// symmetric binary
-	case gc.OAND,
-		gc.OOR,
-		gc.OXOR,
-		gc.OADD,
-		gc.OMUL:
-		a = optoas(int(n.Op), nl.Type)
-
-		if a == x86.AIMULB {
-			cgen_bmul(int(n.Op), nl, nr, res)
-			break
-		}
-
-		goto sbop
-
-		// asymmetric binary
-	case gc.OSUB:
-		a = optoas(int(n.Op), nl.Type)
-
-		goto abop
-
-	case gc.OHMUL:
-		cgen_hmul(nl, nr, res)
-
-	case gc.OCONV:
-		if n.Type.Width > nl.Type.Width {
-			// If loading from memory, do conversion during load,
-			// so as to avoid use of 8-bit register in, say, int(*byteptr).
-			switch nl.Op {
-			case gc.ODOT,
-				gc.ODOTPTR,
-				gc.OINDEX,
-				gc.OIND,
-				gc.ONAME:
-				var n1 gc.Node
-				igen(nl, &n1, res)
-				var n2 gc.Node
-				regalloc(&n2, n.Type, res)
-				gmove(&n1, &n2)
-				gmove(&n2, res)
-				regfree(&n2)
-				regfree(&n1)
-				return
-			}
-		}
-
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-		var n2 gc.Node
-		regalloc(&n2, n.Type, &n1)
-		cgen(nl, &n1)
-
-		// if we do the conversion n1 -> n2 here
-		// reusing the register, then gmove won't
-		// have to allocate its own register.
-		gmove(&n1, &n2)
-
-		gmove(&n2, res)
-		regfree(&n2)
-		regfree(&n1)
-
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OIND,
-		gc.ONAME: // PHEAP or PPARAMREF var
-		var n1 gc.Node
-		igen(n, &n1, res)
-
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// interface table is first word of interface value
-	case gc.OITAB:
-		var n1 gc.Node
-		igen(nl, &n1, res)
-
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// pointer is the first word of string or slice.
-	case gc.OSPTR:
-		if gc.Isconst(nl, gc.CTSTR) {
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-			p1 := gins(x86.ALEAQ, nil, &n1)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		var n1 gc.Node
-		igen(nl, &n1, res)
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-	case gc.OLEN:
-		if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) {
-			// map and chan have len in the first int-sized word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-
-			cgen(nl, &n1)
-
-			var n2 gc.Node
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Type = gc.Types[gc.Simtype[gc.TINT]]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) {
-			// both slice and string have len one pointer into the struct.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			igen(nl, &n1, res)
-
-			n1.Type = gc.Types[gc.Simtype[gc.TUINT]]
-			n1.Xoffset += int64(gc.Array_nel)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OCAP:
-		if gc.Istype(nl.Type, gc.TCHAN) {
-			// chan has cap in the second int-sized word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-
-			cgen(nl, &n1)
-
-			var n2 gc.Node
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Xoffset = int64(gc.Widthint)
-			n2.Type = gc.Types[gc.Simtype[gc.TINT]]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isslice(nl.Type) {
-			var n1 gc.Node
-			igen(nl, &n1, res)
-			n1.Type = gc.Types[gc.Simtype[gc.TUINT]]
-			n1.Xoffset += int64(gc.Array_cap)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OADDR:
-		if n.Bounded { // let race detector avoid nil checks
-			gc.Disable_checknil++
-		}
-		agen(nl, res)
-		if n.Bounded {
-			gc.Disable_checknil--
-		}
-
-	case gc.OCALLMETH:
-		gc.Cgen_callmeth(n, 0)
-		cgen_callret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_callret(n, res)
-
-	case gc.OCALLFUNC:
-		cgen_call(n, 0)
-		cgen_callret(n, res)
-
-	case gc.OMOD,
-		gc.ODIV:
-		if gc.Isfloat[n.Type.Etype] {
-			a = optoas(int(n.Op), nl.Type)
-			goto abop
-		}
-
-		if nl.Ullman >= nr.Ullman {
-			var n1 gc.Node
-			regalloc(&n1, nl.Type, res)
-			cgen(nl, &n1)
-			cgen_div(int(n.Op), &n1, nr, res)
-			regfree(&n1)
-		} else {
-			var n2 gc.Node
-			if !gc.Smallintconst(nr) {
-				regalloc(&n2, nr.Type, res)
-				cgen(nr, &n2)
-			} else {
-				n2 = *nr
-			}
-
-			cgen_div(int(n.Op), nl, &n2, res)
-			if n2.Op != gc.OLITERAL {
-				regfree(&n2)
-			}
-		}
-
-	case gc.OLSH,
-		gc.ORSH,
-		gc.OLROT:
-		cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
-	}
-
-	return
-
-	/*
-	 * put simplest on right - we'll generate into left
-	 * and then adjust it using the computation of right.
-	 * constants and variables have the same ullman
-	 * count, so look for constants specially.
-	 *
-	 * an integer constant we can use as an immediate
-	 * is simpler than a variable - we can use the immediate
-	 * in the adjustment instruction directly - so it goes
-	 * on the right.
-	 *
-	 * other constants, like big integers or floating point
-	 * constants, require a mov into a register, so those
-	 * might as well go on the left, so we can reuse that
-	 * register for the computation.
-	 */
-sbop: // symmetric binary
-	if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (gc.Smallintconst(nl) || (nr.Op == gc.OLITERAL && !gc.Smallintconst(nr)))) {
-		r := nl
-		nl = nr
-		nr = r
-	}
-
-abop: // asymmetric binary
-	var n1 gc.Node
-	var n2 gc.Node
-	if nl.Ullman >= nr.Ullman {
-		regalloc(&n1, nl.Type, res)
-		cgen(nl, &n1)
-
-		/*
-			 * This generates smaller code - it avoids a MOV - but it's
-			 * easily 10% slower due to not being able to
-			 * optimize/manipulate the move.
-			 * To see, run: go test -bench . crypto/md5
-			 * with and without.
-			 *
-				if(sudoaddable(a, nr, &addr)) {
-					p1 = gins(a, N, &n1);
-					p1->from = addr;
-					gmove(&n1, res);
-					sudoclean();
-					regfree(&n1);
-					goto ret;
-				}
-			 *
-		*/
-		if gc.Smallintconst(nr) {
-			n2 = *nr
-		} else {
-			regalloc(&n2, nr.Type, nil)
-			cgen(nr, &n2)
-		}
-	} else {
-		if gc.Smallintconst(nr) {
-			n2 = *nr
-		} else {
-			regalloc(&n2, nr.Type, res)
-			cgen(nr, &n2)
-		}
-
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-	}
-
-	gins(a, &n2, &n1)
-	gmove(&n1, res)
-	regfree(&n1)
-	if n2.Op != gc.OLITERAL {
-		regfree(&n2)
-	}
-	return
-}
-
-/*
- * allocate a register (reusing res if possible) and generate
- *  a = n
- * The caller must call regfree(a).
- */
-func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("cgenr-n", n)
-	}
-
-	if gc.Isfat(n.Type) {
-		gc.Fatal("cgenr on fat node")
-	}
-
-	if n.Addable != 0 {
-		regalloc(a, n.Type, res)
-		gmove(n, a)
-		return
-	}
-
-	switch n.Op {
-	case gc.ONAME,
-		gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		var n1 gc.Node
-		igen(n, &n1, res)
-		regalloc(a, gc.Types[gc.Tptr], &n1)
-		gmove(&n1, a)
-		regfree(&n1)
-
-	default:
-		regalloc(a, n.Type, res)
-		cgen(n, a)
-	}
-}
-
-/*
- * allocate a register (reusing res if possible) and generate
- * a = &n
- * The caller must call regfree(a).
- * The generated code checks that the result is not nil.
- */
-func agenr(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nagenr-n", n)
-	}
-
-	nl := n.Left
-	nr := n.Right
-
-	switch n.Op {
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		var n1 gc.Node
-		igen(n, &n1, res)
-		regalloc(a, gc.Types[gc.Tptr], &n1)
-		agen(&n1, a)
-		regfree(&n1)
-
-	case gc.OIND:
-		cgenr(n.Left, a, res)
-		gc.Cgen_checknil(a)
-
-	case gc.OINDEX:
-		freelen := 0
-		w := uint64(n.Type.Width)
-
-		// Generate the non-addressable child first.
-		var n3 gc.Node
-		var nlen gc.Node
-		var tmp gc.Node
-		var n1 gc.Node
-		if nr.Addable != 0 {
-			goto irad
-		}
-		if nl.Addable != 0 {
-			cgenr(nr, &n1, nil)
-			if !gc.Isconst(nl, gc.CTSTR) {
-				if gc.Isfixedarray(nl.Type) {
-					agenr(nl, &n3, res)
-				} else {
-					igen(nl, &nlen, res)
-					freelen = 1
-					nlen.Type = gc.Types[gc.Tptr]
-					nlen.Xoffset += int64(gc.Array_array)
-					regalloc(&n3, gc.Types[gc.Tptr], res)
-					gmove(&nlen, &n3)
-					nlen.Type = gc.Types[gc.Simtype[gc.TUINT]]
-					nlen.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-				}
-			}
-
-			goto index
-		}
-
-		gc.Tempname(&tmp, nr.Type)
-		cgen(nr, &tmp)
-		nr = &tmp
-
-	irad:
-		if !gc.Isconst(nl, gc.CTSTR) {
-			if gc.Isfixedarray(nl.Type) {
-				agenr(nl, &n3, res)
-			} else {
-				if nl.Addable == 0 {
-					// igen will need an addressable node.
-					var tmp2 gc.Node
-					gc.Tempname(&tmp2, nl.Type)
-
-					cgen(nl, &tmp2)
-					nl = &tmp2
-				}
-
-				igen(nl, &nlen, res)
-				freelen = 1
-				nlen.Type = gc.Types[gc.Tptr]
-				nlen.Xoffset += int64(gc.Array_array)
-				regalloc(&n3, gc.Types[gc.Tptr], res)
-				gmove(&nlen, &n3)
-				nlen.Type = gc.Types[gc.Simtype[gc.TUINT]]
-				nlen.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			}
-		}
-
-		if !gc.Isconst(nr, gc.CTINT) {
-			cgenr(nr, &n1, nil)
-		}
-
-		goto index
-
-		// &a is in &n3 (allocated in res)
-		// i is in &n1 (if not constant)
-		// len(a) is in nlen (if needed)
-		// w is width
-
-		// constant index
-	index:
-		if gc.Isconst(nr, gc.CTINT) {
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Fatal("constant string constant index") // front end should handle
-			}
-			v := uint64(gc.Mpgetfix(nr.Val.U.Xval))
-			if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				if gc.Debug['B'] == 0 && !n.Bounded {
-					var n2 gc.Node
-					gc.Nodconst(&n2, gc.Types[gc.Simtype[gc.TUINT]], int64(v))
-					if gc.Smallintconst(nr) {
-						gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), &nlen, &n2)
-					} else {
-						regalloc(&tmp, gc.Types[gc.Simtype[gc.TUINT]], nil)
-						gmove(&n2, &tmp)
-						gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), &nlen, &tmp)
-						regfree(&tmp)
-					}
-
-					p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.Simtype[gc.TUINT]]), nil, +1)
-					ginscall(gc.Panicindex, -1)
-					gc.Patch(p1, gc.Pc)
-				}
-
-				regfree(&nlen)
-			}
-
-			if v*w != 0 {
-				ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), int64(v*w), &n3)
-			}
-			*a = n3
-			break
-		}
-
-		// type of the index
-		t := gc.Types[gc.TUINT64]
-
-		if gc.Issigned[n1.Type.Etype] {
-			t = gc.Types[gc.TINT64]
-		}
-
-		var n2 gc.Node
-		regalloc(&n2, t, &n1) // i
-		gmove(&n1, &n2)
-		regfree(&n1)
-
-		if gc.Debug['B'] == 0 && !n.Bounded {
-			// check bounds
-			t = gc.Types[gc.Simtype[gc.TUINT]]
-
-			if gc.Is64(nr.Type) {
-				t = gc.Types[gc.TUINT64]
-			}
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
-			} else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				if gc.Is64(nr.Type) {
-					var n5 gc.Node
-					regalloc(&n5, t, nil)
-					gmove(&nlen, &n5)
-					regfree(&nlen)
-					nlen = n5
-				}
-			} else {
-				gc.Nodconst(&nlen, t, nl.Type.Bound)
-				if !gc.Smallintconst(&nlen) {
-					var n5 gc.Node
-					regalloc(&n5, t, nil)
-					gmove(&nlen, &n5)
-					nlen = n5
-					freelen = 1
-				}
-			}
-
-			gins(optoas(gc.OCMP, t), &n2, &nlen)
-			p1 := gc.Gbranch(optoas(gc.OLT, t), nil, +1)
-			ginscall(gc.Panicindex, -1)
-			gc.Patch(p1, gc.Pc)
-		}
-
-		if gc.Isconst(nl, gc.CTSTR) {
-			regalloc(&n3, gc.Types[gc.Tptr], res)
-			p1 := gins(x86.ALEAQ, nil, &n3)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			gins(x86.AADDQ, &n2, &n3)
-			goto indexdone
-		}
-
-		if w == 0 {
-		} else // nothing to do
-		if w == 1 || w == 2 || w == 4 || w == 8 {
-			p1 := gins(x86.ALEAQ, &n2, &n3)
-			p1.From.Type = obj.TYPE_MEM
-			p1.From.Scale = int16(w)
-			p1.From.Index = p1.From.Reg
-			p1.From.Reg = p1.To.Reg
-		} else {
-			ginscon(optoas(gc.OMUL, t), int64(w), &n2)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-		}
-
-	indexdone:
-		*a = n3
-		regfree(&n2)
-		if freelen != 0 {
-			regfree(&nlen)
-		}
-
-	default:
-		regalloc(a, gc.Types[gc.Tptr], res)
-		agen(n, a)
-	}
-}
-
-/*
- * generate:
- *	res = &n;
- * The generated code checks that the result is not nil.
- */
-func agen(n *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nagen-res", res)
-		gc.Dump("agen-r", n)
-	}
-
-	if n == nil || n.Type == nil {
-		return
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) {
-		// Use of a nil interface or nil slice.
-		// Create a temporary we can take the address of and read.
-		// The generated code is just going to panic, so it need not
-		// be terribly efficient. See issue 3670.
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-
-		gc.Gvardef(&n1)
-		clearfat(&n1)
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.Tptr], res)
-		gins(x86.ALEAQ, &n1, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		return
-	}
-
-	if n.Addable != 0 {
-		var n1 gc.Node
-		regalloc(&n1, gc.Types[gc.Tptr], res)
-		gins(x86.ALEAQ, n, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		return
-	}
-
-	nl := n.Left
-
-	switch n.Op {
-	default:
-		gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign))
-
-	case gc.OCALLMETH:
-		gc.Cgen_callmeth(n, 0)
-		cgen_aret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_aret(n, res)
-
-	case gc.OCALLFUNC:
-		cgen_call(n, 0)
-		cgen_aret(n, res)
-
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_slice(n, &n1)
-		agen(&n1, res)
-
-	case gc.OEFACE:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_eface(n, &n1)
-		agen(&n1, res)
-
-	case gc.OINDEX:
-		var n1 gc.Node
-		agenr(n, &n1, res)
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// should only get here with names in this func.
-	case gc.ONAME:
-		if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth)
-		}
-
-		// should only get here for heap vars or paramref
-		if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME class %#x", n.Class)
-		}
-
-		cgen(n.Heapaddr, res)
-		if n.Xoffset != 0 {
-			ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-
-	case gc.OIND:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-
-	case gc.ODOT:
-		agen(nl, res)
-		if n.Xoffset != 0 {
-			ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-
-	case gc.ODOTPTR:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-		if n.Xoffset != 0 {
-			ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-	}
-}
-
-/*
- * generate:
- *	newreg = &n;
- *	res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- * The generated code checks that the result is not *nil.
- */
-func igen(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nigen-n", n)
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF {
-			break
-		}
-		*a = *n
-		return
-
-		// Increase the refcount of the register so that igen's caller
-	// has to call regfree.
-	case gc.OINDREG:
-		if n.Val.U.Reg != x86.REG_SP {
-			reg[n.Val.U.Reg]++
-		}
-		*a = *n
-		return
-
-	case gc.ODOT:
-		igen(n.Left, a, res)
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		fixlargeoffset(a)
-		return
-
-	case gc.ODOTPTR:
-		cgenr(n.Left, a, res)
-		gc.Cgen_checknil(a)
-		a.Op = gc.OINDREG
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		fixlargeoffset(a)
-		return
-
-	case gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		switch n.Op {
-		case gc.OCALLFUNC:
-			cgen_call(n, 0)
-
-		case gc.OCALLMETH:
-			gc.Cgen_callmeth(n, 0)
-
-		case gc.OCALLINTER:
-			cgen_callinter(n, nil, 0)
-		}
-
-		var flist gc.Iter
-		fp := gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type))
-		*a = gc.Node{}
-		a.Op = gc.OINDREG
-		a.Val.U.Reg = x86.REG_SP
-		a.Addable = 1
-		a.Xoffset = fp.Width
-		a.Type = n.Type
-		return
-
-		// Index of fixed-size array by constant can
-	// put the offset in the addressing.
-	// Could do the same for slice except that we need
-	// to use the real index for the bounds checking.
-	case gc.OINDEX:
-		if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] && gc.Isfixedarray(n.Left.Left.Type)) {
-			if gc.Isconst(n.Right, gc.CTINT) {
-				// Compute &a.
-				if !gc.Isptr[n.Left.Type.Etype] {
-					igen(n.Left, a, res)
-				} else {
-					var n1 gc.Node
-					igen(n.Left, &n1, res)
-					gc.Cgen_checknil(&n1)
-					regalloc(a, gc.Types[gc.Tptr], res)
-					gmove(&n1, a)
-					regfree(&n1)
-					a.Op = gc.OINDREG
-				}
-
-				// Compute &a[i] as &a + i*width.
-				a.Type = n.Type
-
-				a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
-				fixlargeoffset(a)
-				return
-			}
-		}
-	}
-
-	agenr(n, a, res)
-	a.Op = gc.OINDREG
-	a.Type = n.Type
-}
-
-/*
- * generate:
- *	if(n == true) goto to;
- */
-func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nbgen", n)
-	}
-
-	if n == nil {
-		n = gc.Nodbool(true)
-	}
-
-	if n.Ninit != nil {
-		gc.Genlist(n.Ninit)
-	}
-
-	if n.Type == nil {
-		gc.Convlit(&n, gc.Types[gc.TBOOL])
-		if n.Type == nil {
-			return
-		}
-	}
-
-	et := int(n.Type.Etype)
-	if et != gc.TBOOL {
-		gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0))
-		gc.Patch(gins(obj.AEND, nil, nil), to)
-		return
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-		if n.Ninit != nil {
-			gc.Genlist(n.Ninit)
-		}
-	}
-
-	var nl *gc.Node
-	var nr *gc.Node
-	switch n.Op {
-	default:
-		goto def
-
-		// need to ask if it is bool?
-	case gc.OLITERAL:
-		if !true_ == (n.Val.U.Bval == 0) {
-			gc.Patch(gc.Gbranch(obj.AJMP, nil, likely), to)
-		}
-		return
-
-	case gc.ONAME:
-		if n.Addable == 0 {
-			goto def
-		}
-		var n1 gc.Node
-		gc.Nodconst(&n1, n.Type, 0)
-		gins(optoas(gc.OCMP, n.Type), n, &n1)
-		a := x86.AJNE
-		if !true_ {
-			a = x86.AJEQ
-		}
-		gc.Patch(gc.Gbranch(a, n.Type, likely), to)
-		return
-
-	case gc.OANDAND,
-		gc.OOROR:
-		if (n.Op == gc.OANDAND) == true_ {
-			p1 := gc.Gbranch(obj.AJMP, nil, 0)
-			p2 := gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, gc.Pc)
-			bgen(n.Left, !true_, -likely, p2)
-			bgen(n.Right, !true_, -likely, p2)
-			p1 = gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, to)
-			gc.Patch(p2, gc.Pc)
-		} else {
-			bgen(n.Left, true_, likely, to)
-			bgen(n.Right, true_, likely, to)
-		}
-
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			return
-		}
-		fallthrough
-
-	case gc.ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
-			return
-		}
-	}
-
-	switch n.Op {
-	case gc.ONOT:
-		bgen(nl, !true_, likely, to)
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		a := int(n.Op)
-		if !true_ {
-			if gc.Isfloat[nr.Type.Etype] {
-				// brcom is not valid on floats when NaN is involved.
-				p1 := gc.Gbranch(obj.AJMP, nil, 0)
-
-				p2 := gc.Gbranch(obj.AJMP, nil, 0)
-				gc.Patch(p1, gc.Pc)
-				ll := n.Ninit // avoid re-genning ninit
-				n.Ninit = nil
-				bgen(n, true, -likely, p2)
-				n.Ninit = ll
-				gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
-				gc.Patch(p2, gc.Pc)
-				return
-			}
-
-			a = gc.Brcom(a)
-			true_ = !true_
-		}
-
-		// make simplest on right
-		if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) {
-			a = gc.Brrev(a)
-			r := nl
-			nl = nr
-			nr = r
-		}
-
-		if gc.Isslice(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal slice comparison")
-				break
-			}
-
-			a = optoas(a, gc.Types[gc.Tptr])
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Xoffset += int64(gc.Array_array)
-			n1.Type = gc.Types[gc.Tptr]
-			var tmp gc.Node
-			gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp)
-			gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isinter(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal interface comparison")
-				break
-			}
-
-			a = optoas(a, gc.Types[gc.Tptr])
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Type = gc.Types[gc.Tptr]
-			var tmp gc.Node
-			gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp)
-			gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Iscomplex[nl.Type.Etype] {
-			gc.Complexbool(a, nl, nr, true_, likely, to)
-			break
-		}
-
-		var n2 gc.Node
-		var n1 gc.Node
-		if nr.Ullman >= gc.UINF {
-			regalloc(&n1, nl.Type, nil)
-			cgen(nl, &n1)
-
-			var tmp gc.Node
-			gc.Tempname(&tmp, nl.Type)
-			gmove(&n1, &tmp)
-			regfree(&n1)
-
-			regalloc(&n2, nr.Type, nil)
-			cgen(nr, &n2)
-
-			regalloc(&n1, nl.Type, nil)
-			cgen(&tmp, &n1)
-
-			goto cmp
-		}
-
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-
-		if gc.Smallintconst(nr) {
-			gins(optoas(gc.OCMP, nr.Type), &n1, nr)
-			gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-			regfree(&n1)
-			break
-		}
-
-		regalloc(&n2, nr.Type, nil)
-		cgen(nr, &n2)
-
-		// only < and <= work right with NaN; reverse if needed
-	cmp:
-		l := &n1
-
-		r := &n2
-		if gc.Isfloat[nl.Type.Etype] && (a == gc.OGT || a == gc.OGE) {
-			l = &n2
-			r = &n1
-			a = gc.Brrev(a)
-		}
-
-		gins(optoas(gc.OCMP, nr.Type), l, r)
-
-		if gc.Isfloat[nr.Type.Etype] && (n.Op == gc.OEQ || n.Op == gc.ONE) {
-			if n.Op == gc.OEQ {
-				// neither NE nor P
-				p1 := gc.Gbranch(x86.AJNE, nil, -likely)
-
-				p2 := gc.Gbranch(x86.AJPS, nil, -likely)
-				gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
-				gc.Patch(p1, gc.Pc)
-				gc.Patch(p2, gc.Pc)
-			} else {
-				// either NE or P
-				gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
-
-				gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to)
-			}
-		} else {
-			gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-		}
-		regfree(&n1)
-		regfree(&n2)
-	}
-
-	return
-
-def:
-	var n1 gc.Node
-	regalloc(&n1, n.Type, nil)
-	cgen(n, &n1)
-	var n2 gc.Node
-	gc.Nodconst(&n2, n.Type, 0)
-	gins(optoas(gc.OCMP, n.Type), &n1, &n2)
-	a := x86.AJNE
-	if !true_ {
-		a = x86.AJEQ
-	}
-	gc.Patch(gc.Gbranch(a, n.Type, likely), to)
-	regfree(&n1)
-	return
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-func stkof(n *gc.Node) int64 {
-	switch n.Op {
-	case gc.OINDREG:
-		return n.Xoffset
-
-	case gc.ODOT:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		return off + n.Xoffset
-
-	case gc.OINDEX:
-		t := n.Left.Type
-		if !gc.Isfixedarray(t) {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		if gc.Isconst(n.Right, gc.CTINT) {
-			return off + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval)
-		}
-		return 1000
-
-	case gc.OCALLMETH,
-		gc.OCALLINTER,
-		gc.OCALLFUNC:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			t = t.Type
-		}
-
-		var flist gc.Iter
-		t = gc.Structfirst(&flist, gc.Getoutarg(t))
-		if t != nil {
-			return t.Width
-		}
-	}
-
-	// botch - probably failing to recognize address
-	// arithmetic on the above. eg INDEX and DOT
-	return -1000
-}
-
-/*
- * block copy:
- *	memmove(&ns, &n, w);
- */
-func sgen(n *gc.Node, ns *gc.Node, w int64) {
-	if gc.Debug['g'] != 0 {
-		fmt.Printf("\nsgen w=%d\n", w)
-		gc.Dump("r", n)
-		gc.Dump("res", ns)
-	}
-
-	if n.Ullman >= gc.UINF && ns.Ullman >= gc.UINF {
-		gc.Fatal("sgen UINF")
-	}
-
-	if w < 0 {
-		gc.Fatal("sgen copy %d", w)
-	}
-
-	// If copying .args, that's all the results, so record definition sites
-	// for them for the liveness analysis.
-	if ns.Op == gc.ONAME && ns.Sym.Name == ".args" {
-		for l := gc.Curfn.Dcl; l != nil; l = l.Next {
-			if l.N.Class == gc.PPARAMOUT {
-				gc.Gvardef(l.N)
-			}
-		}
-	}
-
-	// Avoid taking the address for simple enough types.
-	if gc.Componentgen(n, ns) {
-		return
-	}
-
-	if w == 0 {
-		// evaluate side effects only
-		var nodr gc.Node
-		regalloc(&nodr, gc.Types[gc.Tptr], nil)
-
-		agen(ns, &nodr)
-		agen(n, &nodr)
-		regfree(&nodr)
-		return
-	}
-
-	// offset on the stack
-	osrc := stkof(n)
-
-	odst := stkof(ns)
-
-	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
-		// osrc and odst both on stack, and at least one is in
-		// an unknown position.  Could generate code to test
-		// for forward/backward copy, but instead just copy
-		// to a temporary location first.
-		var tmp gc.Node
-		gc.Tempname(&tmp, n.Type)
-
-		sgen(n, &tmp, w)
-		sgen(&tmp, ns, w)
-		return
-	}
-
+func stackcopy(n, ns *gc.Node, osrc, odst, w int64) {
 	var noddi gc.Node
 	gc.Nodreg(&noddi, gc.Types[gc.Tptr], x86.REG_DI)
 	var nodsi gc.Node
@@ -1482,17 +19,17 @@
 	var nodl gc.Node
 	var nodr gc.Node
 	if n.Ullman >= ns.Ullman {
-		agenr(n, &nodr, &nodsi)
+		gc.Agenr(n, &nodr, &nodsi)
 		if ns.Op == gc.ONAME {
 			gc.Gvardef(ns)
 		}
-		agenr(ns, &nodl, &noddi)
+		gc.Agenr(ns, &nodl, &noddi)
 	} else {
 		if ns.Op == gc.ONAME {
 			gc.Gvardef(ns)
 		}
-		agenr(ns, &nodl, &noddi)
-		agenr(n, &nodr, &nodsi)
+		gc.Agenr(ns, &nodl, &noddi)
+		gc.Agenr(n, &nodr, &nodsi)
 	}
 
 	if nodl.Val.U.Reg != x86.REG_DI {
@@ -1501,8 +38,8 @@
 	if nodr.Val.U.Reg != x86.REG_SI {
 		gmove(&nodr, &nodsi)
 	}
-	regfree(&nodl)
-	regfree(&nodr)
+	gc.Regfree(&nodl)
+	gc.Regfree(&nodr)
 
 	c := w % 8 // bytes
 	q := w / 8 // quads
diff --git a/src/cmd/6g/galign.go b/src/cmd/6g/galign.go
index ca8d387..8dab036 100644
--- a/src/cmd/6g/galign.go
+++ b/src/cmd/6g/galign.go
@@ -64,39 +64,52 @@
 }
 
 func main() {
+	if obj.Getgoos() == "nacl" {
+		resvd = append(resvd, x86.REG_BP, x86.REG_SI)
+	} else if obj.Framepointer_enabled != 0 {
+		resvd = append(resvd, x86.REG_BP)
+	}
+
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
 	gc.Thearch.Typedefs = typedefs
 	gc.Thearch.REGSP = x86.REGSP
 	gc.Thearch.REGCTXT = x86.REGCTXT
+	gc.Thearch.REGCALLX = x86.REG_BX
+	gc.Thearch.REGCALLX2 = x86.REG_AX
+	gc.Thearch.REGRETURN = x86.REG_AX
+	gc.Thearch.REGMIN = x86.REG_AX
+	gc.Thearch.REGMAX = x86.REG_R15
+	gc.Thearch.FREGMIN = x86.REG_X0
+	gc.Thearch.FREGMAX = x86.REG_X15
 	gc.Thearch.MAXWIDTH = MAXWIDTH
-	gc.Thearch.Anyregalloc = anyregalloc
+	gc.Thearch.ReservedRegs = resvd
+
+	gc.Thearch.AddIndex = addindex
 	gc.Thearch.Betypeinit = betypeinit
-	gc.Thearch.Bgen = bgen
-	gc.Thearch.Cgen = cgen
-	gc.Thearch.Cgen_call = cgen_call
-	gc.Thearch.Cgen_callinter = cgen_callinter
-	gc.Thearch.Cgen_ret = cgen_ret
+	gc.Thearch.Cgen_bmul = cgen_bmul
+	gc.Thearch.Cgen_hmul = cgen_hmul
+	gc.Thearch.Cgen_shift = cgen_shift
 	gc.Thearch.Clearfat = clearfat
 	gc.Thearch.Defframe = defframe
+	gc.Thearch.Dodiv = dodiv
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
-	gc.Thearch.Gclean = gclean
-	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
-	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
-	gc.Thearch.Igen = igen
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
 	gc.Thearch.Proginfo = proginfo
-	gc.Thearch.Regalloc = regalloc
-	gc.Thearch.Regfree = regfree
 	gc.Thearch.Regtyp = regtyp
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
+	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Sudoaddable = sudoaddable
+	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
 	gc.Thearch.RtoB = RtoB
 	gc.Thearch.FtoB = FtoB
diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go
index 42bebf8..f7977af 100644
--- a/src/cmd/6g/ggen.go
+++ b/src/cmd/6g/ggen.go
@@ -117,326 +117,6 @@
 }
 
 /*
- * generate:
- *	call f
- *	proc=-1	normal call but no return
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
-  *	proc=3	normal call to C pointer (not Go func value)
-*/
-func ginscall(f *gc.Node, proc int) {
-	if f.Type != nil {
-		extra := int32(0)
-		if proc == 1 || proc == 2 {
-			extra = 2 * int32(gc.Widthptr)
-		}
-		gc.Setmaxarg(f.Type, extra)
-	}
-
-	switch proc {
-	default:
-		gc.Fatal("ginscall: bad proc %d", proc)
-
-	case 0, // normal call
-		-1: // normal call but no return
-		if f.Op == gc.ONAME && f.Class == gc.PFUNC {
-			if f == gc.Deferreturn {
-				// Deferred calls will appear to be returning to
-				// the CALL deferreturn(SB) that we are about to emit.
-				// However, the stack trace code will show the line
-				// of the instruction byte before the return PC.
-				// To avoid that being an unrelated instruction,
-				// insert an x86 NOP that we will have the right line number.
-				// x86 NOP 0x90 is really XCHG AX, AX; use that description
-				// because the NOP pseudo-instruction would be removed by
-				// the linker.
-				var reg gc.Node
-				gc.Nodreg(&reg, gc.Types[gc.TINT], x86.REG_AX)
-
-				gins(x86.AXCHGL, &reg, &reg)
-			}
-
-			p := gins(obj.ACALL, nil, f)
-			gc.Afunclit(&p.To, f)
-			if proc == -1 || gc.Noreturn(p) {
-				gins(obj.AUNDEF, nil, nil)
-			}
-			break
-		}
-
-		var reg gc.Node
-		gc.Nodreg(&reg, gc.Types[gc.Tptr], x86.REG_DX)
-		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[gc.Tptr], x86.REG_BX)
-		gmove(f, &reg)
-		reg.Op = gc.OINDREG
-		gmove(&reg, &r1)
-		reg.Op = gc.OREGISTER
-		gins(obj.ACALL, &reg, &r1)
-
-	case 3: // normal call of c function pointer
-		gins(obj.ACALL, nil, f)
-
-	case 1, // call in new proc (go)
-		2: // deferred call (defer)
-		var stk gc.Node
-
-		stk.Op = gc.OINDREG
-		stk.Val.U.Reg = x86.REG_SP
-		stk.Xoffset = 0
-
-		var reg gc.Node
-		if gc.Widthptr == 8 {
-			// size of arguments at 0(SP)
-			ginscon(x86.AMOVQ, int64(gc.Argsize(f.Type)), &stk)
-
-			// FuncVal* at 8(SP)
-			stk.Xoffset = int64(gc.Widthptr)
-
-			gc.Nodreg(&reg, gc.Types[gc.TINT64], x86.REG_AX)
-			gmove(f, &reg)
-			gins(x86.AMOVQ, &reg, &stk)
-		} else {
-			// size of arguments at 0(SP)
-			ginscon(x86.AMOVL, int64(gc.Argsize(f.Type)), &stk)
-
-			// FuncVal* at 4(SP)
-			stk.Xoffset = int64(gc.Widthptr)
-
-			gc.Nodreg(&reg, gc.Types[gc.TINT32], x86.REG_AX)
-			gmove(f, &reg)
-			gins(x86.AMOVL, &reg, &stk)
-		}
-
-		if proc == 1 {
-			ginscall(gc.Newproc, 0)
-		} else {
-			if gc.Hasdefer == 0 {
-				gc.Fatal("hasdefer=0 but has defer")
-			}
-			ginscall(gc.Deferproc, 0)
-		}
-
-		if proc == 2 {
-			gc.Nodreg(&reg, gc.Types[gc.TINT32], x86.REG_AX)
-			gins(x86.ATESTL, &reg, &reg)
-			p := gc.Gbranch(x86.AJEQ, nil, +1)
-			cgen_ret(nil)
-			gc.Patch(p, gc.Pc)
-		}
-	}
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-func cgen_callinter(n *gc.Node, res *gc.Node, proc int) {
-	i := n.Left
-	if i.Op != gc.ODOTINTER {
-		gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0))
-	}
-
-	f := i.Right // field
-	if f.Op != gc.ONAME {
-		gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0))
-	}
-
-	i = i.Left // interface
-
-	if i.Addable == 0 {
-		var tmpi gc.Node
-		gc.Tempname(&tmpi, i.Type)
-		cgen(i, &tmpi)
-		i = &tmpi
-	}
-
-	gc.Genlist(n.List) // assign the args
-
-	// i is now addable, prepare an indirected
-	// register to hold its address.
-	var nodi gc.Node
-	igen(i, &nodi, res) // REG = &inter
-
-	var nodsp gc.Node
-	gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], x86.REG_SP)
-
-	nodsp.Xoffset = 0
-	if proc != 0 {
-		nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn
-	}
-	nodi.Type = gc.Types[gc.Tptr]
-	nodi.Xoffset += int64(gc.Widthptr)
-	cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data
-
-	var nodo gc.Node
-	regalloc(&nodo, gc.Types[gc.Tptr], res)
-
-	nodi.Type = gc.Types[gc.Tptr]
-	nodi.Xoffset -= int64(gc.Widthptr)
-	cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
-	regfree(&nodi)
-
-	var nodr gc.Node
-	regalloc(&nodr, gc.Types[gc.Tptr], &nodo)
-	if n.Left.Xoffset == gc.BADWIDTH {
-		gc.Fatal("cgen_callinter: badwidth")
-	}
-	gc.Cgen_checknil(&nodo) // in case offset is huge
-	nodo.Op = gc.OINDREG
-	nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8
-	if proc == 0 {
-		// plain call: use direct c function pointer - more efficient
-		cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
-		proc = 3
-	} else {
-		// go/defer. generate go func value.
-		gins(x86.ALEAQ, &nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
-	}
-
-	nodr.Type = n.Left.Type
-	ginscall(&nodr, proc)
-
-	regfree(&nodr)
-	regfree(&nodo)
-}
-
-/*
- * generate function call;
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
- */
-func cgen_call(n *gc.Node, proc int) {
-	if n == nil {
-		return
-	}
-
-	var afun gc.Node
-	if n.Left.Ullman >= gc.UINF {
-		// if name involves a fn call
-		// precompute the address of the fn
-		gc.Tempname(&afun, gc.Types[gc.Tptr])
-
-		cgen(n.Left, &afun)
-	}
-
-	gc.Genlist(n.List) // assign the args
-	t := n.Left.Type
-
-	// call tempname pointer
-	if n.Left.Ullman >= gc.UINF {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, &afun)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call pointer
-	if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, n.Left)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call direct
-	n.Left.Method = 1
-
-	ginscall(n.Left, proc)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = return value from call.
- */
-func cgen_callret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_callret: nil")
-	}
-
-	var nod gc.Node
-	nod.Op = gc.OINDREG
-	nod.Val.U.Reg = x86.REG_SP
-	nod.Addable = 1
-
-	nod.Xoffset = fp.Width
-	nod.Type = fp.Type
-	gc.Cgen_as(res, &nod)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = &return value from call.
- */
-func cgen_aret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if gc.Isptr[t.Etype] {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	var nod1 gc.Node
-	nod1.Op = gc.OINDREG
-	nod1.Val.U.Reg = x86.REG_SP
-	nod1.Addable = 1
-
-	nod1.Xoffset = fp.Width
-	nod1.Type = fp.Type
-
-	if res.Op != gc.OREGISTER {
-		var nod2 gc.Node
-		regalloc(&nod2, gc.Types[gc.Tptr], res)
-		gins(leaptr, &nod1, &nod2)
-		gins(movptr, &nod2, res)
-		regfree(&nod2)
-	} else {
-		gins(leaptr, &nod1, res)
-	}
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-func cgen_ret(n *gc.Node) {
-	if n != nil {
-		gc.Genlist(n.List) // copy out args
-	}
-	if gc.Hasdefer != 0 {
-		ginscall(gc.Deferreturn, 0)
-	}
-	gc.Genlist(gc.Curfn.Exit)
-	p := gins(obj.ARET, nil, nil)
-	if n != nil && n.Op == gc.ORETJMP {
-		p.To.Type = obj.TYPE_MEM
-		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(n.Left.Sym)
-	}
-}
-
-/*
  * generate division.
  * generates one of:
  *	res = nl / nr
@@ -477,19 +157,19 @@
 	a := optoas(op, t)
 
 	var n3 gc.Node
-	regalloc(&n3, t0, nil)
+	gc.Regalloc(&n3, t0, nil)
 	var ax gc.Node
 	var oldax gc.Node
 	if nl.Ullman >= nr.Ullman {
 		savex(x86.REG_AX, &ax, &oldax, res, t0)
-		cgen(nl, &ax)
-		regalloc(&ax, t0, &ax) // mark ax live during cgen
-		cgen(nr, &n3)
-		regfree(&ax)
+		gc.Cgen(nl, &ax)
+		gc.Regalloc(&ax, t0, &ax) // mark ax live during cgen
+		gc.Cgen(nr, &n3)
+		gc.Regfree(&ax)
 	} else {
-		cgen(nr, &n3)
+		gc.Cgen(nr, &n3)
 		savex(x86.REG_AX, &ax, &oldax, res, t0)
-		cgen(nl, &ax)
+		gc.Cgen(nl, &ax)
 	}
 
 	if t != t0 {
@@ -515,7 +195,7 @@
 		if panicdiv == nil {
 			panicdiv = gc.Sysfunc("panicdivide")
 		}
-		ginscall(panicdiv, -1)
+		gc.Ginscall(panicdiv, -1)
 		gc.Patch(p1, gc.Pc)
 	}
 
@@ -550,7 +230,7 @@
 		gins(optoas(gc.OEXTEND, t), nil, nil)
 	}
 	gins(a, &n3, nil)
-	regfree(&n3)
+	gc.Regfree(&n3)
 	if op == gc.ODIV {
 		gmove(&ax, res)
 	} else {
@@ -582,7 +262,7 @@
 
 	gc.Nodreg(x, t, dr)
 	if r > 1 && !gc.Samereg(x, res) {
-		regalloc(oldx, gc.Types[gc.TINT64], nil)
+		gc.Regalloc(oldx, gc.Types[gc.TINT64], nil)
 		x.Type = gc.Types[gc.TINT64]
 		gmove(x, oldx)
 		x.Type = t
@@ -596,154 +276,11 @@
 		x.Type = gc.Types[gc.TINT64]
 		reg[x.Val.U.Reg] = uint8(oldx.Ostk)
 		gmove(oldx, x)
-		regfree(oldx)
+		gc.Regfree(oldx)
 	}
 }
 
 /*
- * generate division according to op, one of:
- *	res = nl / nr
- *	res = nl % nr
- */
-func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
-	var w int
-
-	if nr.Op != gc.OLITERAL {
-		goto longdiv
-	}
-	w = int(nl.Type.Width * 8)
-
-	// Front end handled 32-bit division. We only need to handle 64-bit.
-	// try to do division by multiply by (2^w)/d
-	// see hacker's delight chapter 10
-	switch gc.Simtype[nl.Type.Etype] {
-	default:
-		goto longdiv
-
-	case gc.TUINT64:
-		var m gc.Magic
-		m.W = w
-		m.Ud = uint64(gc.Mpgetfix(nr.Val.U.Xval))
-		gc.Umagic(&m)
-		if m.Bad != 0 {
-			break
-		}
-		if op == gc.OMOD {
-			goto longmod
-		}
-
-		var n1 gc.Node
-		cgenr(nl, &n1, nil)
-		var n2 gc.Node
-		gc.Nodconst(&n2, nl.Type, int64(m.Um))
-		var n3 gc.Node
-		regalloc(&n3, nl.Type, res)
-		cgen_hmul(&n1, &n2, &n3)
-
-		if m.Ua != 0 {
-			// need to add numerator accounting for overflow
-			gins(optoas(gc.OADD, nl.Type), &n1, &n3)
-
-			gc.Nodconst(&n2, nl.Type, 1)
-			gins(optoas(gc.ORROTC, nl.Type), &n2, &n3)
-			gc.Nodconst(&n2, nl.Type, int64(m.S)-1)
-			gins(optoas(gc.ORSH, nl.Type), &n2, &n3)
-		} else {
-			gc.Nodconst(&n2, nl.Type, int64(m.S))
-			gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift dx
-		}
-
-		gmove(&n3, res)
-		regfree(&n1)
-		regfree(&n3)
-		return
-
-	case gc.TINT64:
-		var m gc.Magic
-		m.W = w
-		m.Sd = gc.Mpgetfix(nr.Val.U.Xval)
-		gc.Smagic(&m)
-		if m.Bad != 0 {
-			break
-		}
-		if op == gc.OMOD {
-			goto longmod
-		}
-
-		var n1 gc.Node
-		cgenr(nl, &n1, res)
-		var n2 gc.Node
-		gc.Nodconst(&n2, nl.Type, m.Sm)
-		var n3 gc.Node
-		regalloc(&n3, nl.Type, nil)
-		cgen_hmul(&n1, &n2, &n3)
-
-		if m.Sm < 0 {
-			// need to add numerator
-			gins(optoas(gc.OADD, nl.Type), &n1, &n3)
-		}
-
-		gc.Nodconst(&n2, nl.Type, int64(m.S))
-		gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift n3
-
-		gc.Nodconst(&n2, nl.Type, int64(w)-1)
-
-		gins(optoas(gc.ORSH, nl.Type), &n2, &n1) // -1 iff num is neg
-		gins(optoas(gc.OSUB, nl.Type), &n1, &n3) // added
-
-		if m.Sd < 0 {
-			// this could probably be removed
-			// by factoring it into the multiplier
-			gins(optoas(gc.OMINUS, nl.Type), nil, &n3)
-		}
-
-		gmove(&n3, res)
-		regfree(&n1)
-		regfree(&n3)
-		return
-	}
-
-	goto longdiv
-
-	// division and mod using (slow) hardware instruction
-longdiv:
-	dodiv(op, nl, nr, res)
-
-	return
-
-	// mod using formula A%B = A-(A/B*B) but
-	// we know that there is a fast algorithm for A/B
-longmod:
-	var n1 gc.Node
-	regalloc(&n1, nl.Type, res)
-
-	cgen(nl, &n1)
-	var n2 gc.Node
-	regalloc(&n2, nl.Type, nil)
-	cgen_div(gc.ODIV, &n1, nr, &n2)
-	a := optoas(gc.OMUL, nl.Type)
-	if w == 8 {
-		// use 2-operand 16-bit multiply
-		// because there is no 2-operand 8-bit multiply
-		a = x86.AIMULW
-	}
-
-	if !gc.Smallintconst(nr) {
-		var n3 gc.Node
-		regalloc(&n3, nl.Type, nil)
-		cgen(nr, &n3)
-		gins(a, &n3, &n2)
-		regfree(&n3)
-	} else {
-		gins(a, nr, &n2)
-	}
-	gins(optoas(gc.OSUB, nl.Type), &n2, &n1)
-	gmove(&n1, res)
-	regfree(&n1)
-	regfree(&n2)
-}
-
-/*
  * generate high multiply:
  *   res = (nl*nr) >> width
  */
@@ -757,15 +294,15 @@
 	}
 
 	var n1 gc.Node
-	cgenr(nl, &n1, res)
+	gc.Cgenr(nl, &n1, res)
 	var n2 gc.Node
-	cgenr(nr, &n2, nil)
+	gc.Cgenr(nr, &n2, nil)
 	var ax gc.Node
 	gc.Nodreg(&ax, t, x86.REG_AX)
 	gmove(&n1, &ax)
 	gins(a, &n2, nil)
-	regfree(&n2)
-	regfree(&n1)
+	gc.Regfree(&n2)
+	gc.Regfree(&n1)
 
 	var dx gc.Node
 	if t.Width == 1 {
@@ -790,8 +327,8 @@
 
 	if nr.Op == gc.OLITERAL {
 		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-		cgen(nl, &n1)
+		gc.Regalloc(&n1, nl.Type, res)
+		gc.Cgen(nl, &n1)
 		sc := uint64(gc.Mpgetfix(nr.Val.U.Xval))
 		if sc >= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
@@ -804,21 +341,21 @@
 			gins(a, nr, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
 	if nl.Ullman >= gc.UINF {
 		var n4 gc.Node
 		gc.Tempname(&n4, nl.Type)
-		cgen(nl, &n4)
+		gc.Cgen(nl, &n4)
 		nl = &n4
 	}
 
 	if nr.Ullman >= gc.UINF {
 		var n5 gc.Node
 		gc.Tempname(&n5, nr.Type)
-		cgen(nr, &n5)
+		gc.Cgen(nr, &n5)
 		nr = &n5
 	}
 
@@ -835,16 +372,16 @@
 		tcount = gc.Types[gc.TUINT32]
 	}
 
-	regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
+	gc.Regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
 	var n3 gc.Node
-	regalloc(&n3, tcount, &n1) // to clear high bits of CX
+	gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
 
 	var cx gc.Node
 	gc.Nodreg(&cx, gc.Types[gc.TUINT64], x86.REG_CX)
 
 	var oldcx gc.Node
 	if rcx > 0 && !gc.Samereg(&cx, res) {
-		regalloc(&oldcx, gc.Types[gc.TUINT64], nil)
+		gc.Regalloc(&oldcx, gc.Types[gc.TUINT64], nil)
 		gmove(&cx, &oldcx)
 	}
 
@@ -852,21 +389,21 @@
 
 	var n2 gc.Node
 	if gc.Samereg(&cx, res) {
-		regalloc(&n2, nl.Type, nil)
+		gc.Regalloc(&n2, nl.Type, nil)
 	} else {
-		regalloc(&n2, nl.Type, res)
+		gc.Regalloc(&n2, nl.Type, res)
 	}
 	if nl.Ullman >= nr.Ullman {
-		cgen(nl, &n2)
-		cgen(nr, &n1)
+		gc.Cgen(nl, &n2)
+		gc.Cgen(nr, &n1)
 		gmove(&n1, &n3)
 	} else {
-		cgen(nr, &n1)
+		gc.Cgen(nr, &n1)
 		gmove(&n1, &n3)
-		cgen(nl, &n2)
+		gc.Cgen(nl, &n2)
 	}
 
-	regfree(&n3)
+	gc.Regfree(&n3)
 
 	// test and fix up large shifts
 	if !bounded {
@@ -889,13 +426,13 @@
 	if oldcx.Op != 0 {
 		cx.Type = gc.Types[gc.TUINT64]
 		gmove(&oldcx, &cx)
-		regfree(&oldcx)
+		gc.Regfree(&oldcx)
 	}
 
 	gmove(&n2, res)
 
-	regfree(&n1)
-	regfree(&n2)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 /*
@@ -904,7 +441,11 @@
  * there is no 2-operand byte multiply instruction so
  * we do a full-width multiplication and truncate afterwards.
  */
-func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
+func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) bool {
+	if optoas(op, nl.Type) != x86.AIMULB {
+		return false
+	}
+
 	// largest ullman on left.
 	if nl.Ullman < nr.Ullman {
 		tmp := nl
@@ -914,12 +455,12 @@
 
 	// generate operands in "8-bit" registers.
 	var n1b gc.Node
-	regalloc(&n1b, nl.Type, res)
+	gc.Regalloc(&n1b, nl.Type, res)
 
-	cgen(nl, &n1b)
+	gc.Cgen(nl, &n1b)
 	var n2b gc.Node
-	regalloc(&n2b, nr.Type, nil)
-	cgen(nr, &n2b)
+	gc.Regalloc(&n2b, nr.Type, nil)
+	gc.Cgen(nr, &n2b)
 
 	// perform full-width multiplication.
 	t := gc.Types[gc.TUINT64]
@@ -937,8 +478,9 @@
 	// truncate.
 	gmove(&n1, res)
 
-	regfree(&n1b)
-	regfree(&n2b)
+	gc.Regfree(&n1b)
+	gc.Regfree(&n2b)
+	return true
 }
 
 func clearfat(nl *gc.Node) {
@@ -965,7 +507,7 @@
 		// NOTE: Must use agen, not igen, so that optimizer sees address
 		// being taken. We are not writing on field boundaries.
 		var n1 gc.Node
-		agenr(nl, &n1, nil)
+		gc.Agenr(nl, &n1, nil)
 
 		n1.Op = gc.OINDREG
 		var z gc.Node
@@ -1001,14 +543,14 @@
 			n1.Xoffset++
 		}
 
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
 	var oldn1 gc.Node
 	var n1 gc.Node
 	savex(x86.REG_DI, &n1, &oldn1, nil, gc.Types[gc.Tptr])
-	agen(nl, &n1)
+	gc.Agen(nl, &n1)
 
 	var ax gc.Node
 	var oldax gc.Node
@@ -1115,3 +657,17 @@
 		p2.To.Offset = 0
 	}
 }
+
+// addr += index*width if possible.
+func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
+	switch width {
+	case 1, 2, 4, 8:
+		p1 := gins(x86.ALEAQ, index, addr)
+		p1.From.Type = obj.TYPE_MEM
+		p1.From.Scale = int16(width)
+		p1.From.Index = p1.From.Reg
+		p1.From.Reg = p1.To.Reg
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/6g/gsubr.go b/src/cmd/6g/gsubr.go
index 6284b8c..b2290af 100644
--- a/src/cmd/6g/gsubr.go
+++ b/src/cmd/6g/gsubr.go
@@ -52,171 +52,6 @@
 	x86.REG_SP, // for stack
 }
 
-func ginit() {
-	for i := 0; i < len(reg); i++ {
-		reg[i] = 1
-	}
-	for i := x86.REG_AX; i <= x86.REG_R15; i++ {
-		reg[i] = 0
-	}
-	for i := x86.REG_X0; i <= x86.REG_X15; i++ {
-		reg[i] = 0
-	}
-
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]]++
-	}
-
-	if gc.Nacl {
-		reg[x86.REG_BP]++
-		reg[x86.REG_R15]++
-	} else if obj.Framepointer_enabled != 0 {
-		// BP is part of the calling convention of framepointer_enabled.
-		reg[x86.REG_BP]++
-	}
-}
-
-func gclean() {
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]]--
-	}
-	if gc.Nacl {
-		reg[x86.REG_BP]--
-		reg[x86.REG_R15]--
-	} else if obj.Framepointer_enabled != 0 {
-		reg[x86.REG_BP]--
-	}
-
-	for i := x86.REG_AX; i <= x86.REG_R15; i++ {
-		if reg[i] != 0 {
-			gc.Yyerror("reg %v left allocated\n", obj.Rconv(i))
-		}
-	}
-	for i := x86.REG_X0; i <= x86.REG_X15; i++ {
-		if reg[i] != 0 {
-			gc.Yyerror("reg %v left allocated\n", obj.Rconv(i))
-		}
-	}
-}
-
-func anyregalloc() bool {
-	var j int
-
-	for i := x86.REG_AX; i <= x86.REG_R15; i++ {
-		if reg[i] == 0 {
-			goto ok
-		}
-		for j = 0; j < len(resvd); j++ {
-			if resvd[j] == i {
-				goto ok
-			}
-		}
-		return true
-	ok:
-	}
-
-	return false
-}
-
-var regpc [x86.REG_R15 + 1 - x86.REG_AX]uint32
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) {
-	if t == nil {
-		gc.Fatal("regalloc: t nil")
-	}
-	et := int(gc.Simtype[t.Etype])
-
-	var i int
-	switch et {
-	case gc.TINT8,
-		gc.TUINT8,
-		gc.TINT16,
-		gc.TUINT16,
-		gc.TINT32,
-		gc.TUINT32,
-		gc.TINT64,
-		gc.TUINT64,
-		gc.TPTR32,
-		gc.TPTR64,
-		gc.TBOOL:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= x86.REG_AX && i <= x86.REG_R15 {
-				goto out
-			}
-		}
-
-		for i = x86.REG_AX; i <= x86.REG_R15; i++ {
-			if reg[i] == 0 {
-				regpc[i-x86.REG_AX] = uint32(obj.Getcallerpc(&n))
-				goto out
-			}
-		}
-
-		gc.Flusherrors()
-		for i := 0; i+x86.REG_AX <= x86.REG_R15; i++ {
-			fmt.Printf("%d %p\n", i, regpc[i])
-		}
-		gc.Fatal("out of fixed registers")
-
-	case gc.TFLOAT32,
-		gc.TFLOAT64:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= x86.REG_X0 && i <= x86.REG_X15 {
-				goto out
-			}
-		}
-
-		for i = x86.REG_X0; i <= x86.REG_X15; i++ {
-			if reg[i] == 0 {
-				goto out
-			}
-		}
-		gc.Fatal("out of floating registers")
-
-	case gc.TCOMPLEX64,
-		gc.TCOMPLEX128:
-		gc.Tempname(n, t)
-		return
-	}
-
-	gc.Fatal("regalloc: unknown type %v", gc.Tconv(t, 0))
-	return
-
-out:
-	reg[i]++
-	gc.Nodreg(n, t, i)
-}
-
-func regfree(n *gc.Node) {
-	if n.Op == gc.ONAME {
-		return
-	}
-	if n.Op != gc.OREGISTER && n.Op != gc.OINDREG {
-		gc.Fatal("regfree: not a register")
-	}
-	i := int(n.Val.U.Reg)
-	if i == x86.REG_SP {
-		return
-	}
-	if i < 0 || i >= len(reg) {
-		gc.Fatal("regfree: reg out of range")
-	}
-	if reg[i] <= 0 {
-		gc.Fatal("regfree: reg not allocated")
-	}
-	reg[i]--
-	if reg[i] == 0 && x86.REG_AX <= i && i <= x86.REG_R15 {
-		regpc[i-x86.REG_AX] = 0
-	}
-}
-
 /*
  * generate
  *	as $c, reg
@@ -258,11 +93,11 @@
 		// cannot have 64-bit immediate in ADD, etc.
 		// instead, MOV into register first.
 		var ntmp gc.Node
-		regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+		gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
 
 		gins(x86.AMOVQ, &n1, &ntmp)
 		gins(as, &ntmp, n2)
-		regfree(&ntmp)
+		gc.Regfree(&ntmp)
 		return
 	}
 
@@ -536,13 +371,13 @@
 		}
 		bignodes()
 		var r1 gc.Node
-		regalloc(&r1, gc.Types[ft], nil)
+		gc.Regalloc(&r1, gc.Types[ft], nil)
 		var r2 gc.Node
-		regalloc(&r2, gc.Types[tt], t)
+		gc.Regalloc(&r2, gc.Types[tt], t)
 		var r3 gc.Node
-		regalloc(&r3, gc.Types[ft], nil)
+		gc.Regalloc(&r3, gc.Types[ft], nil)
 		var r4 gc.Node
-		regalloc(&r4, gc.Types[tt], nil)
+		gc.Regalloc(&r4, gc.Types[tt], nil)
 		gins(optoas(gc.OAS, f.Type), f, &r1)
 		gins(optoas(gc.OCMP, f.Type), &bigf, &r1)
 		p1 := gc.Gbranch(optoas(gc.OLE, f.Type), nil, +1)
@@ -556,10 +391,10 @@
 		gins(x86.AXORQ, &r4, &r2)
 		gc.Patch(p2, gc.Pc)
 		gmove(&r2, t)
-		regfree(&r4)
-		regfree(&r3)
-		regfree(&r2)
-		regfree(&r1)
+		gc.Regfree(&r4)
+		gc.Regfree(&r3)
+		gc.Regfree(&r2)
+		gc.Regfree(&r1)
 		return
 
 		/*
@@ -617,13 +452,13 @@
 		var one gc.Node
 		gc.Nodconst(&one, gc.Types[gc.TUINT64], 1)
 		var r1 gc.Node
-		regalloc(&r1, f.Type, f)
+		gc.Regalloc(&r1, f.Type, f)
 		var r2 gc.Node
-		regalloc(&r2, t.Type, t)
+		gc.Regalloc(&r2, t.Type, t)
 		var r3 gc.Node
-		regalloc(&r3, f.Type, nil)
+		gc.Regalloc(&r3, f.Type, nil)
 		var r4 gc.Node
-		regalloc(&r4, f.Type, nil)
+		gc.Regalloc(&r4, f.Type, nil)
 		gmove(f, &r1)
 		gins(x86.ACMPQ, &r1, &zero)
 		p1 := gc.Gbranch(x86.AJLT, nil, +1)
@@ -639,10 +474,10 @@
 		gins(optoas(gc.OADD, t.Type), &r2, &r2)
 		gc.Patch(p2, gc.Pc)
 		gmove(&r2, t)
-		regfree(&r4)
-		regfree(&r3)
-		regfree(&r2)
-		regfree(&r1)
+		gc.Regfree(&r4)
+		gc.Regfree(&r3)
+		gc.Regfree(&r2)
+		gc.Regfree(&r1)
 		return
 
 		/*
@@ -670,22 +505,22 @@
 rdst:
 	{
 		var r1 gc.Node
-		regalloc(&r1, t.Type, t)
+		gc.Regalloc(&r1, t.Type, t)
 
 		gins(a, f, &r1)
 		gmove(&r1, t)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		return
 	}
 
 	// requires register intermediate
 hard:
 	var r1 gc.Node
-	regalloc(&r1, cvt, t)
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 }
 
@@ -713,22 +548,35 @@
 	//	Node nod;
 
 	//	if(f != N && f->op == OINDEX) {
-	//		regalloc(&nod, &regnode, Z);
+	//		gc.Regalloc(&nod, &regnode, Z);
 	//		v = constnode.vconst;
-	//		cgen(f->right, &nod);
+	//		gc.Cgen(f->right, &nod);
 	//		constnode.vconst = v;
 	//		idx.reg = nod.reg;
-	//		regfree(&nod);
+	//		gc.Regfree(&nod);
 	//	}
 	//	if(t != N && t->op == OINDEX) {
-	//		regalloc(&nod, &regnode, Z);
+	//		gc.Regalloc(&nod, &regnode, Z);
 	//		v = constnode.vconst;
-	//		cgen(t->right, &nod);
+	//		gc.Cgen(t->right, &nod);
 	//		constnode.vconst = v;
 	//		idx.reg = nod.reg;
-	//		regfree(&nod);
+	//		gc.Regfree(&nod);
 	//	}
 
+	if f != nil && f.Op == gc.OADDR && (as == x86.AMOVL || as == x86.AMOVQ) {
+		// Turn MOVL $xxx into LEAL xxx.
+		// These should be equivalent but most of the backend
+		// only expects to see LEAL, because that's what we had
+		// historically generated. Various hidden assumptions are baked in by now.
+		if as == x86.AMOVL {
+			as = x86.ALEAL
+		} else {
+			as = x86.ALEAQ
+		}
+		f = f.Left
+	}
+
 	switch as {
 	case x86.AMOVB,
 		x86.AMOVW,
@@ -782,27 +630,13 @@
 	return p
 }
 
-func fixlargeoffset(n *gc.Node) {
-	if n == nil {
-		return
-	}
-	if n.Op != gc.OINDREG {
-		return
-	}
-	if n.Val.U.Reg == x86.REG_SP { // stack offset cannot be large
-		return
-	}
-	if n.Xoffset != int64(int32(n.Xoffset)) {
-		// offset too large, add to register instead.
-		a := *n
-
-		a.Op = gc.OREGISTER
-		a.Type = gc.Types[gc.Tptr]
-		a.Xoffset = 0
-		gc.Cgen_checknil(&a)
-		ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, &a)
-		n.Xoffset = 0
-	}
+func ginsnop() {
+	// This is actually not the x86 NOP anymore,
+	// but at the point where it gets used, AX is dead
+	// so it's okay if we lose the high bits.
+	var reg gc.Node
+	gc.Nodreg(&reg, gc.Types[gc.TINT], x86.REG_AX)
+	gins(x86.AXCHGL, &reg, &reg)
 }
 
 /*
@@ -854,6 +688,21 @@
 		gc.ONE<<16 | gc.TFLOAT64:
 		a = x86.AJNE
 
+	case gc.OPS<<16 | gc.TBOOL,
+		gc.OPS<<16 | gc.TINT8,
+		gc.OPS<<16 | gc.TUINT8,
+		gc.OPS<<16 | gc.TINT16,
+		gc.OPS<<16 | gc.TUINT16,
+		gc.OPS<<16 | gc.TINT32,
+		gc.OPS<<16 | gc.TUINT32,
+		gc.OPS<<16 | gc.TINT64,
+		gc.OPS<<16 | gc.TUINT64,
+		gc.OPS<<16 | gc.TPTR32,
+		gc.OPS<<16 | gc.TPTR64,
+		gc.OPS<<16 | gc.TFLOAT32,
+		gc.OPS<<16 | gc.TFLOAT64:
+		a = x86.AJPS
+
 	case gc.OLT<<16 | gc.TINT8,
 		gc.OLT<<16 | gc.TINT16,
 		gc.OLT<<16 | gc.TINT32,
@@ -1296,29 +1145,12 @@
 
 var cleani int = 0
 
-func xgen(n *gc.Node, a *gc.Node, o int) bool {
-	regalloc(a, gc.Types[gc.Tptr], nil)
-
-	if o&ODynam != 0 {
-		if n.Addable != 0 {
-			if n.Op != gc.OINDREG {
-				if n.Op != gc.OREGISTER {
-					return true
-				}
-			}
-		}
-	}
-
-	agen(n, a)
-	return false
-}
-
 func sudoclean() {
 	if clean[cleani-1].Op != gc.OEMPTY {
-		regfree(&clean[cleani-1])
+		gc.Regfree(&clean[cleani-1])
 	}
 	if clean[cleani-2].Op != gc.OEMPTY {
-		regfree(&clean[cleani-2])
+		gc.Regfree(&clean[cleani-2])
 	}
 	cleani -= 2
 }
@@ -1422,14 +1254,14 @@
 			return true
 		}
 
-		regalloc(reg, gc.Types[gc.Tptr], nil)
+		gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
 		n1 := *reg
 		n1.Op = gc.OINDREG
 		if oary[0] >= 0 {
-			agen(nn, reg)
+			gc.Agen(nn, reg)
 			n1.Xoffset = oary[0]
 		} else {
-			cgen(nn, reg)
+			gc.Cgen(nn, reg)
 			gc.Cgen_checknil(reg)
 			n1.Xoffset = -(oary[0] + 1)
 		}
@@ -1445,7 +1277,7 @@
 
 		a.Type = obj.TYPE_NONE
 		a.Index = obj.TYPE_NONE
-		fixlargeoffset(&n1)
+		gc.Fixlargeoffset(&n1)
 		gc.Naddr(a, &n1)
 		return true
 
diff --git a/src/cmd/7g/cgen.go b/src/cmd/7g/cgen.go
index b18ba5f..8d6dce4 100644
--- a/src/cmd/7g/cgen.go
+++ b/src/cmd/7g/cgen.go
@@ -8,1437 +8,9 @@
 	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
-	"fmt"
 )
 
-/*
- * peep.c
- */
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- */
-func cgen(n *gc.Node, res *gc.Node) {
-	//print("cgen %N(%d) -> %N(%d)\n", n, n->addable, res, res->addable);
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\ncgen-n", n)
-		gc.Dump("cgen-res", res)
-	}
-
-	if n == nil || n.Type == nil {
-		return
-	}
-
-	if res == nil || res.Type == nil {
-		gc.Fatal("cgen: res nil")
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	switch n.Op {
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_slice(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_slice(n, res)
-		}
-		return
-
-	case gc.OEFACE:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_eface(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_eface(n, res)
-		}
-		return
-	}
-
-	if n.Ullman >= gc.UINF {
-		if n.Op == gc.OINDREG {
-			gc.Fatal("cgen: this is going to misscompile")
-		}
-		if res.Ullman >= gc.UINF {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			cgen(n, &n1)
-			cgen(&n1, res)
-			return
-		}
-	}
-
-	if gc.Isfat(n.Type) {
-		if n.Type.Width < 0 {
-			gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0))
-		}
-		sgen(n, res, n.Type.Width)
-		return
-	}
-
-	if res.Addable == 0 {
-		if n.Ullman > res.Ullman {
-			var n1 gc.Node
-			regalloc(&n1, n.Type, res)
-			cgen(n, &n1)
-			if n1.Ullman > res.Ullman {
-				gc.Dump("n1", &n1)
-				gc.Dump("res", res)
-				gc.Fatal("loop in cgen")
-			}
-
-			cgen(&n1, res)
-			regfree(&n1)
-			return
-		}
-
-		var f int
-		if res.Ullman >= gc.UINF {
-			goto gen
-		}
-
-		if gc.Complexop(n, res) {
-			gc.Complexgen(n, res)
-			return
-		}
-
-		f = 1 // gen thru register
-		switch n.Op {
-		case gc.OLITERAL:
-			if gc.Smallintconst(n) {
-				f = 0
-			}
-
-		case gc.OREGISTER:
-			f = 0
-		}
-
-		if !gc.Iscomplex[n.Type.Etype] {
-			a := optoas(gc.OAS, res.Type)
-			var addr obj.Addr
-			if sudoaddable(a, res, &addr) {
-				var p1 *obj.Prog
-				if f != 0 {
-					var n2 gc.Node
-					regalloc(&n2, res.Type, nil)
-					cgen(n, &n2)
-					p1 = gins(a, &n2, nil)
-					regfree(&n2)
-				} else {
-					p1 = gins(a, n, nil)
-				}
-				p1.To = addr
-				if gc.Debug['g'] != 0 {
-					fmt.Printf("%v [ignore previous line]\n", p1)
-				}
-				sudoclean()
-				return
-			}
-		}
-
-	gen:
-		var n1 gc.Node
-		igen(res, &n1, nil)
-		cgen(n, &n1)
-		regfree(&n1)
-		return
-	}
-
-	// update addressability for string, slice
-	// can't do in walk because n->left->addable
-	// changes if n->left is an escaping local variable.
-	switch n.Op {
-	case gc.OSPTR,
-		gc.OLEN:
-		if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OCAP:
-		if gc.Isslice(n.Left.Type) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OITAB:
-		n.Addable = n.Left.Addable
-	}
-
-	if gc.Complexop(n, res) {
-		gc.Complexgen(n, res)
-		return
-	}
-
-	// if both are addressable, move
-	if n.Addable != 0 {
-		if n.Op == gc.OREGISTER || res.Op == gc.OREGISTER {
-			gmove(n, res)
-		} else {
-			var n1 gc.Node
-			regalloc(&n1, n.Type, nil)
-			gmove(n, &n1)
-			cgen(&n1, res)
-			regfree(&n1)
-		}
-
-		return
-	}
-
-	nl := n.Left
-	nr := n.Right
-
-	if nl != nil && nl.Ullman >= gc.UINF {
-		if nr != nil && nr.Ullman >= gc.UINF {
-			var n1 gc.Node
-			gc.Tempname(&n1, nl.Type)
-			cgen(nl, &n1)
-			n2 := *n
-			n2.Left = &n1
-			cgen(&n2, res)
-			return
-		}
-	}
-
-	if !gc.Iscomplex[n.Type.Etype] {
-		a := optoas(gc.OAS, n.Type)
-		var addr obj.Addr
-		if sudoaddable(a, n, &addr) {
-			if res.Op == gc.OREGISTER {
-				p1 := gins(a, nil, res)
-				p1.From = addr
-			} else {
-				var n2 gc.Node
-				regalloc(&n2, n.Type, nil)
-				p1 := gins(a, nil, &n2)
-				p1.From = addr
-				gins(a, &n2, res)
-				regfree(&n2)
-			}
-
-			sudoclean()
-			return
-		}
-	}
-
-	// TODO(minux): we shouldn't reverse FP comparisons, but then we need to synthesize
-	// OGE, OLE, and ONE ourselves.
-	// if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) goto flt;
-
-	var a int
-	switch n.Op {
-	default:
-		gc.Dump("cgen", n)
-		gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign))
-
-		// these call bgen to get a bool value
-	case gc.OOROR,
-		gc.OANDAND,
-		gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OLE,
-		gc.OGE,
-		gc.OGT,
-		gc.ONOT:
-		p1 := gc.Gbranch(arm64.AB, nil, 0)
-
-		p2 := gc.Pc
-		gmove(gc.Nodbool(true), res)
-		p3 := gc.Gbranch(arm64.AB, nil, 0)
-		gc.Patch(p1, gc.Pc)
-		bgen(n, true, 0, p2)
-		gmove(gc.Nodbool(false), res)
-		gc.Patch(p3, gc.Pc)
-		return
-
-	case gc.OPLUS:
-		cgen(nl, res)
-		return
-
-		// unary
-	case gc.OCOM:
-		a := optoas(gc.OXOR, nl.Type)
-
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-		var n2 gc.Node
-		gc.Nodconst(&n2, nl.Type, -1)
-		gins(a, &n2, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		return
-
-	case gc.OMINUS:
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-		gins(optoas(gc.OMINUS, nl.Type), &n1, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		return
-
-		// symmetric binary
-	case gc.OAND,
-		gc.OOR,
-		gc.OXOR,
-		gc.OADD,
-		gc.OMUL:
-		a = optoas(int(n.Op), nl.Type)
-
-		goto sbop
-
-		// asymmetric binary
-	case gc.OSUB:
-		a = optoas(int(n.Op), nl.Type)
-
-		goto abop
-
-	case gc.OHMUL:
-		cgen_hmul(nl, nr, res)
-
-	case gc.OCONV:
-		if n.Type.Width > nl.Type.Width {
-			// If loading from memory, do conversion during load,
-			// so as to avoid use of 8-bit register in, say, int(*byteptr).
-			switch nl.Op {
-			case gc.ODOT,
-				gc.ODOTPTR,
-				gc.OINDEX,
-				gc.OIND,
-				gc.ONAME:
-				var n1 gc.Node
-				igen(nl, &n1, res)
-				var n2 gc.Node
-				regalloc(&n2, n.Type, res)
-				gmove(&n1, &n2)
-				gmove(&n2, res)
-				regfree(&n2)
-				regfree(&n1)
-				return
-			}
-		}
-
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-		var n2 gc.Node
-		regalloc(&n2, n.Type, &n1)
-		cgen(nl, &n1)
-
-		// if we do the conversion n1 -> n2 here
-		// reusing the register, then gmove won't
-		// have to allocate its own register.
-		gmove(&n1, &n2)
-
-		gmove(&n2, res)
-		regfree(&n2)
-		regfree(&n1)
-
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OIND,
-		gc.ONAME: // PHEAP or PPARAMREF var
-		var n1 gc.Node
-		igen(n, &n1, res)
-
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// interface table is first word of interface value
-	case gc.OITAB:
-		var n1 gc.Node
-		igen(nl, &n1, res)
-
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// pointer is the first word of string or slice.
-	case gc.OSPTR:
-		if gc.Isconst(nl, gc.CTSTR) {
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-			p1 := gins(arm64.AMOVD, nil, &n1)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		var n1 gc.Node
-		igen(nl, &n1, res)
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-	case gc.OLEN:
-		if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) {
-			// map and chan have len in the first int-sized word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-
-			cgen(nl, &n1)
-
-			var n2 gc.Node
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Type = gc.Types[gc.Simtype[gc.TINT]]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) {
-			// both slice and string have len one pointer into the struct.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			igen(nl, &n1, res)
-
-			n1.Type = gc.Types[gc.Simtype[gc.TUINT]]
-			n1.Xoffset += int64(gc.Array_nel)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OCAP:
-		if gc.Istype(nl.Type, gc.TCHAN) {
-			// chan has cap in the second int-sized word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-
-			cgen(nl, &n1)
-
-			var n2 gc.Node
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Xoffset = int64(gc.Widthint)
-			n2.Type = gc.Types[gc.Simtype[gc.TINT]]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isslice(nl.Type) {
-			var n1 gc.Node
-			igen(nl, &n1, res)
-			n1.Type = gc.Types[gc.Simtype[gc.TUINT]]
-			n1.Xoffset += int64(gc.Array_cap)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OADDR:
-		if n.Bounded { // let race detector avoid nil checks
-			gc.Disable_checknil++
-		}
-		agen(nl, res)
-		if n.Bounded {
-			gc.Disable_checknil--
-		}
-
-	case gc.OCALLMETH:
-		gc.Cgen_callmeth(n, 0)
-		cgen_callret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_callret(n, res)
-
-	case gc.OCALLFUNC:
-		cgen_call(n, 0)
-		cgen_callret(n, res)
-
-	case gc.OMOD,
-		gc.ODIV:
-		if gc.Isfloat[n.Type.Etype] {
-			a = optoas(int(n.Op), nl.Type)
-			goto abop
-		}
-
-		if nl.Ullman >= nr.Ullman {
-			var n1 gc.Node
-			regalloc(&n1, nl.Type, res)
-			cgen(nl, &n1)
-			cgen_div(int(n.Op), &n1, nr, res)
-			regfree(&n1)
-		} else {
-			var n2 gc.Node
-			if !gc.Smallintconst(nr) {
-				regalloc(&n2, nr.Type, res)
-				cgen(nr, &n2)
-			} else {
-				n2 = *nr
-			}
-
-			cgen_div(int(n.Op), nl, &n2, res)
-			if n2.Op != gc.OLITERAL {
-				regfree(&n2)
-			}
-		}
-
-	case gc.OLSH,
-		gc.ORSH,
-		gc.OLROT:
-		cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
-	}
-
-	return
-
-	/*
-	 * put simplest on right - we'll generate into left
-	 * and then adjust it using the computation of right.
-	 * constants and variables have the same ullman
-	 * count, so look for constants specially.
-	 *
-	 * an integer constant we can use as an immediate
-	 * is simpler than a variable - we can use the immediate
-	 * in the adjustment instruction directly - so it goes
-	 * on the right.
-	 *
-	 * other constants, like big integers or floating point
-	 * constants, require a mov into a register, so those
-	 * might as well go on the left, so we can reuse that
-	 * register for the computation.
-	 */
-sbop: // symmetric binary
-	if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (gc.Smallintconst(nl) || (nr.Op == gc.OLITERAL && !gc.Smallintconst(nr)))) {
-		r := nl
-		nl = nr
-		nr = r
-	}
-
-abop: // asymmetric binary
-	var n1 gc.Node
-	var n2 gc.Node
-	if nl.Ullman >= nr.Ullman {
-		regalloc(&n1, nl.Type, res)
-		cgen(nl, &n1)
-
-		/*
-			 * This generates smaller code - it avoids a MOV - but it's
-			 * easily 10% slower due to not being able to
-			 * optimize/manipulate the move.
-			 * To see, run: go test -bench . crypto/md5
-			 * with and without.
-			 *
-				if(sudoaddable(a, nr, &addr)) {
-					p1 = gins(a, N, &n1);
-					p1->from = addr;
-					gmove(&n1, res);
-					sudoclean();
-					regfree(&n1);
-					goto ret;
-				}
-			 *
-		*/
-		// TODO(minux): enable using constants directly in certain instructions.
-		//if(smallintconst(nr))
-		//	n2 = *nr;
-		//else {
-		regalloc(&n2, nr.Type, nil)
-
-		cgen(nr, &n2)
-	} else //}
-	{
-		//if(smallintconst(nr))
-		//	n2 = *nr;
-		//else {
-		regalloc(&n2, nr.Type, res)
-
-		cgen(nr, &n2)
-
-		//}
-		regalloc(&n1, nl.Type, nil)
-
-		cgen(nl, &n1)
-	}
-
-	gins(a, &n2, &n1)
-
-	// Normalize result for types smaller than word.
-	if n.Type.Width < int64(gc.Widthreg) {
-		switch n.Op {
-		case gc.OADD,
-			gc.OSUB,
-			gc.OMUL,
-			gc.OLSH:
-			gins(optoas(gc.OAS, n.Type), &n1, &n1)
-		}
-	}
-
-	gmove(&n1, res)
-	regfree(&n1)
-	if n2.Op != gc.OLITERAL {
-		regfree(&n2)
-	}
-	return
-}
-
-/*
- * allocate a register (reusing res if possible) and generate
- *  a = n
- * The caller must call regfree(a).
- */
-func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("cgenr-n", n)
-	}
-
-	if gc.Isfat(n.Type) {
-		gc.Fatal("cgenr on fat node")
-	}
-
-	if n.Addable != 0 {
-		regalloc(a, n.Type, res)
-		gmove(n, a)
-		return
-	}
-
-	switch n.Op {
-	case gc.ONAME,
-		gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		var n1 gc.Node
-		igen(n, &n1, res)
-		regalloc(a, gc.Types[gc.Tptr], &n1)
-		gmove(&n1, a)
-		regfree(&n1)
-
-	default:
-		regalloc(a, n.Type, res)
-		cgen(n, a)
-	}
-}
-
-/*
- * allocate a register (reusing res if possible) and generate
- * a = &n
- * The caller must call regfree(a).
- * The generated code checks that the result is not nil.
- */
-func agenr(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("agenr-n", n)
-	}
-
-	nl := n.Left
-	nr := n.Right
-
-	switch n.Op {
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		var n1 gc.Node
-		igen(n, &n1, res)
-		regalloc(a, gc.Types[gc.Tptr], &n1)
-		agen(&n1, a)
-		regfree(&n1)
-
-	case gc.OIND:
-		cgenr(n.Left, a, res)
-		gc.Cgen_checknil(a)
-
-	case gc.OINDEX:
-		p2 := (*obj.Prog)(nil) // to be patched to panicindex.
-		w := uint32(n.Type.Width)
-
-		//bounded = debug['B'] || n->bounded;
-		var n3 gc.Node
-		var n1 gc.Node
-		if nr.Addable != 0 {
-			var tmp gc.Node
-			if !gc.Isconst(nr, gc.CTINT) {
-				gc.Tempname(&tmp, gc.Types[gc.TINT64])
-			}
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-			if !gc.Isconst(nr, gc.CTINT) {
-				cgen(nr, &tmp)
-				regalloc(&n1, tmp.Type, nil)
-				gmove(&tmp, &n1)
-			}
-		} else if nl.Addable != 0 {
-			if !gc.Isconst(nr, gc.CTINT) {
-				var tmp gc.Node
-				gc.Tempname(&tmp, gc.Types[gc.TINT64])
-				cgen(nr, &tmp)
-				regalloc(&n1, tmp.Type, nil)
-				gmove(&tmp, &n1)
-			}
-
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-		} else {
-			var tmp gc.Node
-			gc.Tempname(&tmp, gc.Types[gc.TINT64])
-			cgen(nr, &tmp)
-			nr = &tmp
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-			regalloc(&n1, tmp.Type, nil)
-			gins(optoas(gc.OAS, tmp.Type), &tmp, &n1)
-		}
-
-		// &a is in &n3 (allocated in res)
-		// i is in &n1 (if not constant)
-		// w is width
-
-		// constant index
-		if gc.Isconst(nr, gc.CTINT) {
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Fatal("constant string constant index")
-			}
-			v := uint64(gc.Mpgetfix(nr.Val.U.Xval))
-			if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				if gc.Debug['B'] == 0 && !n.Bounded {
-					n1 = n3
-					n1.Op = gc.OINDREG
-					n1.Type = gc.Types[gc.Tptr]
-					n1.Xoffset = int64(gc.Array_nel)
-					var n4 gc.Node
-					regalloc(&n4, n1.Type, nil)
-					gmove(&n1, &n4)
-					ginscon2(optoas(gc.OCMP, gc.Types[gc.TUINT64]), &n4, int64(v))
-					regfree(&n4)
-					p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT64]), nil, +1)
-					ginscall(gc.Panicindex, 0)
-					gc.Patch(p1, gc.Pc)
-				}
-
-				n1 = n3
-				n1.Op = gc.OINDREG
-				n1.Type = gc.Types[gc.Tptr]
-				n1.Xoffset = int64(gc.Array_array)
-				gmove(&n1, &n3)
-			}
-
-			if v*uint64(w) != 0 {
-				ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), int64(v*uint64(w)), &n3)
-			}
-
-			*a = n3
-			break
-		}
-
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.TINT64], &n1) // i
-		gmove(&n1, &n2)
-		regfree(&n1)
-
-		var n4 gc.Node
-		if gc.Debug['B'] == 0 && !n.Bounded {
-			// check bounds
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Nodconst(&n4, gc.Types[gc.TUINT64], int64(len(nl.Val.U.Sval)))
-			} else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				n1 = n3
-				n1.Op = gc.OINDREG
-				n1.Type = gc.Types[gc.Tptr]
-				n1.Xoffset = int64(gc.Array_nel)
-				regalloc(&n4, gc.Types[gc.TUINT64], nil)
-				gmove(&n1, &n4)
-			} else {
-				if nl.Type.Bound < (1<<15)-1 {
-					gc.Nodconst(&n4, gc.Types[gc.TUINT64], nl.Type.Bound)
-				} else {
-					regalloc(&n4, gc.Types[gc.TUINT64], nil)
-					p1 := gins(arm64.AMOVD, nil, &n4)
-					p1.From.Type = obj.TYPE_CONST
-					p1.From.Offset = nl.Type.Bound
-				}
-			}
-
-			gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT64]), &n2, &n4)
-			if n4.Op == gc.OREGISTER {
-				regfree(&n4)
-			}
-			p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1)
-			if p2 != nil {
-				gc.Patch(p2, gc.Pc)
-			}
-			ginscall(gc.Panicindex, 0)
-			gc.Patch(p1, gc.Pc)
-		}
-
-		if gc.Isconst(nl, gc.CTSTR) {
-			regalloc(&n3, gc.Types[gc.Tptr], res)
-			p1 := gins(arm64.AMOVD, nil, &n3)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			p1.From.Type = obj.TYPE_ADDR
-		} else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-			n1 = n3
-			n1.Op = gc.OINDREG
-			n1.Type = gc.Types[gc.Tptr]
-			n1.Xoffset = int64(gc.Array_array)
-			gmove(&n1, &n3)
-		}
-
-		if w == 0 {
-		} else // nothing to do
-		if w == 1 {
-			/* w already scaled */
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			/* else if(w == 2 || w == 4 || w == 8) {
-				// TODO(minux): scale using shift
-			} */
-		} else {
-			regalloc(&n4, gc.Types[gc.TUINT64], nil)
-			gc.Nodconst(&n1, gc.Types[gc.TUINT64], int64(w))
-			gmove(&n1, &n4)
-			gins(optoas(gc.OMUL, gc.Types[gc.TUINT64]), &n4, &n2)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			regfree(&n4)
-		}
-
-		*a = n3
-		regfree(&n2)
-
-	default:
-		regalloc(a, gc.Types[gc.Tptr], res)
-		agen(n, a)
-	}
-}
-
-func ginsadd(as int, off int64, dst *gc.Node) {
-	var n1 gc.Node
-
-	regalloc(&n1, gc.Types[gc.Tptr], dst)
-	gmove(dst, &n1)
-	ginscon(as, off, &n1)
-	gmove(&n1, dst)
-	regfree(&n1)
-}
-
-/*
- * generate:
- *	res = &n;
- * The generated code checks that the result is not nil.
- */
-func agen(n *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nagen-res", res)
-		gc.Dump("agen-r", n)
-	}
-
-	if n == nil || n.Type == nil {
-		return
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) {
-		// Use of a nil interface or nil slice.
-		// Create a temporary we can take the address of and read.
-		// The generated code is just going to panic, so it need not
-		// be terribly efficient. See issue 3670.
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-
-		gc.Gvardef(&n1)
-		clearfat(&n1)
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.Tptr], res)
-		var n3 gc.Node
-		n3.Op = gc.OADDR
-		n3.Left = &n1
-		gins(arm64.AMOVD, &n3, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		return
-	}
-
-	if n.Addable != 0 {
-		var n1 gc.Node
-		n1.Op = gc.OADDR
-		n1.Left = n
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.Tptr], res)
-		gins(arm64.AMOVD, &n1, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		return
-	}
-
-	nl := n.Left
-
-	switch n.Op {
-	default:
-		gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign))
-
-		// TODO(minux): 5g has this: Release res so that it is available for cgen_call.
-	// Pick it up again after the call for OCALLMETH and OCALLFUNC.
-	case gc.OCALLMETH:
-		gc.Cgen_callmeth(n, 0)
-
-		cgen_aret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_aret(n, res)
-
-	case gc.OCALLFUNC:
-		cgen_call(n, 0)
-		cgen_aret(n, res)
-
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_slice(n, &n1)
-		agen(&n1, res)
-
-	case gc.OEFACE:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_eface(n, &n1)
-		agen(&n1, res)
-
-	case gc.OINDEX:
-		var n1 gc.Node
-		agenr(n, &n1, res)
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// should only get here with names in this func.
-	case gc.ONAME:
-		if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth)
-		}
-
-		// should only get here for heap vars or paramref
-		if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME class %#x", n.Class)
-		}
-
-		cgen(n.Heapaddr, res)
-		if n.Xoffset != 0 {
-			ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-
-	case gc.OIND:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-
-	case gc.ODOT:
-		agen(nl, res)
-		if n.Xoffset != 0 {
-			ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-
-	case gc.ODOTPTR:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-		if n.Xoffset != 0 {
-			ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-	}
-}
-
-/*
- * generate:
- *	newreg = &n;
- *	res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- * The generated code checks that the result is not *nil.
- */
-func igen(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nigen-n", n)
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF {
-			break
-		}
-		*a = *n
-		return
-
-		// Increase the refcount of the register so that igen's caller
-	// has to call regfree.
-	case gc.OINDREG:
-		if n.Val.U.Reg != arm64.REGSP {
-			reg[n.Val.U.Reg]++
-		}
-		*a = *n
-		return
-
-	case gc.ODOT:
-		igen(n.Left, a, res)
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		fixlargeoffset(a)
-		return
-
-	case gc.ODOTPTR:
-		cgenr(n.Left, a, res)
-		gc.Cgen_checknil(a)
-		a.Op = gc.OINDREG
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		fixlargeoffset(a)
-		return
-
-	case gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		switch n.Op {
-		case gc.OCALLFUNC:
-			cgen_call(n, 0)
-
-		case gc.OCALLMETH:
-			gc.Cgen_callmeth(n, 0)
-
-		case gc.OCALLINTER:
-			cgen_callinter(n, nil, 0)
-		}
-
-		var flist gc.Iter
-		fp := gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type))
-		*a = gc.Node{}
-		a.Op = gc.OINDREG
-		a.Val.U.Reg = arm64.REGSP
-		a.Addable = 1
-		a.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP)
-		a.Type = n.Type
-		return
-
-		// Index of fixed-size array by constant can
-	// put the offset in the addressing.
-	// Could do the same for slice except that we need
-	// to use the real index for the bounds checking.
-	case gc.OINDEX:
-		if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] && gc.Isfixedarray(n.Left.Left.Type)) {
-			if gc.Isconst(n.Right, gc.CTINT) {
-				// Compute &a.
-				if !gc.Isptr[n.Left.Type.Etype] {
-					igen(n.Left, a, res)
-				} else {
-					var n1 gc.Node
-					igen(n.Left, &n1, res)
-					gc.Cgen_checknil(&n1)
-					regalloc(a, gc.Types[gc.Tptr], res)
-					gmove(&n1, a)
-					regfree(&n1)
-					a.Op = gc.OINDREG
-				}
-
-				// Compute &a[i] as &a + i*width.
-				a.Type = n.Type
-
-				a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
-				fixlargeoffset(a)
-				return
-			}
-		}
-	}
-
-	agenr(n, a, res)
-	a.Op = gc.OINDREG
-	a.Type = n.Type
-}
-
-/*
- * generate:
- *	if(n == true) goto to;
- */
-func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nbgen", n)
-	}
-
-	if n == nil {
-		n = gc.Nodbool(true)
-	}
-
-	if n.Ninit != nil {
-		gc.Genlist(n.Ninit)
-	}
-
-	if n.Type == nil {
-		gc.Convlit(&n, gc.Types[gc.TBOOL])
-		if n.Type == nil {
-			return
-		}
-	}
-
-	et := int(n.Type.Etype)
-	if et != gc.TBOOL {
-		gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0))
-		gc.Patch(gins(obj.AEND, nil, nil), to)
-		return
-	}
-
-	var nr *gc.Node
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-		if n.Ninit != nil {
-			gc.Genlist(n.Ninit)
-		}
-	}
-
-	var nl *gc.Node
-	switch n.Op {
-	default:
-		var n1 gc.Node
-		regalloc(&n1, n.Type, nil)
-		cgen(n, &n1)
-		var n2 gc.Node
-		gc.Nodconst(&n2, n.Type, 0)
-		gcmp(optoas(gc.OCMP, n.Type), &n1, &n2)
-		a := arm64.ABNE
-		if !true_ {
-			a = arm64.ABEQ
-		}
-		gc.Patch(gc.Gbranch(a, n.Type, likely), to)
-		regfree(&n1)
-		return
-
-		// need to ask if it is bool?
-	case gc.OLITERAL:
-		if !true_ == (n.Val.U.Bval == 0) {
-			gc.Patch(gc.Gbranch(arm64.AB, nil, likely), to)
-		}
-		return
-
-	case gc.OANDAND,
-		gc.OOROR:
-		if (n.Op == gc.OANDAND) == true_ {
-			p1 := gc.Gbranch(obj.AJMP, nil, 0)
-			p2 := gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, gc.Pc)
-			bgen(n.Left, !true_, -likely, p2)
-			bgen(n.Right, !true_, -likely, p2)
-			p1 = gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, to)
-			gc.Patch(p2, gc.Pc)
-		} else {
-			bgen(n.Left, true_, likely, to)
-			bgen(n.Right, true_, likely, to)
-		}
-
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			return
-		}
-		fallthrough
-
-	case gc.ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
-			return
-		}
-	}
-
-	switch n.Op {
-	case gc.ONOT:
-		bgen(nl, !true_, likely, to)
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		a := int(n.Op)
-		if !true_ {
-			if gc.Isfloat[nr.Type.Etype] {
-				// brcom is not valid on floats when NaN is involved.
-				p1 := gc.Gbranch(arm64.AB, nil, 0)
-
-				p2 := gc.Gbranch(arm64.AB, nil, 0)
-				gc.Patch(p1, gc.Pc)
-				ll := n.Ninit // avoid re-genning ninit
-				n.Ninit = nil
-				bgen(n, true, -likely, p2)
-				n.Ninit = ll
-				gc.Patch(gc.Gbranch(arm64.AB, nil, 0), to)
-				gc.Patch(p2, gc.Pc)
-				return
-			}
-
-			a = gc.Brcom(a)
-			true_ = !true_
-		}
-
-		// make simplest on right
-		if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) {
-			a = gc.Brrev(a)
-			r := nl
-			nl = nr
-			nr = r
-		}
-
-		if gc.Isslice(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal slice comparison")
-				break
-			}
-
-			a = optoas(a, gc.Types[gc.Tptr])
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Xoffset += int64(gc.Array_array)
-			n1.Type = gc.Types[gc.Tptr]
-			var tmp gc.Node
-			gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
-			var n2 gc.Node
-			regalloc(&n2, gc.Types[gc.Tptr], &n1)
-			gmove(&n1, &n2)
-			gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp)
-			regfree(&n2)
-			gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isinter(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal interface comparison")
-				break
-			}
-
-			a = optoas(a, gc.Types[gc.Tptr])
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Type = gc.Types[gc.Tptr]
-			var tmp gc.Node
-			gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
-			var n2 gc.Node
-			regalloc(&n2, gc.Types[gc.Tptr], &n1)
-			gmove(&n1, &n2)
-			gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp)
-			regfree(&n2)
-			gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Iscomplex[nl.Type.Etype] {
-			gc.Complexbool(a, nl, nr, true_, likely, to)
-			break
-		}
-
-		var n1 gc.Node
-		var n2 gc.Node
-		if nr.Ullman >= gc.UINF {
-			regalloc(&n1, nl.Type, nil)
-			cgen(nl, &n1)
-
-			var tmp gc.Node
-			gc.Tempname(&tmp, nl.Type)
-			gmove(&n1, &tmp)
-			regfree(&n1)
-
-			regalloc(&n2, nr.Type, nil)
-			cgen(nr, &n2)
-
-			regalloc(&n1, nl.Type, nil)
-			cgen(&tmp, &n1)
-
-			goto cmp
-		}
-
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-		regalloc(&n2, nr.Type, nil)
-		cgen(nr, &n2)
-
-	cmp:
-		l := &n1
-		r := &n2
-		gcmp(optoas(gc.OCMP, nr.Type), l, r)
-		if gc.Isfloat[nr.Type.Etype] && (a == gc.OLE || a == gc.OGE) {
-			// To get NaN right, must rewrite x <= y into separate x < y or x = y.
-			switch a {
-			case gc.OLE:
-				a = gc.OLT
-
-			case gc.OGE:
-				a = gc.OGT
-			}
-
-			gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-			gc.Patch(gc.Gbranch(optoas(gc.OEQ, nr.Type), nr.Type, likely), to)
-		} else {
-			gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-		}
-
-		regfree(&n1)
-		regfree(&n2)
-	}
-
-	return
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-func stkof(n *gc.Node) int64 {
-	switch n.Op {
-	case gc.OINDREG:
-		return n.Xoffset
-
-	case gc.ODOT:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		return off + n.Xoffset
-
-	case gc.OINDEX:
-		t := n.Left.Type
-		if !gc.Isfixedarray(t) {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		if gc.Isconst(n.Right, gc.CTINT) {
-			return off + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval)
-		}
-		return 1000
-
-	case gc.OCALLMETH,
-		gc.OCALLINTER,
-		gc.OCALLFUNC:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			t = t.Type
-		}
-
-		var flist gc.Iter
-		t = gc.Structfirst(&flist, gc.Getoutarg(t))
-		if t != nil {
-			return t.Width + int64(gc.Widthptr) // +widthptr: correct for saved LR
-		}
-	}
-
-	// botch - probably failing to recognize address
-	// arithmetic on the above. eg INDEX and DOT
-	return -1000
-}
-
-/*
- * block copy:
- *	memmove(&ns, &n, w);
- */
-func sgen(n *gc.Node, ns *gc.Node, w int64) {
-	var res *gc.Node = ns
-
-	if gc.Debug['g'] != 0 {
-		fmt.Printf("\nsgen w=%d\n", w)
-		gc.Dump("r", n)
-		gc.Dump("res", ns)
-	}
-
-	if n.Ullman >= gc.UINF && ns.Ullman >= gc.UINF {
-		gc.Fatal("sgen UINF")
-	}
-
-	if w < 0 {
-		gc.Fatal("sgen copy %d", w)
-	}
-
-	// If copying .args, that's all the results, so record definition sites
-	// for them for the liveness analysis.
-	if ns.Op == gc.ONAME && ns.Sym.Name == ".args" {
-		for l := gc.Curfn.Dcl; l != nil; l = l.Next {
-			if l.N.Class == gc.PPARAMOUT {
-				gc.Gvardef(l.N)
-			}
-		}
-	}
-
-	// Avoid taking the address for simple enough types.
-	//if gc.Componentgen(n, ns) {
-	//	return
-	//}
-
-	if w == 0 {
-		// evaluate side effects only.
-		var dst gc.Node
-		regalloc(&dst, gc.Types[gc.Tptr], nil)
-
-		agen(res, &dst)
-		agen(n, &dst)
-		regfree(&dst)
-		return
-	}
-
+func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// determine alignment.
 	// want to avoid unaligned access, so have to use
 	// smaller operations for less aligned types.
@@ -1468,24 +40,7 @@
 	}
 	c := int32(w / int64(align))
 
-	// offset on the stack
-	osrc := int32(stkof(n))
-
-	odst := int32(stkof(res))
-	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
-		// osrc and odst both on stack, and at least one is in
-		// an unknown position.  Could generate code to test
-		// for forward/backward copy, but instead just copy
-		// to a temporary location first.
-		var tmp gc.Node
-		gc.Tempname(&tmp, n.Type)
-
-		sgen(n, &tmp, w)
-		sgen(&tmp, res, w)
-		return
-	}
-
-	if osrc%int32(align) != 0 || odst%int32(align) != 0 {
+	if osrc%int64(align) != 0 || odst%int64(align) != 0 {
 		gc.Fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align)
 	}
 
@@ -1500,23 +55,23 @@
 	var dst gc.Node
 	var src gc.Node
 	if n.Ullman >= res.Ullman {
-		agenr(n, &dst, res) // temporarily use dst
-		regalloc(&src, gc.Types[gc.Tptr], nil)
+		gc.Agenr(n, &dst, res) // temporarily use dst
+		gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
 		gins(arm64.AMOVD, &dst, &src)
 		if res.Op == gc.ONAME {
 			gc.Gvardef(res)
 		}
-		agen(res, &dst)
+		gc.Agen(res, &dst)
 	} else {
 		if res.Op == gc.ONAME {
 			gc.Gvardef(res)
 		}
-		agenr(res, &dst, res)
-		agenr(n, &src, nil)
+		gc.Agenr(res, &dst, res)
+		gc.Agenr(n, &src, nil)
 	}
 
 	var tmp gc.Node
-	regalloc(&tmp, gc.Types[gc.Tptr], nil)
+	gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
 
 	// set up end marker
 	var nend gc.Node
@@ -1524,7 +79,7 @@
 	// move src and dest to the end of block if necessary
 	if dir < 0 {
 		if c >= 4 {
-			regalloc(&nend, gc.Types[gc.Tptr], nil)
+			gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
 			gins(arm64.AMOVD, &src, &nend)
 		}
 
@@ -1545,7 +100,7 @@
 		p.From.Offset = int64(-dir)
 
 		if c >= 4 {
-			regalloc(&nend, gc.Types[gc.Tptr], nil)
+			gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
 			p := gins(arm64.AMOVD, &src, &nend)
 			p.From.Type = obj.TYPE_ADDR
 			p.From.Offset = w
@@ -1569,7 +124,7 @@
 		p = gcmp(arm64.ACMP, &src, &nend)
 
 		gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), ploop)
-		regfree(&nend)
+		gc.Regfree(&nend)
 	} else {
 		// TODO(austin): Instead of generating ADD $-8,R8; ADD
 		// $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just
@@ -1596,7 +151,7 @@
 		}
 	}
 
-	regfree(&dst)
-	regfree(&src)
-	regfree(&tmp)
+	gc.Regfree(&dst)
+	gc.Regfree(&src)
+	gc.Regfree(&tmp)
 }
diff --git a/src/cmd/7g/galign.go b/src/cmd/7g/galign.go
index 19c4d38..1c50c21 100644
--- a/src/cmd/7g/galign.go
+++ b/src/cmd/7g/galign.go
@@ -44,33 +44,38 @@
 	gc.Thearch.Typedefs = typedefs
 	gc.Thearch.REGSP = arm64.REGSP
 	gc.Thearch.REGCTXT = arm64.REGCTXT
+	gc.Thearch.REGCALLX = arm64.REGRT1
+	gc.Thearch.REGCALLX2 = arm64.REGRT2
+	gc.Thearch.REGRETURN = arm64.REG_R0
+	gc.Thearch.REGMIN = arm64.REG_R0
+	gc.Thearch.REGMAX = arm64.REG_R31
+	gc.Thearch.FREGMIN = arm64.REG_F0
+	gc.Thearch.FREGMAX = arm64.REG_F31
 	gc.Thearch.MAXWIDTH = MAXWIDTH
-	gc.Thearch.Anyregalloc = anyregalloc
+	gc.Thearch.ReservedRegs = resvd
+
 	gc.Thearch.Betypeinit = betypeinit
-	gc.Thearch.Bgen = bgen
-	gc.Thearch.Cgen = cgen
-	gc.Thearch.Cgen_call = cgen_call
-	gc.Thearch.Cgen_callinter = cgen_callinter
-	gc.Thearch.Cgen_ret = cgen_ret
+	gc.Thearch.Cgen_hmul = cgen_hmul
+	gc.Thearch.Cgen_shift = cgen_shift
 	gc.Thearch.Clearfat = clearfat
 	gc.Thearch.Defframe = defframe
+	gc.Thearch.Dodiv = dodiv
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
-	gc.Thearch.Gclean = gclean
-	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
-	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
-	gc.Thearch.Igen = igen
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
 	gc.Thearch.Proginfo = proginfo
-	gc.Thearch.Regalloc = regalloc
-	gc.Thearch.Regfree = regfree
 	gc.Thearch.Regtyp = regtyp
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
+	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Sudoaddable = sudoaddable
+	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
 	gc.Thearch.RtoB = RtoB
 	gc.Thearch.FtoB = RtoB
diff --git a/src/cmd/7g/ggen.go b/src/cmd/7g/ggen.go
index cb48663..6bf60f8 100644
--- a/src/cmd/7g/ggen.go
+++ b/src/cmd/7g/ggen.go
@@ -116,316 +116,10 @@
 	return q
 }
 
-/*
- * generate:
- *	call f
- *	proc=-1	normal call but no return
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
-  *	proc=3	normal call to C pointer (not Go func value)
-*/
-func ginscall(f *gc.Node, proc int) {
-	if f.Type != nil {
-		extra := int32(0)
-		if proc == 1 || proc == 2 {
-			extra = 2 * int32(gc.Widthptr)
-		}
-		gc.Setmaxarg(f.Type, extra)
-	}
-
-	switch proc {
-	default:
-		gc.Fatal("ginscall: bad proc %d", proc)
-
-	case 0, // normal call
-		-1: // normal call but no return
-		if f.Op == gc.ONAME && f.Class == gc.PFUNC {
-			if f == gc.Deferreturn {
-				// Deferred calls will appear to be returning to
-				// the CALL deferreturn(SB) that we are about to emit.
-				// However, the stack trace code will show the line
-				// of the instruction byte before the return PC.
-				// To avoid that being an unrelated instruction,
-				// insert a arm64 NOP that we will have the right line number.
-				// The arm64 NOP is really or HINT $0; use that description
-				// because the NOP pseudo-instruction would be removed by
-				// the linker.
-				var con gc.Node
-				gc.Nodconst(&con, gc.Types[gc.TINT], 0)
-				gins(arm64.AHINT, &con, nil)
-			}
-
-			p := gins(arm64.ABL, nil, f)
-			gc.Afunclit(&p.To, f)
-			if proc == -1 || gc.Noreturn(p) {
-				gins(obj.AUNDEF, nil, nil)
-			}
-			break
-		}
-
-		var reg gc.Node
-		gc.Nodreg(&reg, gc.Types[gc.Tptr], arm64.REGCTXT)
-		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[gc.Tptr], arm64.REGRT1)
-		gmove(f, &reg)
-		reg.Op = gc.OINDREG
-		gmove(&reg, &r1)
-		r1.Op = gc.OINDREG
-		gins(arm64.ABL, nil, &r1)
-
-	case 3: // normal call of c function pointer
-		gins(arm64.ABL, nil, f)
-
-	case 1, // call in new proc (go)
-		2: // deferred call (defer)
-		var con gc.Node
-		gc.Nodconst(&con, gc.Types[gc.TINT64], int64(gc.Argsize(f.Type)))
-
-		var reg gc.Node
-		gc.Nodreg(&reg, gc.Types[gc.TINT64], arm64.REGRT1)
-		var reg2 gc.Node
-		gc.Nodreg(&reg2, gc.Types[gc.TINT64], arm64.REGRT2)
-		gmove(f, &reg)
-
-		gmove(&con, &reg2)
-		p := gins(arm64.AMOVW, &reg2, nil)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = arm64.REGSP
-		p.To.Offset = 8
-
-		p = gins(arm64.AMOVD, &reg, nil)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = arm64.REGSP
-		p.To.Offset = 16
-
-		if proc == 1 {
-			ginscall(gc.Newproc, 0)
-		} else {
-			if gc.Hasdefer == 0 {
-				gc.Fatal("hasdefer=0 but has defer")
-			}
-			ginscall(gc.Deferproc, 0)
-		}
-
-		if proc == 2 {
-			gc.Nodreg(&reg, gc.Types[gc.TINT64], arm64.REG_R0) // R0 should match runtime.return0
-			p := gins(arm64.ACMP, &reg, nil)
-			p.Reg = arm64.REGZERO
-			p = gc.Gbranch(arm64.ABEQ, nil, +1)
-			cgen_ret(nil)
-			gc.Patch(p, gc.Pc)
-		}
-	}
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-func cgen_callinter(n *gc.Node, res *gc.Node, proc int) {
-	i := n.Left
-	if i.Op != gc.ODOTINTER {
-		gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0))
-	}
-
-	f := i.Right // field
-	if f.Op != gc.ONAME {
-		gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0))
-	}
-
-	i = i.Left // interface
-
-	if i.Addable == 0 {
-		var tmpi gc.Node
-		gc.Tempname(&tmpi, i.Type)
-		cgen(i, &tmpi)
-		i = &tmpi
-	}
-
-	gc.Genlist(n.List) // assign the args
-
-	// i is now addable, prepare an indirected
-	// register to hold its address.
-	var nodi gc.Node
-	igen(i, &nodi, res) // REG = &inter
-
-	var nodsp gc.Node
-	gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], arm64.REGSP)
-
-	nodsp.Xoffset = int64(gc.Widthptr)
-	if proc != 0 {
-		nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn
-	}
-	nodi.Type = gc.Types[gc.Tptr]
-	nodi.Xoffset += int64(gc.Widthptr)
-	cgen(&nodi, &nodsp) // {8 or 24}(SP) = 8(REG) -- i.data
-
-	var nodo gc.Node
-	regalloc(&nodo, gc.Types[gc.Tptr], res)
-
-	nodi.Type = gc.Types[gc.Tptr]
-	nodi.Xoffset -= int64(gc.Widthptr)
-	cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
-	regfree(&nodi)
-
-	var nodr gc.Node
-	regalloc(&nodr, gc.Types[gc.Tptr], &nodo)
-	if n.Left.Xoffset == gc.BADWIDTH {
-		gc.Fatal("cgen_callinter: badwidth")
-	}
-	gc.Cgen_checknil(&nodo) // in case offset is huge
-	nodo.Op = gc.OINDREG
-	nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8
-	if proc == 0 {
-		// plain call: use direct c function pointer - more efficient
-		cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
-		proc = 3
-	} else {
-		// go/defer. generate go func value.
-		p := gins(arm64.AMOVD, &nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
-		p.From.Type = obj.TYPE_ADDR
-	}
-
-	nodr.Type = n.Left.Type
-	ginscall(&nodr, proc)
-
-	regfree(&nodr)
-	regfree(&nodo)
-}
-
-/*
- * generate function call;
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
- */
-func cgen_call(n *gc.Node, proc int) {
-	if n == nil {
-		return
-	}
-
-	var afun gc.Node
-	if n.Left.Ullman >= gc.UINF {
-		// if name involves a fn call
-		// precompute the address of the fn
-		gc.Tempname(&afun, gc.Types[gc.Tptr])
-
-		cgen(n.Left, &afun)
-	}
-
-	gc.Genlist(n.List) // assign the args
-	t := n.Left.Type
-
-	// call tempname pointer
-	if n.Left.Ullman >= gc.UINF {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, &afun)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call pointer
-	if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, n.Left)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call direct
-	n.Left.Method = 1
-
-	ginscall(n.Left, proc)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = return value from call.
- */
-func cgen_callret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_callret: nil")
-	}
-
-	var nod gc.Node
-	nod.Op = gc.OINDREG
-	nod.Val.U.Reg = arm64.REGSP
-	nod.Addable = 1
-
-	nod.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved LR at 0(R1)
-	nod.Type = fp.Type
-	gc.Cgen_as(res, &nod)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = &return value from call.
- */
-func cgen_aret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if gc.Isptr[t.Etype] {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	var nod1 gc.Node
-	nod1.Op = gc.OINDREG
-	nod1.Val.U.Reg = arm64.REGSP
-	nod1.Addable = 1
-
-	nod1.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP)
-	nod1.Type = fp.Type
-
-	if res.Op != gc.OREGISTER {
-		var nod2 gc.Node
-		regalloc(&nod2, gc.Types[gc.Tptr], res)
-		agen(&nod1, &nod2)
-		gins(arm64.AMOVD, &nod2, res)
-		regfree(&nod2)
-	} else {
-		agen(&nod1, res)
-	}
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-func cgen_ret(n *gc.Node) {
-	if n != nil {
-		gc.Genlist(n.List) // copy out args
-	}
-	if gc.Hasdefer != 0 {
-		ginscall(gc.Deferreturn, 0)
-	}
-	gc.Genlist(gc.Curfn.Exit)
-	p := gins(obj.ARET, nil, nil)
-	if n != nil && n.Op == gc.ORETJMP {
-		p.To.Name = obj.NAME_EXTERN
-		p.To.Type = obj.TYPE_ADDR
-		p.To.Sym = gc.Linksym(n.Left.Sym)
-	}
+func ginsnop() {
+	var con gc.Node
+	gc.Nodconst(&con, gc.Types[gc.TINT], 0)
+	gins(arm64.AHINT, &con, nil)
 }
 
 /*
@@ -468,15 +162,15 @@
 	a := optoas(gc.ODIV, t)
 
 	var tl gc.Node
-	regalloc(&tl, t0, nil)
+	gc.Regalloc(&tl, t0, nil)
 	var tr gc.Node
-	regalloc(&tr, t0, nil)
+	gc.Regalloc(&tr, t0, nil)
 	if nl.Ullman >= nr.Ullman {
-		cgen(nl, &tl)
-		cgen(nr, &tr)
+		gc.Cgen(nl, &tl)
+		gc.Cgen(nr, &tr)
 	} else {
-		cgen(nr, &tr)
-		cgen(nl, &tl)
+		gc.Cgen(nr, &tr)
+		gc.Cgen(nl, &tl)
 	}
 
 	if t != t0 {
@@ -497,7 +191,7 @@
 	if panicdiv == nil {
 		panicdiv = gc.Sysfunc("panicdivide")
 	}
-	ginscall(panicdiv, -1)
+	gc.Ginscall(panicdiv, -1)
 	gc.Patch(p1, gc.Pc)
 
 	var p2 *obj.Prog
@@ -525,12 +219,12 @@
 
 	p1 = gins(a, &tr, &tl)
 	if op == gc.ODIV {
-		regfree(&tr)
+		gc.Regfree(&tr)
 		gmove(&tl, res)
 	} else {
 		// A%B = A-(A/B*B)
 		var tm gc.Node
-		regalloc(&tm, t, nil)
+		gc.Regalloc(&tm, t, nil)
 
 		// patch div to use the 3 register form
 		// TODO(minux): add gins3?
@@ -538,33 +232,19 @@
 
 		p1.To.Reg = tm.Val.U.Reg
 		gins(optoas(gc.OMUL, t), &tr, &tm)
-		regfree(&tr)
+		gc.Regfree(&tr)
 		gins(optoas(gc.OSUB, t), &tm, &tl)
-		regfree(&tm)
+		gc.Regfree(&tm)
 		gmove(&tl, res)
 	}
 
-	regfree(&tl)
+	gc.Regfree(&tl)
 	if check != 0 {
 		gc.Patch(p2, gc.Pc)
 	}
 }
 
 /*
- * generate division according to op, one of:
- *	res = nl / nr
- *	res = nl % nr
- */
-func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
-	// TODO(minux): enable division by magic multiply (also need to fix longmod below)
-	//if(nr->op != OLITERAL)
-	// division and mod using (slow) hardware instruction
-	dodiv(op, nl, nr, res)
-
-	return
-}
-
-/*
  * generate high multiply:
  *   res = (nl*nr) >> width
  */
@@ -579,9 +259,9 @@
 	t := (*gc.Type)(nl.Type)
 	w := int(int(t.Width * 8))
 	var n1 gc.Node
-	cgenr(nl, &n1, res)
+	gc.Cgenr(nl, &n1, res)
 	var n2 gc.Node
-	cgenr(nr, &n2, nil)
+	gc.Cgenr(nr, &n2, nil)
 	switch gc.Simtype[t.Etype] {
 	case gc.TINT8,
 		gc.TINT16,
@@ -611,9 +291,9 @@
 		gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
 	}
 
-	cgen(&n1, res)
-	regfree(&n1)
-	regfree(&n2)
+	gc.Cgen(&n1, res)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 /*
@@ -626,8 +306,8 @@
 
 	if nr.Op == gc.OLITERAL {
 		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-		cgen(nl, &n1)
+		gc.Regalloc(&n1, nl.Type, res)
+		gc.Cgen(nl, &n1)
 		sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval)))
 		if sc >= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
@@ -640,21 +320,21 @@
 			gins(a, nr, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
 	if nl.Ullman >= gc.UINF {
 		var n4 gc.Node
 		gc.Tempname(&n4, nl.Type)
-		cgen(nl, &n4)
+		gc.Cgen(nl, &n4)
 		nl = &n4
 	}
 
 	if nr.Ullman >= gc.UINF {
 		var n5 gc.Node
 		gc.Tempname(&n5, nr.Type)
-		cgen(nr, &n5)
+		gc.Cgen(nr, &n5)
 		nr = &n5
 	}
 
@@ -668,24 +348,24 @@
 	}
 
 	var n1 gc.Node
-	regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
+	gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
 	var n3 gc.Node
-	regalloc(&n3, tcount, &n1) // to clear high bits of CX
+	gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
 
 	var n2 gc.Node
-	regalloc(&n2, nl.Type, res)
+	gc.Regalloc(&n2, nl.Type, res)
 
 	if nl.Ullman >= nr.Ullman {
-		cgen(nl, &n2)
-		cgen(nr, &n1)
+		gc.Cgen(nl, &n2)
+		gc.Cgen(nr, &n1)
 		gmove(&n1, &n3)
 	} else {
-		cgen(nr, &n1)
+		gc.Cgen(nr, &n1)
 		gmove(&n1, &n3)
-		cgen(nl, &n2)
+		gc.Cgen(nl, &n2)
 	}
 
-	regfree(&n3)
+	gc.Regfree(&n3)
 
 	// test and fix up large shifts
 	if !bounded {
@@ -707,8 +387,8 @@
 
 	gmove(&n2, res)
 
-	regfree(&n1)
-	regfree(&n2)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 func clearfat(nl *gc.Node) {
@@ -736,7 +416,7 @@
 	var dst gc.Node
 	gc.Nodreg(&dst, gc.Types[gc.Tptr], arm64.REGRT1)
 	reg[arm64.REGRT1-arm64.REG_R0]++
-	agen(nl, &dst)
+	gc.Agen(nl, &dst)
 
 	var boff uint64
 	if q > 128 {
@@ -745,7 +425,7 @@
 		p.From.Offset = 8
 
 		var end gc.Node
-		regalloc(&end, gc.Types[gc.Tptr], nil)
+		gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
 		p = gins(arm64.AMOVD, &dst, &end)
 		p.From.Type = obj.TYPE_ADDR
 		p.From.Offset = int64(q * 8)
@@ -759,7 +439,7 @@
 		p = gcmp(arm64.ACMP, &dst, &end)
 		gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), pl)
 
-		regfree(&end)
+		gc.Regfree(&end)
 
 		// The loop leaves R16 on the last zeroed dword
 		boff = 8
diff --git a/src/cmd/7g/gsubr.go b/src/cmd/7g/gsubr.go
index edde1fd..0828daf 100644
--- a/src/cmd/7g/gsubr.go
+++ b/src/cmd/7g/gsubr.go
@@ -52,171 +52,6 @@
 	arm64.FREGTWO,
 }
 
-func ginit() {
-	for i := 0; i < len(reg); i++ {
-		reg[i] = 1
-	}
-	for i := 0; i < arm64.NREG+arm64.NFREG; i++ {
-		reg[i] = 0
-	}
-
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]-arm64.REG_R0]++
-	}
-}
-
-var regpc [len(reg)]uint32
-
-func gclean() {
-	for i := int(0); i < len(resvd); i++ {
-		reg[resvd[i]-arm64.REG_R0]--
-	}
-
-	for i := int(0); i < len(reg); i++ {
-		if reg[i] != 0 {
-			gc.Yyerror("reg %v left allocated, %p\n", obj.Rconv(i+arm64.REG_R0), regpc[i])
-		}
-	}
-}
-
-func anyregalloc() bool {
-	var j int
-
-	for i := int(0); i < len(reg); i++ {
-		if reg[i] == 0 {
-			goto ok
-		}
-		for j = 0; j < len(resvd); j++ {
-			if resvd[j] == i {
-				goto ok
-			}
-		}
-		return true
-	ok:
-	}
-
-	return false
-}
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) {
-	if t == nil {
-		gc.Fatal("regalloc: t nil")
-	}
-	et := int(int(gc.Simtype[t.Etype]))
-
-	if gc.Debug['r'] != 0 {
-		fixfree := int(0)
-		fltfree := int(0)
-		for i := int(arm64.REG_R0); i < arm64.REG_F31; i++ {
-			if reg[i-arm64.REG_R0] == 0 {
-				if i < arm64.REG_F0 {
-					fixfree++
-				} else {
-					fltfree++
-				}
-			}
-		}
-
-		fmt.Printf("regalloc fix %d flt %d free\n", fixfree, fltfree)
-	}
-
-	var i int
-	switch et {
-	case gc.TINT8,
-		gc.TUINT8,
-		gc.TINT16,
-		gc.TUINT16,
-		gc.TINT32,
-		gc.TUINT32,
-		gc.TINT64,
-		gc.TUINT64,
-		gc.TPTR32,
-		gc.TPTR64,
-		gc.TBOOL:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= arm64.REGMIN && i <= arm64.REGMAX {
-				goto out
-			}
-		}
-
-		for i = arm64.REGMIN; i <= arm64.REGMAX; i++ {
-			if reg[i-arm64.REG_R0] == 0 {
-				regpc[i-arm64.REG_R0] = uint32(obj.Getcallerpc(&n))
-				goto out
-			}
-		}
-
-		gc.Flusherrors()
-		for i := int(arm64.REG_R0); i < arm64.REG_R0+arm64.NREG; i++ {
-			fmt.Printf("R%d %p\n", i, regpc[i-arm64.REG_R0])
-		}
-		gc.Fatal("out of fixed registers")
-
-	case gc.TFLOAT32,
-		gc.TFLOAT64:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= arm64.FREGMIN && i <= arm64.FREGMAX {
-				goto out
-			}
-		}
-
-		for i = arm64.FREGMIN; i <= arm64.FREGMAX; i++ {
-			if reg[i-arm64.REG_R0] == 0 {
-				regpc[i-arm64.REG_R0] = uint32(obj.Getcallerpc(&n))
-				goto out
-			}
-		}
-
-		gc.Flusherrors()
-		for i := int(arm64.REG_F0); i < arm64.REG_F0+arm64.NREG; i++ {
-			fmt.Printf("F%d %p\n", i, regpc[i-arm64.REG_R0])
-		}
-		gc.Fatal("out of floating registers")
-
-	case gc.TCOMPLEX64,
-		gc.TCOMPLEX128:
-		gc.Tempname(n, t)
-		return
-	}
-
-	gc.Fatal("regalloc: unknown type %v", gc.Tconv(t, 0))
-	return
-
-out:
-	reg[i-arm64.REG_R0]++
-	gc.Nodreg(n, t, i)
-}
-
-func regfree(n *gc.Node) {
-	if n.Op == gc.ONAME {
-		return
-	}
-	if n.Op != gc.OREGISTER && n.Op != gc.OINDREG {
-		gc.Fatal("regfree: not a register")
-	}
-	i := int(int(n.Val.U.Reg) - arm64.REG_R0)
-	if i == arm64.REGSP-arm64.REG_R0 {
-		return
-	}
-	if i < 0 || i >= len(reg) {
-		gc.Fatal("regfree: reg out of range")
-	}
-	if reg[i] <= 0 {
-		gc.Fatal("regfree: reg not allocated")
-	}
-	reg[i]--
-	if reg[i] == 0 {
-		regpc[i] = 0
-	}
-}
-
 /*
  * generate
  *	as $c, n
@@ -226,19 +61,19 @@
 
 	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
 
-	if as != arm64.AMOVD && (c < -arm64.BIG || c > arm64.BIG) {
+	if as != arm64.AMOVD && (c < -arm64.BIG || c > arm64.BIG) || as == arm64.AMUL || n2 != nil && n2.Op != gc.OREGISTER {
 		// cannot have more than 16-bit of immediate in ADD, etc.
 		// instead, MOV into register first.
 		var ntmp gc.Node
-		regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+		gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
 
 		gins(arm64.AMOVD, &n1, &ntmp)
 		gins(as, &ntmp, n2)
-		regfree(&ntmp)
+		gc.Regfree(&ntmp)
 		return
 	}
 
-	gins(as, &n1, n2)
+	rawgins(as, &n1, n2)
 }
 
 /*
@@ -263,11 +98,11 @@
 
 	// MOV n1 into register first
 	var ntmp gc.Node
-	regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+	gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
 
-	gins(arm64.AMOVD, &n1, &ntmp)
+	rawgins(arm64.AMOVD, &n1, &ntmp)
 	gcmp(as, n2, &ntmp)
-	regfree(&ntmp)
+	gc.Regfree(&ntmp)
 }
 
 /*
@@ -309,10 +144,10 @@
 			var con gc.Node
 			gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val)
 			var r1 gc.Node
-			regalloc(&r1, con.Type, t)
+			gc.Regalloc(&r1, con.Type, t)
 			gins(arm64.AMOVD, &con, &r1)
 			gmove(&r1, t)
-			regfree(&r1)
+			gc.Regfree(&r1)
 			return
 
 		case gc.TUINT32,
@@ -321,10 +156,10 @@
 			var con gc.Node
 			gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val)
 			var r1 gc.Node
-			regalloc(&r1, con.Type, t)
+			gc.Regalloc(&r1, con.Type, t)
 			gins(arm64.AMOVD, &con, &r1)
 			gmove(&r1, t)
-			regfree(&r1)
+			gc.Regfree(&r1)
 			return
 		}
 
@@ -590,28 +425,60 @@
 
 	// requires register destination
 rdst:
-	regalloc(&r1, t.Type, t)
+	gc.Regalloc(&r1, t.Type, t)
 
 	gins(a, f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 
 	// requires register intermediate
 hard:
-	regalloc(&r1, cvt, t)
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 }
 
+func intLiteral(n *gc.Node) (x int64, ok bool) {
+	if n == nil || n.Op != gc.OLITERAL {
+		return
+	}
+	switch n.Val.Ctype {
+	case gc.CTINT, gc.CTRUNE:
+		return gc.Mpgetfix(n.Val.U.Xval), true
+	case gc.CTBOOL:
+		return int64(n.Val.U.Bval), true
+	}
+	return
+}
+
+// gins is called by the front end.
+// It synthesizes some multiple-instruction sequences
+// so the front end can stay simpler.
+func gins(as int, f, t *gc.Node) *obj.Prog {
+	if as >= obj.A_ARCHSPECIFIC {
+		if x, ok := intLiteral(f); ok {
+			ginscon(as, x, t)
+			return nil // caller must not use
+		}
+	}
+	if as == arm64.ACMP {
+		if x, ok := intLiteral(t); ok {
+			ginscon2(as, f, x)
+			return nil // caller must not use
+		}
+	}
+	return rawgins(as, f, t)
+}
+
 /*
  * generate one instruction:
  *	as f, t
  */
-func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 	// TODO(austin): Add self-move test like in 6g (but be careful
 	// of truncation moves)
 
@@ -619,6 +486,32 @@
 	gc.Naddr(&p.From, f)
 	gc.Naddr(&p.To, t)
 
+	switch as {
+	case arm64.ACMP, arm64.AFCMPS, arm64.AFCMPD:
+		if t != nil {
+			if f.Op != gc.OREGISTER {
+				gc.Fatal("bad operands to gcmp")
+			}
+			p.From = p.To
+			p.To = obj.Addr{}
+			raddr(f, p)
+		}
+	}
+
+	// Bad things the front end has done to us. Crash to find call stack.
+	switch as {
+	case arm64.AAND, arm64.AMUL:
+		if p.From.Type == obj.TYPE_CONST {
+			gc.Debug['h'] = 1
+			gc.Fatal("bad inst: %v", p)
+		}
+	case arm64.ACMP:
+		if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
+			gc.Debug['h'] = 1
+			gc.Fatal("bad inst: %v", p)
+		}
+	}
+
 	if gc.Debug['g'] != 0 {
 		fmt.Printf("%v\n", p)
 	}
@@ -696,7 +589,7 @@
 		gc.Fatal("bad operands to gcmp: %v %v", gc.Oconv(int(lhs.Op), 0), gc.Oconv(int(rhs.Op), 0))
 	}
 
-	p := gins(as, rhs, nil)
+	p := rawgins(as, rhs, nil)
 	raddr(lhs, p)
 	return p
 }
diff --git a/src/cmd/8g/cgen.go b/src/cmd/8g/cgen.go
index 2a10e49..5546aba3 100644
--- a/src/cmd/8g/cgen.go
+++ b/src/cmd/8g/cgen.go
@@ -8,507 +8,21 @@
 	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
-	"fmt"
 )
 
 /*
- * reg.c
- */
-
-/*
- * peep.c
- */
-func mgen(n *gc.Node, n1 *gc.Node, rg *gc.Node) {
-	n1.Op = gc.OEMPTY
-
-	if n.Addable != 0 {
-		*n1 = *n
-		if n1.Op == gc.OREGISTER || n1.Op == gc.OINDREG {
-			reg[n.Val.U.Reg]++
-		}
-		return
-	}
-
-	gc.Tempname(n1, n.Type)
-	cgen(n, n1)
-	if n.Type.Width <= int64(gc.Widthptr) || gc.Isfloat[n.Type.Etype] {
-		n2 := *n1
-		regalloc(n1, n.Type, rg)
-		gmove(&n2, n1)
-	}
-}
-
-func mfree(n *gc.Node) {
-	if n.Op == gc.OREGISTER {
-		regfree(n)
-	}
-}
-
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- *
- * TODO:
- *	sudoaddable
- */
-func cgen(n *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\ncgen-n", n)
-		gc.Dump("cgen-res", res)
-	}
-
-	if n == nil || n.Type == nil {
-		gc.Fatal("cgen: n nil")
-	}
-	if res == nil || res.Type == nil {
-		gc.Fatal("cgen: res nil")
-	}
-
-	switch n.Op {
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_slice(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_slice(n, res)
-		}
-		return
-
-	case gc.OEFACE:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_eface(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_eface(n, res)
-		}
-		return
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	// function calls on both sides?  introduce temporary
-	if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF {
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		cgen(n, &n1)
-		cgen(&n1, res)
-		return
-	}
-
-	// structs etc get handled specially
-	if gc.Isfat(n.Type) {
-		if n.Type.Width < 0 {
-			gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0))
-		}
-		sgen(n, res, n.Type.Width)
-		return
-	}
-
-	// update addressability for string, slice
-	// can't do in walk because n->left->addable
-	// changes if n->left is an escaping local variable.
-	switch n.Op {
-	case gc.OSPTR,
-		gc.OLEN:
-		if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OCAP:
-		if gc.Isslice(n.Left.Type) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OITAB:
-		n.Addable = n.Left.Addable
-	}
-
-	// if both are addressable, move
-	if n.Addable != 0 && res.Addable != 0 {
-		gmove(n, res)
-		return
-	}
-
-	// if both are not addressable, use a temporary.
-	if n.Addable == 0 && res.Addable == 0 {
-		// could use regalloc here sometimes,
-		// but have to check for ullman >= UINF.
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-
-		cgen(n, &n1)
-		cgen(&n1, res)
-		return
-	}
-
-	// if result is not addressable directly but n is,
-	// compute its address and then store via the address.
-	if res.Addable == 0 {
-		var n1 gc.Node
-		igen(res, &n1, nil)
-		cgen(n, &n1)
-		regfree(&n1)
-		return
-	}
-
-	// complex types
-	if gc.Complexop(n, res) {
-		gc.Complexgen(n, res)
-		return
-	}
-
-	// otherwise, the result is addressable but n is not.
-	// let's do some computation.
-
-	// use ullman to pick operand to eval first.
-	nl := n.Left
-
-	nr := n.Right
-	if nl != nil && nl.Ullman >= gc.UINF {
-		if nr != nil && nr.Ullman >= gc.UINF {
-			// both are hard
-			var n1 gc.Node
-			gc.Tempname(&n1, nl.Type)
-
-			cgen(nl, &n1)
-			n2 := *n
-			n2.Left = &n1
-			cgen(&n2, res)
-			return
-		}
-	}
-
-	// 64-bit ops are hard on 32-bit machine.
-	if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Left != nil && gc.Is64(n.Left.Type) {
-		switch n.Op {
-		// math goes to cgen64.
-		case gc.OMINUS,
-			gc.OCOM,
-			gc.OADD,
-			gc.OSUB,
-			gc.OMUL,
-			gc.OLROT,
-			gc.OLSH,
-			gc.ORSH,
-			gc.OAND,
-			gc.OOR,
-			gc.OXOR:
-			cgen64(n, res)
-
-			return
-		}
-	}
-
-	if nl != nil && gc.Isfloat[n.Type.Etype] && gc.Isfloat[nl.Type.Etype] {
-		cgen_float(n, res)
-		return
-	}
-
-	var a int
-	switch n.Op {
-	default:
-		gc.Dump("cgen", n)
-		gc.Fatal("cgen %v", gc.Oconv(int(n.Op), 0))
-
-	case gc.OREAL,
-		gc.OIMAG,
-		gc.OCOMPLEX:
-		gc.Fatal("unexpected complex")
-		return
-
-		// these call bgen to get a bool value
-	case gc.OOROR,
-		gc.OANDAND,
-		gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OLE,
-		gc.OGE,
-		gc.OGT,
-		gc.ONOT:
-		p1 := gc.Gbranch(obj.AJMP, nil, 0)
-
-		p2 := gc.Pc
-		gmove(gc.Nodbool(true), res)
-		p3 := gc.Gbranch(obj.AJMP, nil, 0)
-		gc.Patch(p1, gc.Pc)
-		bgen(n, true, 0, p2)
-		gmove(gc.Nodbool(false), res)
-		gc.Patch(p3, gc.Pc)
-		return
-
-	case gc.OPLUS:
-		cgen(nl, res)
-		return
-
-	case gc.OMINUS,
-		gc.OCOM:
-		a := optoas(int(n.Op), nl.Type)
-		// unary
-		var n1 gc.Node
-		gc.Tempname(&n1, nl.Type)
-
-		cgen(nl, &n1)
-		gins(a, nil, &n1)
-		gmove(&n1, res)
-		return
-
-		// symmetric binary
-	case gc.OAND,
-		gc.OOR,
-		gc.OXOR,
-		gc.OADD,
-		gc.OMUL:
-		a = optoas(int(n.Op), nl.Type)
-
-		if a == x86.AIMULB {
-			cgen_bmul(int(n.Op), nl, nr, res)
-			break
-		}
-
-		// symmetric binary
-		if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL {
-			r := nl
-			nl = nr
-			nr = r
-		}
-		goto abop
-
-		// asymmetric binary
-	case gc.OSUB:
-		a = optoas(int(n.Op), nl.Type)
-
-		goto abop
-
-	case gc.OHMUL:
-		cgen_hmul(nl, nr, res)
-
-	case gc.OCONV:
-		if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) {
-			cgen(nl, res)
-			break
-		}
-
-		var n2 gc.Node
-		gc.Tempname(&n2, n.Type)
-		var n1 gc.Node
-		mgen(nl, &n1, res)
-		gmove(&n1, &n2)
-		gmove(&n2, res)
-		mfree(&n1)
-
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OIND,
-		gc.ONAME: // PHEAP or PPARAMREF var
-		var n1 gc.Node
-		igen(n, &n1, res)
-
-		gmove(&n1, res)
-		regfree(&n1)
-
-	case gc.OITAB:
-		var n1 gc.Node
-		igen(nl, &n1, res)
-		n1.Type = gc.Ptrto(gc.Types[gc.TUINTPTR])
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// pointer is the first word of string or slice.
-	case gc.OSPTR:
-		if gc.Isconst(nl, gc.CTSTR) {
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-			p1 := gins(x86.ALEAL, nil, &n1)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		var n1 gc.Node
-		igen(nl, &n1, res)
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-	case gc.OLEN:
-		if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) {
-			// map has len in the first 32-bit word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			gc.Tempname(&n1, gc.Types[gc.Tptr])
-
-			cgen(nl, &n1)
-			var n2 gc.Node
-			regalloc(&n2, gc.Types[gc.Tptr], nil)
-			gmove(&n1, &n2)
-			n1 = n2
-
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Type = gc.Types[gc.TINT32]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) {
-			// both slice and string have len one pointer into the struct.
-			var n1 gc.Node
-			igen(nl, &n1, res)
-
-			n1.Type = gc.Types[gc.TUINT32]
-			n1.Xoffset += int64(gc.Array_nel)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OCAP:
-		if gc.Istype(nl.Type, gc.TCHAN) {
-			// chan has cap in the second 32-bit word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			gc.Tempname(&n1, gc.Types[gc.Tptr])
-
-			cgen(nl, &n1)
-			var n2 gc.Node
-			regalloc(&n2, gc.Types[gc.Tptr], nil)
-			gmove(&n1, &n2)
-			n1 = n2
-
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Xoffset = 4
-			n2.Type = gc.Types[gc.TINT32]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isslice(nl.Type) {
-			var n1 gc.Node
-			igen(nl, &n1, res)
-			n1.Type = gc.Types[gc.TUINT32]
-			n1.Xoffset += int64(gc.Array_cap)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OADDR:
-		agen(nl, res)
-
-	case gc.OCALLMETH:
-		gc.Cgen_callmeth(n, 0)
-		cgen_callret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_callret(n, res)
-
-	case gc.OCALLFUNC:
-		cgen_call(n, 0)
-		cgen_callret(n, res)
-
-	case gc.OMOD,
-		gc.ODIV:
-		cgen_div(int(n.Op), nl, nr, res)
-
-	case gc.OLSH,
-		gc.ORSH,
-		gc.OLROT:
-		cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
-	}
-
-	return
-
-abop: // asymmetric binary
-	if gc.Smallintconst(nr) {
-		var n1 gc.Node
-		mgen(nl, &n1, res)
-		var n2 gc.Node
-		regalloc(&n2, nl.Type, &n1)
-		gmove(&n1, &n2)
-		gins(a, nr, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		mfree(&n1)
-	} else if nl.Ullman >= nr.Ullman {
-		var nt gc.Node
-		gc.Tempname(&nt, nl.Type)
-		cgen(nl, &nt)
-		var n2 gc.Node
-		mgen(nr, &n2, nil)
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-		gmove(&nt, &n1)
-		gins(a, &n2, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		mfree(&n2)
-	} else {
-		var n2 gc.Node
-		regalloc(&n2, nr.Type, res)
-		cgen(nr, &n2)
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-		gins(a, &n2, &n1)
-		regfree(&n2)
-		gmove(&n1, res)
-		regfree(&n1)
-	}
-
-	return
-}
-
-/*
  * generate an addressable node in res, containing the value of n.
  * n is an array index, and might be any size; res width is <= 32-bit.
  * returns Prog* to patch to panic call.
  */
-func igenindex(n *gc.Node, res *gc.Node, bounded int) *obj.Prog {
+func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
 	if !gc.Is64(n.Type) {
 		if n.Addable != 0 {
 			// nothing to do.
 			*res = *n
 		} else {
 			gc.Tempname(res, gc.Types[gc.TUINT32])
-			cgen(n, res)
+			gc.Cgen(n, res)
 		}
 
 		return nil
@@ -516,13 +30,13 @@
 
 	var tmp gc.Node
 	gc.Tempname(&tmp, gc.Types[gc.TINT64])
-	cgen(n, &tmp)
+	gc.Cgen(n, &tmp)
 	var lo gc.Node
 	var hi gc.Node
 	split64(&tmp, &lo, &hi)
 	gc.Tempname(res, gc.Types[gc.TUINT32])
 	gmove(&lo, res)
-	if bounded != 0 {
+	if bounded {
 		splitclean()
 		return nil
 	}
@@ -534,826 +48,7 @@
 	return gc.Gbranch(x86.AJNE, nil, +1)
 }
 
-/*
- * address gen
- *	res = &n;
- * The generated code checks that the result is not nil.
- */
-func agen(n *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nagen-res", res)
-		gc.Dump("agen-r", n)
-	}
-
-	if n == nil || n.Type == nil || res == nil || res.Type == nil {
-		gc.Fatal("agen")
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) {
-		// Use of a nil interface or nil slice.
-		// Create a temporary we can take the address of and read.
-		// The generated code is just going to panic, so it need not
-		// be terribly efficient. See issue 3670.
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-
-		gc.Gvardef(&n1)
-		clearfat(&n1)
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.Tptr], res)
-		gins(x86.ALEAL, &n1, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		return
-	}
-
-	// addressable var is easy
-	if n.Addable != 0 {
-		if n.Op == gc.OREGISTER {
-			gc.Fatal("agen OREGISTER")
-		}
-		var n1 gc.Node
-		regalloc(&n1, gc.Types[gc.Tptr], res)
-		gins(x86.ALEAL, n, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		return
-	}
-
-	// let's compute
-	nl := n.Left
-
-	nr := n.Right
-
-	switch n.Op {
-	default:
-		gc.Fatal("agen %v", gc.Oconv(int(n.Op), 0))
-
-	case gc.OCALLMETH:
-		gc.Cgen_callmeth(n, 0)
-		cgen_aret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_aret(n, res)
-
-	case gc.OCALLFUNC:
-		cgen_call(n, 0)
-		cgen_aret(n, res)
-
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_slice(n, &n1)
-		agen(&n1, res)
-
-	case gc.OEFACE:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_eface(n, &n1)
-		agen(&n1, res)
-
-	case gc.OINDEX:
-		var p2 *obj.Prog // to be patched to panicindex.
-		w := uint32(n.Type.Width)
-		bounded := gc.Debug['B'] != 0 || n.Bounded
-		var n3 gc.Node
-		var tmp gc.Node
-		var n1 gc.Node
-		if nr.Addable != 0 {
-			// Generate &nl first, and move nr into register.
-			if !gc.Isconst(nl, gc.CTSTR) {
-				igen(nl, &n3, res)
-			}
-			if !gc.Isconst(nr, gc.CTINT) {
-				p2 = igenindex(nr, &tmp, bool2int(bounded))
-				regalloc(&n1, tmp.Type, nil)
-				gmove(&tmp, &n1)
-			}
-		} else if nl.Addable != 0 {
-			// Generate nr first, and move &nl into register.
-			if !gc.Isconst(nr, gc.CTINT) {
-				p2 = igenindex(nr, &tmp, bool2int(bounded))
-				regalloc(&n1, tmp.Type, nil)
-				gmove(&tmp, &n1)
-			}
-
-			if !gc.Isconst(nl, gc.CTSTR) {
-				igen(nl, &n3, res)
-			}
-		} else {
-			p2 = igenindex(nr, &tmp, bool2int(bounded))
-			nr = &tmp
-			if !gc.Isconst(nl, gc.CTSTR) {
-				igen(nl, &n3, res)
-			}
-			regalloc(&n1, tmp.Type, nil)
-			gins(optoas(gc.OAS, tmp.Type), &tmp, &n1)
-		}
-
-		// For fixed array we really want the pointer in n3.
-		var n2 gc.Node
-		if gc.Isfixedarray(nl.Type) {
-			regalloc(&n2, gc.Types[gc.Tptr], &n3)
-			agen(&n3, &n2)
-			regfree(&n3)
-			n3 = n2
-		}
-
-		// &a[0] is in n3 (allocated in res)
-		// i is in n1 (if not constant)
-		// len(a) is in nlen (if needed)
-		// w is width
-
-		// constant index
-		if gc.Isconst(nr, gc.CTINT) {
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Fatal("constant string constant index") // front end should handle
-			}
-			v := uint64(gc.Mpgetfix(nr.Val.U.Xval))
-			if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				if gc.Debug['B'] == 0 && !n.Bounded {
-					nlen := n3
-					nlen.Type = gc.Types[gc.TUINT32]
-					nlen.Xoffset += int64(gc.Array_nel)
-					gc.Nodconst(&n2, gc.Types[gc.TUINT32], int64(v))
-					gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &nlen, &n2)
-					p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1)
-					ginscall(gc.Panicindex, -1)
-					gc.Patch(p1, gc.Pc)
-				}
-			}
-
-			// Load base pointer in n2 = n3.
-			regalloc(&n2, gc.Types[gc.Tptr], &n3)
-
-			n3.Type = gc.Types[gc.Tptr]
-			n3.Xoffset += int64(gc.Array_array)
-			gmove(&n3, &n2)
-			regfree(&n3)
-			if v*uint64(w) != 0 {
-				gc.Nodconst(&n1, gc.Types[gc.Tptr], int64(v*uint64(w)))
-				gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, &n2)
-			}
-
-			gmove(&n2, res)
-			regfree(&n2)
-			break
-		}
-
-		// i is in register n1, extend to 32 bits.
-		t := gc.Types[gc.TUINT32]
-
-		if gc.Issigned[n1.Type.Etype] {
-			t = gc.Types[gc.TINT32]
-		}
-
-		regalloc(&n2, t, &n1) // i
-		gmove(&n1, &n2)
-		regfree(&n1)
-
-		if gc.Debug['B'] == 0 && !n.Bounded {
-			// check bounds
-			t := gc.Types[gc.TUINT32]
-
-			var nlen gc.Node
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
-			} else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				nlen = n3
-				nlen.Type = t
-				nlen.Xoffset += int64(gc.Array_nel)
-			} else {
-				gc.Nodconst(&nlen, t, nl.Type.Bound)
-			}
-
-			gins(optoas(gc.OCMP, t), &n2, &nlen)
-			p1 := gc.Gbranch(optoas(gc.OLT, t), nil, +1)
-			if p2 != nil {
-				gc.Patch(p2, gc.Pc)
-			}
-			ginscall(gc.Panicindex, -1)
-			gc.Patch(p1, gc.Pc)
-		}
-
-		if gc.Isconst(nl, gc.CTSTR) {
-			regalloc(&n3, gc.Types[gc.Tptr], res)
-			p1 := gins(x86.ALEAL, nil, &n3)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			p1.From.Scale = 1
-			p1.From.Index = n2.Val.U.Reg
-			goto indexdone
-		}
-
-		// Load base pointer in n3.
-		regalloc(&tmp, gc.Types[gc.Tptr], &n3)
-
-		if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-			n3.Type = gc.Types[gc.Tptr]
-			n3.Xoffset += int64(gc.Array_array)
-			gmove(&n3, &tmp)
-		}
-
-		regfree(&n3)
-		n3 = tmp
-
-		if w == 0 {
-		} else // nothing to do
-		if w == 1 || w == 2 || w == 4 || w == 8 {
-			// LEAL (n3)(n2*w), n3
-			p1 := gins(x86.ALEAL, &n2, &n3)
-
-			p1.From.Scale = int16(w)
-			p1.From.Type = obj.TYPE_MEM
-			p1.From.Index = p1.From.Reg
-			p1.From.Reg = p1.To.Reg
-		} else {
-			gc.Nodconst(&tmp, gc.Types[gc.TUINT32], int64(w))
-			gins(optoas(gc.OMUL, gc.Types[gc.TUINT32]), &tmp, &n2)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-		}
-
-	indexdone:
-		gmove(&n3, res)
-		regfree(&n2)
-		regfree(&n3)
-
-		// should only get here with names in this func.
-	case gc.ONAME:
-		if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth)
-		}
-
-		// should only get here for heap vars or paramref
-		if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME class %#x", n.Class)
-		}
-
-		cgen(n.Heapaddr, res)
-		if n.Xoffset != 0 {
-			var n1 gc.Node
-			gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res)
-		}
-
-	case gc.OIND:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-
-	case gc.ODOT:
-		agen(nl, res)
-		if n.Xoffset != 0 {
-			var n1 gc.Node
-			gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res)
-		}
-
-	case gc.ODOTPTR:
-		t := nl.Type
-		if !gc.Isptr[t.Etype] {
-			gc.Fatal("agen: not ptr %v", gc.Nconv(n, 0))
-		}
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-		if n.Xoffset != 0 {
-			var n1 gc.Node
-			gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res)
-		}
-	}
-}
-
-/*
- * generate:
- *	newreg = &n;
- *	res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- * The generated code checks that the result is not *nil.
- */
-func igen(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nigen-n", n)
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF {
-			break
-		}
-		*a = *n
-		return
-
-		// Increase the refcount of the register so that igen's caller
-	// has to call regfree.
-	case gc.OINDREG:
-		if n.Val.U.Reg != x86.REG_SP {
-			reg[n.Val.U.Reg]++
-		}
-		*a = *n
-		return
-
-	case gc.ODOT:
-		igen(n.Left, a, res)
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		return
-
-	case gc.ODOTPTR:
-		switch n.Left.Op {
-		// igen-able nodes.
-		case gc.ODOT,
-			gc.ODOTPTR,
-			gc.OCALLFUNC,
-			gc.OCALLMETH,
-			gc.OCALLINTER:
-			var n1 gc.Node
-			igen(n.Left, &n1, res)
-
-			regalloc(a, gc.Types[gc.Tptr], &n1)
-			gmove(&n1, a)
-			regfree(&n1)
-
-		default:
-			regalloc(a, gc.Types[gc.Tptr], res)
-			cgen(n.Left, a)
-		}
-
-		gc.Cgen_checknil(a)
-		a.Op = gc.OINDREG
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		return
-
-	case gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		switch n.Op {
-		case gc.OCALLFUNC:
-			cgen_call(n, 0)
-
-		case gc.OCALLMETH:
-			gc.Cgen_callmeth(n, 0)
-
-		case gc.OCALLINTER:
-			cgen_callinter(n, nil, 0)
-		}
-
-		var flist gc.Iter
-		fp := gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type))
-		*a = gc.Node{}
-		a.Op = gc.OINDREG
-		a.Val.U.Reg = x86.REG_SP
-		a.Addable = 1
-		a.Xoffset = fp.Width
-		a.Type = n.Type
-		return
-
-		// Index of fixed-size array by constant can
-	// put the offset in the addressing.
-	// Could do the same for slice except that we need
-	// to use the real index for the bounds checking.
-	case gc.OINDEX:
-		if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] && gc.Isfixedarray(n.Left.Left.Type)) {
-			if gc.Isconst(n.Right, gc.CTINT) {
-				// Compute &a.
-				if !gc.Isptr[n.Left.Type.Etype] {
-					igen(n.Left, a, res)
-				} else {
-					var n1 gc.Node
-					igen(n.Left, &n1, res)
-					gc.Cgen_checknil(&n1)
-					regalloc(a, gc.Types[gc.Tptr], res)
-					gmove(&n1, a)
-					regfree(&n1)
-					a.Op = gc.OINDREG
-				}
-
-				// Compute &a[i] as &a + i*width.
-				a.Type = n.Type
-
-				a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
-				return
-			}
-		}
-	}
-
-	// release register for now, to avoid
-	// confusing tempname.
-	if res != nil && res.Op == gc.OREGISTER {
-		reg[res.Val.U.Reg]--
-	}
-	var n1 gc.Node
-	gc.Tempname(&n1, gc.Types[gc.Tptr])
-	agen(n, &n1)
-	if res != nil && res.Op == gc.OREGISTER {
-		reg[res.Val.U.Reg]++
-	}
-	regalloc(a, gc.Types[gc.Tptr], res)
-	gmove(&n1, a)
-	a.Op = gc.OINDREG
-	a.Type = n.Type
-}
-
-/*
- * branch gen
- *	if(n == true) goto to;
- */
-func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nbgen", n)
-	}
-
-	if n == nil {
-		n = gc.Nodbool(true)
-	}
-
-	if n.Ninit != nil {
-		gc.Genlist(n.Ninit)
-	}
-
-	if n.Type == nil {
-		gc.Convlit(&n, gc.Types[gc.TBOOL])
-		if n.Type == nil {
-			return
-		}
-	}
-
-	et := int(n.Type.Etype)
-	if et != gc.TBOOL {
-		gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0))
-		gc.Patch(gins(obj.AEND, nil, nil), to)
-		return
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-		if n.Ninit != nil {
-			gc.Genlist(n.Ninit)
-		}
-	}
-
-	nl := n.Left
-	var nr *gc.Node
-
-	if nl != nil && gc.Isfloat[nl.Type.Etype] {
-		bgen_float(n, bool2int(true_), likely, to)
-		return
-	}
-
-	switch n.Op {
-	default:
-		goto def
-
-		// need to ask if it is bool?
-	case gc.OLITERAL:
-		if !true_ == (n.Val.U.Bval == 0) {
-			gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
-		}
-		return
-
-	case gc.ONAME:
-		if n.Addable == 0 {
-			goto def
-		}
-		var n1 gc.Node
-		gc.Nodconst(&n1, n.Type, 0)
-		gins(optoas(gc.OCMP, n.Type), n, &n1)
-		a := x86.AJNE
-		if !true_ {
-			a = x86.AJEQ
-		}
-		gc.Patch(gc.Gbranch(a, n.Type, likely), to)
-		return
-
-	case gc.OANDAND,
-		gc.OOROR:
-		if (n.Op == gc.OANDAND) == true_ {
-			p1 := gc.Gbranch(obj.AJMP, nil, 0)
-			p2 := gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, gc.Pc)
-			bgen(n.Left, !true_, -likely, p2)
-			bgen(n.Right, !true_, -likely, p2)
-			p1 = gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, to)
-			gc.Patch(p2, gc.Pc)
-		} else {
-			bgen(n.Left, true_, likely, to)
-			bgen(n.Right, true_, likely, to)
-		}
-
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			return
-		}
-		fallthrough
-
-	case gc.ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
-			return
-		}
-	}
-
-	switch n.Op {
-	case gc.ONOT:
-		bgen(nl, !true_, likely, to)
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		a := int(n.Op)
-		if !true_ {
-			a = gc.Brcom(a)
-			true_ = !true_
-		}
-
-		// make simplest on right
-		if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) {
-			a = gc.Brrev(a)
-			r := nl
-			nl = nr
-			nr = r
-		}
-
-		if gc.Isslice(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal slice comparison")
-				break
-			}
-
-			a = optoas(a, gc.Types[gc.Tptr])
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Xoffset += int64(gc.Array_array)
-			n1.Type = gc.Types[gc.Tptr]
-			var tmp gc.Node
-			gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp)
-			gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isinter(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal interface comparison")
-				break
-			}
-
-			a = optoas(a, gc.Types[gc.Tptr])
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Type = gc.Types[gc.Tptr]
-			var tmp gc.Node
-			gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp)
-			gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Iscomplex[nl.Type.Etype] {
-			gc.Complexbool(a, nl, nr, true_, likely, to)
-			break
-		}
-
-		if gc.Is64(nr.Type) {
-			if nl.Addable == 0 || gc.Isconst(nl, gc.CTINT) {
-				var n1 gc.Node
-				gc.Tempname(&n1, nl.Type)
-				cgen(nl, &n1)
-				nl = &n1
-			}
-
-			if nr.Addable == 0 {
-				var n2 gc.Node
-				gc.Tempname(&n2, nr.Type)
-				cgen(nr, &n2)
-				nr = &n2
-			}
-
-			cmp64(nl, nr, a, likely, to)
-			break
-		}
-
-		var n2 gc.Node
-		if nr.Ullman >= gc.UINF {
-			if nl.Addable == 0 {
-				var n1 gc.Node
-				gc.Tempname(&n1, nl.Type)
-				cgen(nl, &n1)
-				nl = &n1
-			}
-
-			if nr.Addable == 0 {
-				var tmp gc.Node
-				gc.Tempname(&tmp, nr.Type)
-				cgen(nr, &tmp)
-				nr = &tmp
-			}
-
-			var n2 gc.Node
-			regalloc(&n2, nr.Type, nil)
-			cgen(nr, &n2)
-			nr = &n2
-			goto cmp
-		}
-
-		if nl.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, nl.Type)
-			cgen(nl, &n1)
-			nl = &n1
-		}
-
-		if gc.Smallintconst(nr) {
-			gins(optoas(gc.OCMP, nr.Type), nl, nr)
-			gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-			break
-		}
-
-		if nr.Addable == 0 {
-			var tmp gc.Node
-			gc.Tempname(&tmp, nr.Type)
-			cgen(nr, &tmp)
-			nr = &tmp
-		}
-
-		regalloc(&n2, nr.Type, nil)
-		gmove(nr, &n2)
-		nr = &n2
-
-	cmp:
-		gins(optoas(gc.OCMP, nr.Type), nl, nr)
-		gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-
-		if nl.Op == gc.OREGISTER {
-			regfree(nl)
-		}
-		regfree(nr)
-	}
-
-	return
-
-def:
-	var n1 gc.Node
-	regalloc(&n1, n.Type, nil)
-	cgen(n, &n1)
-	var n2 gc.Node
-	gc.Nodconst(&n2, n.Type, 0)
-	gins(optoas(gc.OCMP, n.Type), &n1, &n2)
-	a := x86.AJNE
-	if !true_ {
-		a = x86.AJEQ
-	}
-	gc.Patch(gc.Gbranch(a, n.Type, likely), to)
-	regfree(&n1)
-	return
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-func stkof(n *gc.Node) int32 {
-	switch n.Op {
-	case gc.OINDREG:
-		return int32(n.Xoffset)
-
-	case gc.ODOT:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		return int32(int64(off) + n.Xoffset)
-
-	case gc.OINDEX:
-		t := n.Left.Type
-		if !gc.Isfixedarray(t) {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		if gc.Isconst(n.Right, gc.CTINT) {
-			return int32(int64(off) + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval))
-		}
-		return 1000
-
-	case gc.OCALLMETH,
-		gc.OCALLINTER,
-		gc.OCALLFUNC:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			t = t.Type
-		}
-
-		var flist gc.Iter
-		t = gc.Structfirst(&flist, gc.Getoutarg(t))
-		if t != nil {
-			return int32(t.Width)
-		}
-	}
-
-	// botch - probably failing to recognize address
-	// arithmetic on the above. eg INDEX and DOT
-	return -1000
-}
-
-/*
- * struct gen
- *	memmove(&res, &n, w);
- */
-func sgen(n *gc.Node, res *gc.Node, w int64) {
-	if gc.Debug['g'] != 0 {
-		fmt.Printf("\nsgen w=%d\n", w)
-		gc.Dump("r", n)
-		gc.Dump("res", res)
-	}
-
-	if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF {
-		gc.Fatal("sgen UINF")
-	}
-
-	if w < 0 || int64(int32(w)) != w {
-		gc.Fatal("sgen copy %d", w)
-	}
-
-	if w == 0 {
-		// evaluate side effects only.
-		var tdst gc.Node
-		gc.Tempname(&tdst, gc.Types[gc.Tptr])
-
-		agen(res, &tdst)
-		agen(n, &tdst)
-		return
-	}
-
-	// If copying .args, that's all the results, so record definition sites
-	// for them for the liveness analysis.
-	if res.Op == gc.ONAME && res.Sym.Name == ".args" {
-		for l := gc.Curfn.Dcl; l != nil; l = l.Next {
-			if l.N.Class == gc.PPARAMOUT {
-				gc.Gvardef(l.N)
-			}
-		}
-	}
-
-	// Avoid taking the address for simple enough types.
-	if gc.Componentgen(n, res) {
-		return
-	}
-
-	// offset on the stack
-	osrc := stkof(n)
-
-	odst := stkof(res)
-
-	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
-		// osrc and odst both on stack, and at least one is in
-		// an unknown position.  Could generate code to test
-		// for forward/backward copy, but instead just copy
-		// to a temporary location first.
-		var tsrc gc.Node
-		gc.Tempname(&tsrc, n.Type)
-
-		sgen(n, &tsrc, w)
-		sgen(&tsrc, res, w)
-		return
-	}
-
+func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
 	var dst gc.Node
 	gc.Nodreg(&dst, gc.Types[gc.Tptr], x86.REG_DI)
 	var src gc.Node
@@ -1364,13 +59,13 @@
 	var tdst gc.Node
 	gc.Tempname(&tdst, gc.Types[gc.Tptr])
 	if n.Addable == 0 {
-		agen(n, &tsrc)
+		gc.Agen(n, &tsrc)
 	}
 	if res.Addable == 0 {
-		agen(res, &tdst)
+		gc.Agen(res, &tdst)
 	}
 	if n.Addable != 0 {
-		agen(n, &src)
+		gc.Agen(n, &src)
 	} else {
 		gmove(&tsrc, &src)
 	}
@@ -1380,7 +75,7 @@
 	}
 
 	if res.Addable != 0 {
-		agen(res, &dst)
+		gc.Agen(res, &dst)
 	} else {
 		gmove(&tdst, &dst)
 	}
diff --git a/src/cmd/8g/cgen64.go b/src/cmd/8g/cgen64.go
index 4c435f6..ee04bdb 100644
--- a/src/cmd/8g/cgen64.go
+++ b/src/cmd/8g/cgen64.go
@@ -27,7 +27,7 @@
 		gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0))
 
 	case gc.OMINUS:
-		cgen(n.Left, res)
+		gc.Cgen(n.Left, res)
 		var hi1 gc.Node
 		var lo1 gc.Node
 		split64(res, &lo1, &hi1)
@@ -38,7 +38,7 @@
 		return
 
 	case gc.OCOM:
-		cgen(n.Left, res)
+		gc.Cgen(n.Left, res)
 		var lo1 gc.Node
 		var hi1 gc.Node
 		split64(res, &lo1, &hi1)
@@ -66,14 +66,14 @@
 	if l.Addable == 0 {
 		var t1 gc.Node
 		gc.Tempname(&t1, l.Type)
-		cgen(l, &t1)
+		gc.Cgen(l, &t1)
 		l = &t1
 	}
 
 	if r != nil && r.Addable == 0 {
 		var t2 gc.Node
 		gc.Tempname(&t2, r.Type)
-		cgen(r, &t2)
+		gc.Cgen(r, &t2)
 		r = &t2
 	}
 
@@ -116,10 +116,10 @@
 		// let's call the next two EX and FX.
 	case gc.OMUL:
 		var ex gc.Node
-		regalloc(&ex, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&ex, gc.Types[gc.TPTR32], nil)
 
 		var fx gc.Node
-		regalloc(&fx, gc.Types[gc.TPTR32], nil)
+		gc.Regalloc(&fx, gc.Types[gc.TPTR32], nil)
 
 		// load args into DX:AX and EX:CX.
 		gins(x86.AMOVL, &lo1, &ax)
@@ -148,8 +148,8 @@
 		gins(x86.AADDL, &fx, &dx)
 		gc.Patch(p2, gc.Pc)
 
-		regfree(&ex)
-		regfree(&fx)
+		gc.Regfree(&ex)
+		gc.Regfree(&fx)
 
 		// We only rotate by a constant c in [0,64).
 	// if c >= 32:
@@ -523,10 +523,10 @@
 	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
 		gins(x86.ACMPL, &hi1, &hi2)
 	} else {
-		regalloc(&rr, gc.Types[gc.TINT32], nil)
+		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
 		gins(x86.AMOVL, &hi1, &rr)
 		gins(x86.ACMPL, &rr, &hi2)
-		regfree(&rr)
+		gc.Regfree(&rr)
 	}
 
 	var br *obj.Prog
@@ -580,10 +580,10 @@
 	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
 		gins(x86.ACMPL, &lo1, &lo2)
 	} else {
-		regalloc(&rr, gc.Types[gc.TINT32], nil)
+		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
 		gins(x86.AMOVL, &lo1, &rr)
 		gins(x86.ACMPL, &rr, &lo2)
-		regfree(&rr)
+		gc.Regfree(&rr)
 	}
 
 	// jump again
diff --git a/src/cmd/8g/galign.go b/src/cmd/8g/galign.go
index f0c878a..f5ff825 100644
--- a/src/cmd/8g/galign.go
+++ b/src/cmd/8g/galign.go
@@ -45,33 +45,44 @@
 	gc.Thearch.Typedefs = typedefs
 	gc.Thearch.REGSP = x86.REGSP
 	gc.Thearch.REGCTXT = x86.REGCTXT
+	gc.Thearch.REGCALLX = x86.REG_BX
+	gc.Thearch.REGCALLX2 = x86.REG_AX
+	gc.Thearch.REGRETURN = x86.REG_AX
+	gc.Thearch.REGMIN = x86.REG_AX
+	gc.Thearch.REGMAX = x86.REG_DI
+	gc.Thearch.FREGMIN = x86.REG_X0
+	gc.Thearch.FREGMAX = x86.REG_X7
 	gc.Thearch.MAXWIDTH = MAXWIDTH
-	gc.Thearch.Anyregalloc = anyregalloc
+	gc.Thearch.ReservedRegs = resvd
+
 	gc.Thearch.Betypeinit = betypeinit
-	gc.Thearch.Bgen = bgen
-	gc.Thearch.Cgen = cgen
-	gc.Thearch.Cgen_call = cgen_call
-	gc.Thearch.Cgen_callinter = cgen_callinter
-	gc.Thearch.Cgen_ret = cgen_ret
+	gc.Thearch.Bgen_float = bgen_float
+	gc.Thearch.Cgen64 = cgen64
+	gc.Thearch.Cgen_bmul = cgen_bmul
+	gc.Thearch.Cgen_float = cgen_float
+	gc.Thearch.Cgen_hmul = cgen_hmul
+	gc.Thearch.Cgen_shift = cgen_shift
 	gc.Thearch.Clearfat = clearfat
+	gc.Thearch.Cmp64 = cmp64
 	gc.Thearch.Defframe = defframe
+	gc.Thearch.Dodiv = cgen_div
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
-	gc.Thearch.Gclean = gclean
-	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
-	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
-	gc.Thearch.Igen = igen
+	gc.Thearch.Igenindex = igenindex
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
 	gc.Thearch.Proginfo = proginfo
-	gc.Thearch.Regalloc = regalloc
-	gc.Thearch.Regfree = regfree
 	gc.Thearch.Regtyp = regtyp
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
+	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Sudoaddable = sudoaddable
+	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
 	gc.Thearch.RtoB = RtoB
 	gc.Thearch.FtoB = FtoB
diff --git a/src/cmd/8g/ggen.go b/src/cmd/8g/ggen.go
index 3a197cd..69c6028 100644
--- a/src/cmd/8g/ggen.go
+++ b/src/cmd/8g/ggen.go
@@ -127,9 +127,9 @@
 		// NOTE: Must use agen, not igen, so that optimizer sees address
 		// being taken. We are not writing on field boundaries.
 		var n1 gc.Node
-		regalloc(&n1, gc.Types[gc.Tptr], nil)
+		gc.Regalloc(&n1, gc.Types[gc.Tptr], nil)
 
-		agen(nl, &n1)
+		gc.Agen(nl, &n1)
 		n1.Op = gc.OINDREG
 		var z gc.Node
 		gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
@@ -156,13 +156,13 @@
 			n1.Xoffset++
 		}
 
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
 	var n1 gc.Node
 	gc.Nodreg(&n1, gc.Types[gc.Tptr], x86.REG_DI)
-	agen(nl, &n1)
+	gc.Agen(nl, &n1)
 	gconreg(x86.AMOVL, 0, x86.REG_AX)
 
 	if q > 128 || (q >= 4 && gc.Nacl) {
@@ -190,312 +190,6 @@
 }
 
 /*
- * generate:
- *	call f
- *	proc=-1	normal call but no return
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
-  *	proc=3	normal call to C pointer (not Go func value)
-*/
-func ginscall(f *gc.Node, proc int) {
-	if f.Type != nil {
-		extra := int32(0)
-		if proc == 1 || proc == 2 {
-			extra = 2 * int32(gc.Widthptr)
-		}
-		gc.Setmaxarg(f.Type, extra)
-	}
-
-	switch proc {
-	default:
-		gc.Fatal("ginscall: bad proc %d", proc)
-
-	case 0, // normal call
-		-1: // normal call but no return
-		if f.Op == gc.ONAME && f.Class == gc.PFUNC {
-			if f == gc.Deferreturn {
-				// Deferred calls will appear to be returning to
-				// the CALL deferreturn(SB) that we are about to emit.
-				// However, the stack trace code will show the line
-				// of the instruction byte before the return PC.
-				// To avoid that being an unrelated instruction,
-				// insert an x86 NOP that we will have the right line number.
-				// x86 NOP 0x90 is really XCHG AX, AX; use that description
-				// because the NOP pseudo-instruction will be removed by
-				// the linker.
-				var reg gc.Node
-				gc.Nodreg(&reg, gc.Types[gc.TINT], x86.REG_AX)
-
-				gins(x86.AXCHGL, &reg, &reg)
-			}
-
-			p := gins(obj.ACALL, nil, f)
-			gc.Afunclit(&p.To, f)
-			if proc == -1 || gc.Noreturn(p) {
-				gins(obj.AUNDEF, nil, nil)
-			}
-			break
-		}
-
-		var reg gc.Node
-		gc.Nodreg(&reg, gc.Types[gc.Tptr], x86.REG_DX)
-		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[gc.Tptr], x86.REG_BX)
-		gmove(f, &reg)
-		reg.Op = gc.OINDREG
-		gmove(&reg, &r1)
-		reg.Op = gc.OREGISTER
-		gins(obj.ACALL, &reg, &r1)
-
-	case 3: // normal call of c function pointer
-		gins(obj.ACALL, nil, f)
-
-	case 1, // call in new proc (go)
-		2: // deferred call (defer)
-		var stk gc.Node
-
-		stk.Op = gc.OINDREG
-		stk.Val.U.Reg = x86.REG_SP
-		stk.Xoffset = 0
-
-		// size of arguments at 0(SP)
-		var con gc.Node
-		gc.Nodconst(&con, gc.Types[gc.TINT32], int64(gc.Argsize(f.Type)))
-
-		gins(x86.AMOVL, &con, &stk)
-
-		// FuncVal* at 4(SP)
-		stk.Xoffset = int64(gc.Widthptr)
-
-		gins(x86.AMOVL, f, &stk)
-
-		if proc == 1 {
-			ginscall(gc.Newproc, 0)
-		} else {
-			ginscall(gc.Deferproc, 0)
-		}
-		if proc == 2 {
-			var reg gc.Node
-			gc.Nodreg(&reg, gc.Types[gc.TINT32], x86.REG_AX)
-			gins(x86.ATESTL, &reg, &reg)
-			p := gc.Gbranch(x86.AJEQ, nil, +1)
-			cgen_ret(nil)
-			gc.Patch(p, gc.Pc)
-		}
-	}
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-func cgen_callinter(n *gc.Node, res *gc.Node, proc int) {
-	i := n.Left
-	if i.Op != gc.ODOTINTER {
-		gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0))
-	}
-
-	f := i.Right // field
-	if f.Op != gc.ONAME {
-		gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0))
-	}
-
-	i = i.Left // interface
-
-	if i.Addable == 0 {
-		var tmpi gc.Node
-		gc.Tempname(&tmpi, i.Type)
-		cgen(i, &tmpi)
-		i = &tmpi
-	}
-
-	gc.Genlist(n.List) // assign the args
-
-	// i is now addable, prepare an indirected
-	// register to hold its address.
-	var nodi gc.Node
-	igen(i, &nodi, res) // REG = &inter
-
-	var nodsp gc.Node
-	gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], x86.REG_SP)
-
-	nodsp.Xoffset = 0
-	if proc != 0 {
-		nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn
-	}
-	nodi.Type = gc.Types[gc.Tptr]
-	nodi.Xoffset += int64(gc.Widthptr)
-	cgen(&nodi, &nodsp) // {0 or 8}(SP) = 4(REG) -- i.data
-
-	var nodo gc.Node
-	regalloc(&nodo, gc.Types[gc.Tptr], res)
-
-	nodi.Type = gc.Types[gc.Tptr]
-	nodi.Xoffset -= int64(gc.Widthptr)
-	cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
-	regfree(&nodi)
-
-	var nodr gc.Node
-	regalloc(&nodr, gc.Types[gc.Tptr], &nodo)
-	if n.Left.Xoffset == gc.BADWIDTH {
-		gc.Fatal("cgen_callinter: badwidth")
-	}
-	gc.Cgen_checknil(&nodo)
-	nodo.Op = gc.OINDREG
-	nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8
-
-	if proc == 0 {
-		// plain call: use direct c function pointer - more efficient
-		cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f]
-		proc = 3
-	} else {
-		// go/defer. generate go func value.
-		gins(x86.ALEAL, &nodo, &nodr) // REG = &(20+offset(REG)) -- i.tab->fun[f]
-	}
-
-	nodr.Type = n.Left.Type
-	ginscall(&nodr, proc)
-
-	regfree(&nodr)
-	regfree(&nodo)
-}
-
-/*
- * generate function call;
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
- */
-func cgen_call(n *gc.Node, proc int) {
-	if n == nil {
-		return
-	}
-
-	var afun gc.Node
-	if n.Left.Ullman >= gc.UINF {
-		// if name involves a fn call
-		// precompute the address of the fn
-		gc.Tempname(&afun, gc.Types[gc.Tptr])
-
-		cgen(n.Left, &afun)
-	}
-
-	gc.Genlist(n.List) // assign the args
-	t := n.Left.Type
-
-	// call tempname pointer
-	if n.Left.Ullman >= gc.UINF {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, &afun)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call pointer
-	if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, n.Left)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call direct
-	n.Left.Method = 1
-
-	ginscall(n.Left, proc)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = return value from call.
- */
-func cgen_callret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_callret: nil")
-	}
-
-	var nod gc.Node
-	nod.Op = gc.OINDREG
-	nod.Val.U.Reg = x86.REG_SP
-	nod.Addable = 1
-
-	nod.Xoffset = fp.Width
-	nod.Type = fp.Type
-	gc.Cgen_as(res, &nod)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = &return value from call.
- */
-func cgen_aret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if gc.Isptr[t.Etype] {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	var nod1 gc.Node
-	nod1.Op = gc.OINDREG
-	nod1.Val.U.Reg = x86.REG_SP
-	nod1.Addable = 1
-
-	nod1.Xoffset = fp.Width
-	nod1.Type = fp.Type
-
-	if res.Op != gc.OREGISTER {
-		var nod2 gc.Node
-		regalloc(&nod2, gc.Types[gc.Tptr], res)
-		gins(x86.ALEAL, &nod1, &nod2)
-		gins(x86.AMOVL, &nod2, res)
-		regfree(&nod2)
-	} else {
-		gins(x86.ALEAL, &nod1, res)
-	}
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-func cgen_ret(n *gc.Node) {
-	if n != nil {
-		gc.Genlist(n.List) // copy out args
-	}
-	if gc.Hasdefer != 0 {
-		ginscall(gc.Deferreturn, 0)
-	}
-	gc.Genlist(gc.Curfn.Exit)
-	p := gins(obj.ARET, nil, nil)
-	if n != nil && n.Op == gc.ORETJMP {
-		p.To.Type = obj.TYPE_MEM
-		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(n.Left.Sym)
-	}
-}
-
-/*
  * generate division.
  * caller must set:
  *	ax = allocated AX register
@@ -545,23 +239,23 @@
 		gc.Tempname(&t3, t0)
 		var t4 gc.Node
 		gc.Tempname(&t4, t0)
-		cgen(nl, &t3)
-		cgen(nr, &t4)
+		gc.Cgen(nl, &t3)
+		gc.Cgen(nr, &t4)
 
 		// Convert.
 		gmove(&t3, &t1)
 
 		gmove(&t4, &t2)
 	} else {
-		cgen(nl, &t1)
-		cgen(nr, &t2)
+		gc.Cgen(nl, &t1)
+		gc.Cgen(nr, &t2)
 	}
 
 	var n1 gc.Node
 	if !gc.Samereg(ax, res) && !gc.Samereg(dx, res) {
-		regalloc(&n1, t, res)
+		gc.Regalloc(&n1, t, res)
 	} else {
-		regalloc(&n1, t, nil)
+		gc.Regalloc(&n1, t, nil)
 	}
 	gmove(&t2, &n1)
 	gmove(&t1, ax)
@@ -578,7 +272,7 @@
 		if panicdiv == nil {
 			panicdiv = gc.Sysfunc("panicdivide")
 		}
-		ginscall(panicdiv, -1)
+		gc.Ginscall(panicdiv, -1)
 		gc.Patch(p1, gc.Pc)
 	}
 
@@ -610,7 +304,7 @@
 		gins(optoas(gc.OEXTEND, t), nil, nil)
 	}
 	gins(optoas(op, t), &n1, nil)
-	regfree(&n1)
+	gc.Regfree(&n1)
 
 	if op == gc.ODIV {
 		gmove(ax, res)
@@ -635,11 +329,11 @@
 		gmove(x, oldx)
 	}
 
-	regalloc(x, t, x)
+	gc.Regalloc(x, t, x)
 }
 
 func restx(x *gc.Node, oldx *gc.Node) {
-	regfree(x)
+	gc.Regfree(x)
 
 	if oldx.Op != 0 {
 		x.Type = gc.Types[gc.TINT32]
@@ -691,9 +385,9 @@
 	if nr.Op == gc.OLITERAL {
 		var n2 gc.Node
 		gc.Tempname(&n2, nl.Type)
-		cgen(nl, &n2)
+		gc.Cgen(nl, &n2)
 		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
+		gc.Regalloc(&n1, nl.Type, res)
 		gmove(&n2, &n1)
 		sc := uint64(gc.Mpgetfix(nr.Val.U.Xval))
 		if sc >= uint64(nl.Type.Width*8) {
@@ -705,7 +399,7 @@
 			gins(a, nr, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
@@ -724,21 +418,21 @@
 		n1 = nt
 	} else {
 		gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
-		regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
+		gc.Regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
 	}
 
 	var n2 gc.Node
 	if gc.Samereg(&cx, res) {
-		regalloc(&n2, nl.Type, nil)
+		gc.Regalloc(&n2, nl.Type, nil)
 	} else {
-		regalloc(&n2, nl.Type, res)
+		gc.Regalloc(&n2, nl.Type, res)
 	}
 	if nl.Ullman >= nr.Ullman {
-		cgen(nl, &n2)
-		cgen(nr, &n1)
+		gc.Cgen(nl, &n2)
+		gc.Cgen(nr, &n1)
 	} else {
-		cgen(nr, &n1)
-		cgen(nl, &n2)
+		gc.Cgen(nr, &n1)
+		gc.Cgen(nl, &n2)
 	}
 
 	// test and fix up large shifts
@@ -747,7 +441,7 @@
 			// delayed reg alloc
 			gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
 
-			regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
+			gc.Regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
 			var lo gc.Node
 			var hi gc.Node
 			split64(&nt, &lo, &hi)
@@ -760,7 +454,7 @@
 			// delayed reg alloc
 			gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
 
-			regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
+			gc.Regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
 			var lo gc.Node
 			var hi gc.Node
 			split64(&nt, &lo, &hi)
@@ -793,8 +487,8 @@
 
 	gmove(&n2, res)
 
-	regfree(&n1)
-	regfree(&n2)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 /*
@@ -803,7 +497,11 @@
  * there is no 2-operand byte multiply instruction so
  * we do a full-width multiplication and truncate afterwards.
  */
-func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
+func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) bool {
+	if optoas(op, nl.Type) != x86.AIMULB {
+		return false
+	}
+
 	// copy from byte to full registers
 	t := gc.Types[gc.TUINT32]
 
@@ -820,18 +518,20 @@
 
 	var nt gc.Node
 	gc.Tempname(&nt, nl.Type)
-	cgen(nl, &nt)
+	gc.Cgen(nl, &nt)
 	var n1 gc.Node
-	regalloc(&n1, t, res)
-	cgen(nr, &n1)
+	gc.Regalloc(&n1, t, res)
+	gc.Cgen(nr, &n1)
 	var n2 gc.Node
-	regalloc(&n2, t, nil)
+	gc.Regalloc(&n2, t, nil)
 	gmove(&nt, &n2)
 	a := optoas(op, t)
 	gins(a, &n2, &n1)
-	regfree(&n2)
+	gc.Regfree(&n2)
 	gmove(&n1, res)
-	regfree(&n1)
+	gc.Regfree(&n1)
+
+	return true
 }
 
 /*
@@ -850,19 +550,19 @@
 	// gen nl in n1.
 	gc.Tempname(&n1, t)
 
-	cgen(nl, &n1)
+	gc.Cgen(nl, &n1)
 
 	// gen nr in n2.
-	regalloc(&n2, t, res)
+	gc.Regalloc(&n2, t, res)
 
-	cgen(nr, &n2)
+	gc.Cgen(nr, &n2)
 
 	// multiply.
 	gc.Nodreg(&ax, t, x86.REG_AX)
 
 	gmove(&n2, &ax)
 	gins(a, &n1, nil)
-	regfree(&n2)
+	gc.Regfree(&n2)
 
 	if t.Width == 1 {
 		// byte multiply behaves differently.
@@ -892,28 +592,28 @@
 		gmove(gc.Nodbool(true), res)
 		p3 := gc.Gbranch(obj.AJMP, nil, 0)
 		gc.Patch(p1, gc.Pc)
-		bgen(n, true, 0, p2)
+		gc.Bgen(n, true, 0, p2)
 		gmove(gc.Nodbool(false), res)
 		gc.Patch(p3, gc.Pc)
 		return
 
 	case gc.OPLUS:
-		cgen(nl, res)
+		gc.Cgen(nl, res)
 		return
 
 	case gc.OCONV:
 		if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) {
-			cgen(nl, res)
+			gc.Cgen(nl, res)
 			return
 		}
 
 		var n2 gc.Node
 		gc.Tempname(&n2, n.Type)
 		var n1 gc.Node
-		mgen(nl, &n1, res)
+		gc.Mgen(nl, &n1, res)
 		gmove(&n1, &n2)
 		gmove(&n2, res)
-		mfree(&n1)
+		gc.Mfree(&n1)
 		return
 	}
 
@@ -936,19 +636,19 @@
 	if nr != nil {
 		// binary
 		if nl.Ullman >= nr.Ullman {
-			cgen(nl, &f0)
+			gc.Cgen(nl, &f0)
 			if nr.Addable != 0 {
 				gins(foptoas(int(n.Op), n.Type, 0), nr, &f0)
 			} else {
-				cgen(nr, &f0)
+				gc.Cgen(nr, &f0)
 				gins(foptoas(int(n.Op), n.Type, Fpop), &f0, &f1)
 			}
 		} else {
-			cgen(nr, &f0)
+			gc.Cgen(nr, &f0)
 			if nl.Addable != 0 {
 				gins(foptoas(int(n.Op), n.Type, Frev), nl, &f0)
 			} else {
-				cgen(nl, &f0)
+				gc.Cgen(nl, &f0)
 				gins(foptoas(int(n.Op), n.Type, Frev|Fpop), &f0, &f1)
 			}
 		}
@@ -958,7 +658,7 @@
 	}
 
 	// unary
-	cgen(nl, &f0)
+	gc.Cgen(nl, &f0)
 
 	if n.Op != gc.OCONV && n.Op != gc.OPLUS {
 		gins(foptoas(int(n.Op), n.Type, 0), nil, nil)
@@ -1012,27 +712,27 @@
 	if nl.Ullman >= nr.Ullman {
 		var nt gc.Node
 		gc.Tempname(&nt, nl.Type)
-		cgen(nl, &nt)
+		gc.Cgen(nl, &nt)
 		var n2 gc.Node
-		mgen(nr, &n2, nil)
+		gc.Mgen(nr, &n2, nil)
 		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
+		gc.Regalloc(&n1, nl.Type, res)
 		gmove(&nt, &n1)
 		gins(a, &n2, &n1)
 		gmove(&n1, res)
-		regfree(&n1)
-		mfree(&n2)
+		gc.Regfree(&n1)
+		gc.Mfree(&n2)
 	} else {
 		var n2 gc.Node
-		regalloc(&n2, nr.Type, res)
-		cgen(nr, &n2)
+		gc.Regalloc(&n2, nr.Type, res)
+		gc.Cgen(nr, &n2)
 		var n1 gc.Node
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
+		gc.Regalloc(&n1, nl.Type, nil)
+		gc.Cgen(nl, &n1)
 		gins(a, &n2, &n1)
-		regfree(&n2)
+		gc.Regfree(&n2)
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 	}
 
 	return
@@ -1065,25 +765,25 @@
 		if nl.Addable == 0 {
 			var n1 gc.Node
 			gc.Tempname(&n1, nl.Type)
-			cgen(nl, &n1)
+			gc.Cgen(nl, &n1)
 			nl = &n1
 		}
 
 		if nr.Addable == 0 {
 			var tmp gc.Node
 			gc.Tempname(&tmp, nr.Type)
-			cgen(nr, &tmp)
+			gc.Cgen(nr, &tmp)
 			nr = &tmp
 		}
 
 		var n2 gc.Node
-		regalloc(&n2, nr.Type, nil)
+		gc.Regalloc(&n2, nr.Type, nil)
 		gmove(nr, &n2)
 		nr = &n2
 
 		if nl.Op != gc.OREGISTER {
 			var n3 gc.Node
-			regalloc(&n3, nl.Type, nil)
+			gc.Regalloc(&n3, nl.Type, nil)
 			gmove(nl, &n3)
 			nl = &n3
 		}
@@ -1099,9 +799,9 @@
 
 		gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr)
 		if nl.Op == gc.OREGISTER {
-			regfree(nl)
+			gc.Regfree(nl)
 		}
-		regfree(nr)
+		gc.Regfree(nr)
 		goto ret
 	} else {
 		goto x87
@@ -1124,12 +824,12 @@
 	et = gc.Simsimtype(nr.Type)
 	if et == gc.TFLOAT64 {
 		if nl.Ullman > nr.Ullman {
-			cgen(nl, &tmp)
-			cgen(nr, &tmp)
+			gc.Cgen(nl, &tmp)
+			gc.Cgen(nr, &tmp)
 			gins(x86.AFXCHD, &tmp, &n2)
 		} else {
-			cgen(nr, &tmp)
-			cgen(nl, &tmp)
+			gc.Cgen(nr, &tmp)
+			gc.Cgen(nl, &tmp)
 		}
 
 		gins(x86.AFUCOMIP, &tmp, &n2)
@@ -1146,8 +846,8 @@
 
 		var t2 gc.Node
 		gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
-		cgen(nr, &t1)
-		cgen(nl, &t2)
+		gc.Cgen(nr, &t1)
+		gc.Cgen(nl, &t2)
 		gmove(&t2, &tmp)
 		gins(x86.AFCOMFP, &t1, &tmp)
 		gins(x86.AFSTSW, nil, &ax)
@@ -1230,3 +930,17 @@
 		p2.To.Offset = 0
 	}
 }
+
+// addr += index*width if possible.
+func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
+	switch width {
+	case 1, 2, 4, 8:
+		p1 := gins(x86.ALEAL, index, addr)
+		p1.From.Type = obj.TYPE_MEM
+		p1.From.Scale = int16(width)
+		p1.From.Index = p1.From.Reg
+		p1.From.Reg = p1.To.Reg
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go
index cc5efdf..fa28b6d 100644
--- a/src/cmd/8g/gsubr.go
+++ b/src/cmd/8g/gsubr.go
@@ -550,184 +550,6 @@
 	x86.REG_CX, // for shift
 	x86.REG_DX, // for divide
 	x86.REG_SP, // for stack
-
-	x86.REG_BL, // because REG_BX can be allocated
-	x86.REG_BH,
-}
-
-func ginit() {
-	for i := 0; i < len(reg); i++ {
-		reg[i] = 1
-	}
-	for i := x86.REG_AX; i <= x86.REG_DI; i++ {
-		reg[i] = 0
-	}
-	for i := x86.REG_X0; i <= x86.REG_X7; i++ {
-		reg[i] = 0
-	}
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]]++
-	}
-}
-
-var regpc [x86.MAXREG]uint32
-
-func gclean() {
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]]--
-	}
-
-	for i := x86.REG_AX; i <= x86.REG_DI; i++ {
-		if reg[i] != 0 {
-			gc.Yyerror("reg %v left allocated at %x", obj.Rconv(i), regpc[i])
-		}
-	}
-	for i := x86.REG_X0; i <= x86.REG_X7; i++ {
-		if reg[i] != 0 {
-			gc.Yyerror("reg %v left allocated\n", obj.Rconv(i))
-		}
-	}
-}
-
-func anyregalloc() bool {
-	var j int
-
-	for i := x86.REG_AX; i <= x86.REG_DI; i++ {
-		if reg[i] == 0 {
-			goto ok
-		}
-		for j = 0; j < len(resvd); j++ {
-			if resvd[j] == i {
-				goto ok
-			}
-		}
-		return true
-	ok:
-	}
-
-	for i := x86.REG_X0; i <= x86.REG_X7; i++ {
-		if reg[i] != 0 {
-			return true
-		}
-	}
-	return false
-}
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) {
-	if t == nil {
-		gc.Fatal("regalloc: t nil")
-	}
-	et := int(gc.Simtype[t.Etype])
-
-	var i int
-	switch et {
-	case gc.TINT64,
-		gc.TUINT64:
-		gc.Fatal("regalloc64")
-
-	case gc.TINT8,
-		gc.TUINT8,
-		gc.TINT16,
-		gc.TUINT16,
-		gc.TINT32,
-		gc.TUINT32,
-		gc.TPTR32,
-		gc.TPTR64,
-		gc.TBOOL:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= x86.REG_AX && i <= x86.REG_DI {
-				goto out
-			}
-		}
-
-		for i = x86.REG_AX; i <= x86.REG_DI; i++ {
-			if reg[i] == 0 {
-				goto out
-			}
-		}
-
-		fmt.Printf("registers allocated at\n")
-		for i := x86.REG_AX; i <= x86.REG_DI; i++ {
-			fmt.Printf("\t%v\t%#x\n", obj.Rconv(i), regpc[i])
-		}
-		gc.Fatal("out of fixed registers")
-		goto err
-
-	case gc.TFLOAT32,
-		gc.TFLOAT64:
-		if gc.Use_sse == 0 {
-			i = x86.REG_F0
-			goto out
-		}
-
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= x86.REG_X0 && i <= x86.REG_X7 {
-				goto out
-			}
-		}
-
-		for i = x86.REG_X0; i <= x86.REG_X7; i++ {
-			if reg[i] == 0 {
-				goto out
-			}
-		}
-		fmt.Printf("registers allocated at\n")
-		for i := x86.REG_X0; i <= x86.REG_X7; i++ {
-			fmt.Printf("\t%v\t%#x\n", obj.Rconv(i), regpc[i])
-		}
-		gc.Fatal("out of floating registers")
-	}
-
-	gc.Yyerror("regalloc: unknown type %v", gc.Tconv(t, 0))
-
-err:
-	gc.Nodreg(n, t, 0)
-	return
-
-out:
-	if i == x86.REG_SP {
-		fmt.Printf("alloc SP\n")
-	}
-	if reg[i] == 0 {
-		regpc[i] = uint32(obj.Getcallerpc(&n))
-		if i == x86.REG_AX || i == x86.REG_CX || i == x86.REG_DX || i == x86.REG_SP {
-			gc.Dump("regalloc-o", o)
-			gc.Fatal("regalloc %v", obj.Rconv(i))
-		}
-	}
-
-	reg[i]++
-	gc.Nodreg(n, t, i)
-}
-
-func regfree(n *gc.Node) {
-	if n.Op == gc.ONAME {
-		return
-	}
-	if n.Op != gc.OREGISTER && n.Op != gc.OINDREG {
-		gc.Fatal("regfree: not a register")
-	}
-	i := int(n.Val.U.Reg)
-	if i == x86.REG_SP {
-		return
-	}
-	if i < 0 || i >= len(reg) {
-		gc.Fatal("regfree: reg out of range")
-	}
-	if reg[i] <= 0 {
-		gc.Fatal("regfree: reg not allocated")
-	}
-	reg[i]--
-	if reg[i] == 0 && (i == x86.REG_AX || i == x86.REG_CX || i == x86.REG_DX || i == x86.REG_SP) {
-		gc.Fatal("regfree %v", obj.Rconv(i))
-	}
 }
 
 /*
@@ -744,6 +566,16 @@
 }
 
 /*
+ * generate
+ *	as $c, n
+ */
+func ginscon(as int, c int64, n2 *gc.Node) {
+	var n1 gc.Node
+	gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
+	gins(as, &n1, n2)
+}
+
+/*
  * swap node contents
  */
 func nswap(a *gc.Node, b *gc.Node) {
@@ -790,7 +622,7 @@
 		default:
 			var n1 gc.Node
 			if !dotaddable(n, &n1) {
-				igen(n, &n1, nil)
+				gc.Igen(n, &n1, nil)
 				sclean[nsclean-1] = n1
 			}
 
@@ -799,7 +631,7 @@
 		case gc.ONAME:
 			if n.Class == gc.PPARAMREF {
 				var n1 gc.Node
-				cgen(n.Heapaddr, &n1)
+				gc.Cgen(n.Heapaddr, &n1)
 				sclean[nsclean-1] = n1
 				n = &n1
 			}
@@ -839,7 +671,7 @@
 	}
 	nsclean--
 	if sclean[nsclean].Op != gc.OEMPTY {
-		regfree(&sclean[nsclean])
+		gc.Regfree(&sclean[nsclean])
 	}
 }
 
@@ -1139,31 +971,31 @@
 
 	// requires register source
 rsrc:
-	regalloc(&r1, f.Type, t)
+	gc.Regalloc(&r1, f.Type, t)
 
 	gmove(f, &r1)
 	gins(a, &r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 
 	// requires register destination
 rdst:
 	{
-		regalloc(&r1, t.Type, t)
+		gc.Regalloc(&r1, t.Type, t)
 
 		gins(a, f, &r1)
 		gmove(&r1, t)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		return
 	}
 
 	// requires register intermediate
 hard:
-	regalloc(&r1, cvt, t)
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 }
 
@@ -1408,11 +1240,11 @@
 
 	// requires register intermediate
 hard:
-	regalloc(&r1, cvt, t)
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 
 	// requires memory intermediate
@@ -1652,11 +1484,11 @@
 
 	// requires register intermediate
 hard:
-	regalloc(&r1, cvt, t)
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 
 	// requires memory intermediate
@@ -1774,11 +1606,11 @@
 
 	// requires register intermediate
 hard:
-	regalloc(&r1, cvt, t)
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 
 	// requires memory intermediate
@@ -1791,11 +1623,11 @@
 
 	// requires register destination
 rdst:
-	regalloc(&r1, t.Type, t)
+	gc.Regalloc(&r1, t.Type, t)
 
 	gins(a, f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 }
 
@@ -1830,6 +1662,15 @@
 		gc.Fatal("gins MOVSD into F0")
 	}
 
+	if as == x86.AMOVL && f != nil && f.Op == gc.OADDR && f.Left.Op == gc.ONAME && f.Left.Class != gc.PEXTERN && f.Left.Class != gc.PFUNC {
+		// Turn MOVL $xxx(FP/SP) into LEAL xxx.
+		// These should be equivalent but most of the backend
+		// only expects to see LEAL, because that's what we had
+		// historically generated. Various hidden assumptions are baked in by now.
+		as = x86.ALEAL
+		f = f.Left
+	}
+
 	switch as {
 	case x86.AMOVB,
 		x86.AMOVW,
@@ -1877,6 +1718,12 @@
 	return p
 }
 
+func ginsnop() {
+	var reg gc.Node
+	gc.Nodreg(&reg, gc.Types[gc.TINT], x86.REG_AX)
+	gins(x86.AXCHGL, &reg, &reg)
+}
+
 func dotaddable(n *gc.Node, n1 *gc.Node) bool {
 	if n.Op != gc.ODOT {
 		return false
diff --git a/src/cmd/8g/peep.go b/src/cmd/8g/peep.go
index 91055fd..e309aea7 100644
--- a/src/cmd/8g/peep.go
+++ b/src/cmd/8g/peep.go
@@ -672,7 +672,7 @@
 	if regtyp(v) {
 		return true
 	}
-	if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
+	if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
 		if v.Offset == a.Offset {
 			return true
 		}
@@ -687,7 +687,7 @@
 	if regtyp(v) {
 		return true
 	}
-	if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
+	if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
 		if v.Offset == a.Offset {
 			return true
 		}
@@ -703,7 +703,7 @@
 		return true
 	}
 	if regtyp(v) {
-		if a.Type == obj.TYPE_MEM && a.Reg == v.Reg {
+		if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == v.Reg {
 			return true
 		}
 		if a.Index == v.Reg {
@@ -732,7 +732,7 @@
 
 	if regtyp(v) {
 		reg := int(v.Reg)
-		if a.Type == obj.TYPE_MEM && int(a.Reg) == reg {
+		if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && int(a.Reg) == reg {
 			if (s.Reg == x86.REG_BP) && a.Index != obj.TYPE_NONE {
 				return 1 /* can't use BP-base with index */
 			}
diff --git a/src/cmd/9g/cgen.go b/src/cmd/9g/cgen.go
index 6ab7f35..0f7fc07 100644
--- a/src/cmd/9g/cgen.go
+++ b/src/cmd/9g/cgen.go
@@ -8,1458 +8,9 @@
 	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
-	"fmt"
 )
 
-/*
- * peep.c
- */
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- */
-func cgen(n *gc.Node, res *gc.Node) {
-	//print("cgen %N(%d) -> %N(%d)\n", n, n->addable, res, res->addable);
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\ncgen-n", n)
-		gc.Dump("cgen-res", res)
-	}
-
-	if n == nil || n.Type == nil {
-		return
-	}
-
-	if res == nil || res.Type == nil {
-		gc.Fatal("cgen: res nil")
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	switch n.Op {
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_slice(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_slice(n, res)
-		}
-		return
-
-	case gc.OEFACE:
-		if res.Op != gc.ONAME || res.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			gc.Cgen_eface(n, &n1)
-			cgen(&n1, res)
-		} else {
-			gc.Cgen_eface(n, res)
-		}
-		return
-	}
-
-	if n.Ullman >= gc.UINF {
-		if n.Op == gc.OINDREG {
-			gc.Fatal("cgen: this is going to misscompile")
-		}
-		if res.Ullman >= gc.UINF {
-			var n1 gc.Node
-			gc.Tempname(&n1, n.Type)
-			cgen(n, &n1)
-			cgen(&n1, res)
-			return
-		}
-	}
-
-	if gc.Isfat(n.Type) {
-		if n.Type.Width < 0 {
-			gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0))
-		}
-		sgen(n, res, n.Type.Width)
-		return
-	}
-
-	if res.Addable == 0 {
-		if n.Ullman > res.Ullman {
-			var n1 gc.Node
-			regalloc(&n1, n.Type, res)
-			cgen(n, &n1)
-			if n1.Ullman > res.Ullman {
-				gc.Dump("n1", &n1)
-				gc.Dump("res", res)
-				gc.Fatal("loop in cgen")
-			}
-
-			cgen(&n1, res)
-			regfree(&n1)
-			return
-		}
-
-		var f int
-		if res.Ullman >= gc.UINF {
-			goto gen
-		}
-
-		if gc.Complexop(n, res) {
-			gc.Complexgen(n, res)
-			return
-		}
-
-		f = 1 // gen thru register
-		switch n.Op {
-		case gc.OLITERAL:
-			if gc.Smallintconst(n) {
-				f = 0
-			}
-
-		case gc.OREGISTER:
-			f = 0
-		}
-
-		if !gc.Iscomplex[n.Type.Etype] {
-			a := optoas(gc.OAS, res.Type)
-			var addr obj.Addr
-			if sudoaddable(a, res, &addr) {
-				var p1 *obj.Prog
-				if f != 0 {
-					var n2 gc.Node
-					regalloc(&n2, res.Type, nil)
-					cgen(n, &n2)
-					p1 = gins(a, &n2, nil)
-					regfree(&n2)
-				} else {
-					p1 = gins(a, n, nil)
-				}
-				p1.To = addr
-				if gc.Debug['g'] != 0 {
-					fmt.Printf("%v [ignore previous line]\n", p1)
-				}
-				sudoclean()
-				return
-			}
-		}
-
-	gen:
-		var n1 gc.Node
-		igen(res, &n1, nil)
-		cgen(n, &n1)
-		regfree(&n1)
-		return
-	}
-
-	// update addressability for string, slice
-	// can't do in walk because n->left->addable
-	// changes if n->left is an escaping local variable.
-	switch n.Op {
-	case gc.OSPTR,
-		gc.OLEN:
-		if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OCAP:
-		if gc.Isslice(n.Left.Type) {
-			n.Addable = n.Left.Addable
-		}
-
-	case gc.OITAB:
-		n.Addable = n.Left.Addable
-	}
-
-	if gc.Complexop(n, res) {
-		gc.Complexgen(n, res)
-		return
-	}
-
-	// if both are addressable, move
-	if n.Addable != 0 {
-		if n.Op == gc.OREGISTER || res.Op == gc.OREGISTER {
-			gmove(n, res)
-		} else {
-			var n1 gc.Node
-			regalloc(&n1, n.Type, nil)
-			gmove(n, &n1)
-			cgen(&n1, res)
-			regfree(&n1)
-		}
-
-		return
-	}
-
-	nl := n.Left
-	nr := n.Right
-
-	if nl != nil && nl.Ullman >= gc.UINF {
-		if nr != nil && nr.Ullman >= gc.UINF {
-			var n1 gc.Node
-			gc.Tempname(&n1, nl.Type)
-			cgen(nl, &n1)
-			n2 := *n
-			n2.Left = &n1
-			cgen(&n2, res)
-			return
-		}
-	}
-
-	if !gc.Iscomplex[n.Type.Etype] {
-		a := optoas(gc.OAS, n.Type)
-		var addr obj.Addr
-		if sudoaddable(a, n, &addr) {
-			if res.Op == gc.OREGISTER {
-				p1 := gins(a, nil, res)
-				p1.From = addr
-			} else {
-				var n2 gc.Node
-				regalloc(&n2, n.Type, nil)
-				p1 := gins(a, nil, &n2)
-				p1.From = addr
-				gins(a, &n2, res)
-				regfree(&n2)
-			}
-
-			sudoclean()
-			return
-		}
-	}
-
-	// TODO(minux): we shouldn't reverse FP comparisons, but then we need to synthesize
-	// OGE, OLE, and ONE ourselves.
-	// if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) goto flt;
-
-	var a int
-	switch n.Op {
-	default:
-		gc.Dump("cgen", n)
-		gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign))
-
-		// these call bgen to get a bool value
-	case gc.OOROR,
-		gc.OANDAND,
-		gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OLE,
-		gc.OGE,
-		gc.OGT,
-		gc.ONOT:
-		p1 := gc.Gbranch(ppc64.ABR, nil, 0)
-
-		p2 := gc.Pc
-		gmove(gc.Nodbool(true), res)
-		p3 := gc.Gbranch(ppc64.ABR, nil, 0)
-		gc.Patch(p1, gc.Pc)
-		bgen(n, true, 0, p2)
-		gmove(gc.Nodbool(false), res)
-		gc.Patch(p3, gc.Pc)
-		return
-
-	case gc.OPLUS:
-		cgen(nl, res)
-		return
-
-		// unary
-	case gc.OCOM:
-		a := optoas(gc.OXOR, nl.Type)
-
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-		var n2 gc.Node
-		gc.Nodconst(&n2, nl.Type, -1)
-		gins(a, &n2, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		return
-
-	case gc.OMINUS:
-		if gc.Isfloat[nl.Type.Etype] {
-			nr = gc.Nodintconst(-1)
-			gc.Convlit(&nr, n.Type)
-			a = optoas(gc.OMUL, nl.Type)
-			goto sbop
-		}
-
-		a := optoas(int(n.Op), nl.Type)
-		// unary
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-
-		cgen(nl, &n1)
-		gins(a, nil, &n1)
-		gmove(&n1, res)
-		regfree(&n1)
-		return
-
-		// symmetric binary
-	case gc.OAND,
-		gc.OOR,
-		gc.OXOR,
-		gc.OADD,
-		gc.OMUL:
-		a = optoas(int(n.Op), nl.Type)
-
-		goto sbop
-
-		// asymmetric binary
-	case gc.OSUB:
-		a = optoas(int(n.Op), nl.Type)
-
-		goto abop
-
-	case gc.OHMUL:
-		cgen_hmul(nl, nr, res)
-
-	case gc.OCONV:
-		if n.Type.Width > nl.Type.Width {
-			// If loading from memory, do conversion during load,
-			// so as to avoid use of 8-bit register in, say, int(*byteptr).
-			switch nl.Op {
-			case gc.ODOT,
-				gc.ODOTPTR,
-				gc.OINDEX,
-				gc.OIND,
-				gc.ONAME:
-				var n1 gc.Node
-				igen(nl, &n1, res)
-				var n2 gc.Node
-				regalloc(&n2, n.Type, res)
-				gmove(&n1, &n2)
-				gmove(&n2, res)
-				regfree(&n2)
-				regfree(&n1)
-				return
-			}
-		}
-
-		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-		var n2 gc.Node
-		regalloc(&n2, n.Type, &n1)
-		cgen(nl, &n1)
-
-		// if we do the conversion n1 -> n2 here
-		// reusing the register, then gmove won't
-		// have to allocate its own register.
-		gmove(&n1, &n2)
-
-		gmove(&n2, res)
-		regfree(&n2)
-		regfree(&n1)
-
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OIND,
-		gc.ONAME: // PHEAP or PPARAMREF var
-		var n1 gc.Node
-		igen(n, &n1, res)
-
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// interface table is first word of interface value
-	case gc.OITAB:
-		var n1 gc.Node
-		igen(nl, &n1, res)
-
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// pointer is the first word of string or slice.
-	case gc.OSPTR:
-		if gc.Isconst(nl, gc.CTSTR) {
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-			p1 := gins(ppc64.AMOVD, nil, &n1)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		var n1 gc.Node
-		igen(nl, &n1, res)
-		n1.Type = n.Type
-		gmove(&n1, res)
-		regfree(&n1)
-
-	case gc.OLEN:
-		if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) {
-			// map and chan have len in the first int-sized word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-
-			cgen(nl, &n1)
-
-			var n2 gc.Node
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Type = gc.Types[gc.Simtype[gc.TINT]]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) {
-			// both slice and string have len one pointer into the struct.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			igen(nl, &n1, res)
-
-			n1.Type = gc.Types[gc.Simtype[gc.TUINT]]
-			n1.Xoffset += int64(gc.Array_nel)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OCAP:
-		if gc.Istype(nl.Type, gc.TCHAN) {
-			// chan has cap in the second int-sized word.
-			// a zero pointer means zero length
-			var n1 gc.Node
-			regalloc(&n1, gc.Types[gc.Tptr], res)
-
-			cgen(nl, &n1)
-
-			var n2 gc.Node
-			gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
-			p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0)
-
-			n2 = n1
-			n2.Op = gc.OINDREG
-			n2.Xoffset = int64(gc.Widthint)
-			n2.Type = gc.Types[gc.Simtype[gc.TINT]]
-			gmove(&n2, &n1)
-
-			gc.Patch(p1, gc.Pc)
-
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isslice(nl.Type) {
-			var n1 gc.Node
-			igen(nl, &n1, res)
-			n1.Type = gc.Types[gc.Simtype[gc.TUINT]]
-			n1.Xoffset += int64(gc.Array_cap)
-			gmove(&n1, res)
-			regfree(&n1)
-			break
-		}
-
-		gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
-	case gc.OADDR:
-		if n.Bounded { // let race detector avoid nil checks
-			gc.Disable_checknil++
-		}
-		agen(nl, res)
-		if n.Bounded {
-			gc.Disable_checknil--
-		}
-
-	case gc.OCALLMETH:
-		gc.Cgen_callmeth(n, 0)
-		cgen_callret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_callret(n, res)
-
-	case gc.OCALLFUNC:
-		cgen_call(n, 0)
-		cgen_callret(n, res)
-
-	case gc.OMOD,
-		gc.ODIV:
-		if gc.Isfloat[n.Type.Etype] {
-			a = optoas(int(n.Op), nl.Type)
-			goto abop
-		}
-
-		if nl.Ullman >= nr.Ullman {
-			var n1 gc.Node
-			regalloc(&n1, nl.Type, res)
-			cgen(nl, &n1)
-			cgen_div(int(n.Op), &n1, nr, res)
-			regfree(&n1)
-		} else {
-			var n2 gc.Node
-			if !gc.Smallintconst(nr) {
-				regalloc(&n2, nr.Type, res)
-				cgen(nr, &n2)
-			} else {
-				n2 = *nr
-			}
-
-			cgen_div(int(n.Op), nl, &n2, res)
-			if n2.Op != gc.OLITERAL {
-				regfree(&n2)
-			}
-		}
-
-	case gc.OLSH,
-		gc.ORSH,
-		gc.OLROT:
-		cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
-	}
-
-	return
-
-	/*
-	 * put simplest on right - we'll generate into left
-	 * and then adjust it using the computation of right.
-	 * constants and variables have the same ullman
-	 * count, so look for constants specially.
-	 *
-	 * an integer constant we can use as an immediate
-	 * is simpler than a variable - we can use the immediate
-	 * in the adjustment instruction directly - so it goes
-	 * on the right.
-	 *
-	 * other constants, like big integers or floating point
-	 * constants, require a mov into a register, so those
-	 * might as well go on the left, so we can reuse that
-	 * register for the computation.
-	 */
-sbop: // symmetric binary
-	if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (gc.Smallintconst(nl) || (nr.Op == gc.OLITERAL && !gc.Smallintconst(nr)))) {
-		r := nl
-		nl = nr
-		nr = r
-	}
-
-abop: // asymmetric binary
-	var n1 gc.Node
-	var n2 gc.Node
-	if nl.Ullman >= nr.Ullman {
-		regalloc(&n1, nl.Type, res)
-		cgen(nl, &n1)
-
-		/*
-			 * This generates smaller code - it avoids a MOV - but it's
-			 * easily 10% slower due to not being able to
-			 * optimize/manipulate the move.
-			 * To see, run: go test -bench . crypto/md5
-			 * with and without.
-			 *
-				if(sudoaddable(a, nr, &addr)) {
-					p1 = gins(a, N, &n1);
-					p1->from = addr;
-					gmove(&n1, res);
-					sudoclean();
-					regfree(&n1);
-					goto ret;
-				}
-			 *
-		*/
-		// TODO(minux): enable using constants directly in certain instructions.
-		//if(smallintconst(nr))
-		//	n2 = *nr;
-		//else {
-		regalloc(&n2, nr.Type, nil)
-
-		cgen(nr, &n2)
-	} else //}
-	{
-		//if(smallintconst(nr))
-		//	n2 = *nr;
-		//else {
-		regalloc(&n2, nr.Type, res)
-
-		cgen(nr, &n2)
-
-		//}
-		regalloc(&n1, nl.Type, nil)
-
-		cgen(nl, &n1)
-	}
-
-	gins(a, &n2, &n1)
-
-	// Normalize result for types smaller than word.
-	if n.Type.Width < int64(gc.Widthreg) {
-		switch n.Op {
-		case gc.OADD,
-			gc.OSUB,
-			gc.OMUL,
-			gc.OLSH:
-			gins(optoas(gc.OAS, n.Type), &n1, &n1)
-		}
-	}
-
-	gmove(&n1, res)
-	regfree(&n1)
-	if n2.Op != gc.OLITERAL {
-		regfree(&n2)
-	}
-	return
-}
-
-/*
- * allocate a register (reusing res if possible) and generate
- *  a = n
- * The caller must call regfree(a).
- */
-func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("cgenr-n", n)
-	}
-
-	if gc.Isfat(n.Type) {
-		gc.Fatal("cgenr on fat node")
-	}
-
-	if n.Addable != 0 {
-		regalloc(a, n.Type, res)
-		gmove(n, a)
-		return
-	}
-
-	switch n.Op {
-	case gc.ONAME,
-		gc.ODOT,
-		gc.ODOTPTR,
-		gc.OINDEX,
-		gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		var n1 gc.Node
-		igen(n, &n1, res)
-		regalloc(a, gc.Types[gc.Tptr], &n1)
-		gmove(&n1, a)
-		regfree(&n1)
-
-	default:
-		regalloc(a, n.Type, res)
-		cgen(n, a)
-	}
-}
-
-/*
- * allocate a register (reusing res if possible) and generate
- * a = &n
- * The caller must call regfree(a).
- * The generated code checks that the result is not nil.
- */
-func agenr(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("agenr-n", n)
-	}
-
-	nl := n.Left
-	nr := n.Right
-
-	switch n.Op {
-	case gc.ODOT,
-		gc.ODOTPTR,
-		gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		var n1 gc.Node
-		igen(n, &n1, res)
-		regalloc(a, gc.Types[gc.Tptr], &n1)
-		agen(&n1, a)
-		regfree(&n1)
-
-	case gc.OIND:
-		cgenr(n.Left, a, res)
-		gc.Cgen_checknil(a)
-
-	case gc.OINDEX:
-		var p2 *obj.Prog // to be patched to panicindex.
-		w := uint32(n.Type.Width)
-
-		//bounded = debug['B'] || n->bounded;
-		var n3 gc.Node
-		var n1 gc.Node
-		if nr.Addable != 0 {
-			var tmp gc.Node
-			if !gc.Isconst(nr, gc.CTINT) {
-				gc.Tempname(&tmp, gc.Types[gc.TINT64])
-			}
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-			if !gc.Isconst(nr, gc.CTINT) {
-				cgen(nr, &tmp)
-				regalloc(&n1, tmp.Type, nil)
-				gmove(&tmp, &n1)
-			}
-		} else if nl.Addable != 0 {
-			if !gc.Isconst(nr, gc.CTINT) {
-				var tmp gc.Node
-				gc.Tempname(&tmp, gc.Types[gc.TINT64])
-				cgen(nr, &tmp)
-				regalloc(&n1, tmp.Type, nil)
-				gmove(&tmp, &n1)
-			}
-
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-		} else {
-			var tmp gc.Node
-			gc.Tempname(&tmp, gc.Types[gc.TINT64])
-			cgen(nr, &tmp)
-			nr = &tmp
-			if !gc.Isconst(nl, gc.CTSTR) {
-				agenr(nl, &n3, res)
-			}
-			regalloc(&n1, tmp.Type, nil)
-			gins(optoas(gc.OAS, tmp.Type), &tmp, &n1)
-		}
-
-		// &a is in &n3 (allocated in res)
-		// i is in &n1 (if not constant)
-		// w is width
-
-		// constant index
-		if gc.Isconst(nr, gc.CTINT) {
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Fatal("constant string constant index")
-			}
-			v := uint64(gc.Mpgetfix(nr.Val.U.Xval))
-			if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				if gc.Debug['B'] == 0 && !n.Bounded {
-					n1 = n3
-					n1.Op = gc.OINDREG
-					n1.Type = gc.Types[gc.Tptr]
-					n1.Xoffset = int64(gc.Array_nel)
-					var n4 gc.Node
-					regalloc(&n4, n1.Type, nil)
-					gmove(&n1, &n4)
-					ginscon2(optoas(gc.OCMP, gc.Types[gc.TUINT64]), &n4, int64(v))
-					regfree(&n4)
-					p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT64]), nil, +1)
-					ginscall(gc.Panicindex, 0)
-					gc.Patch(p1, gc.Pc)
-				}
-
-				n1 = n3
-				n1.Op = gc.OINDREG
-				n1.Type = gc.Types[gc.Tptr]
-				n1.Xoffset = int64(gc.Array_array)
-				gmove(&n1, &n3)
-			}
-
-			if v*uint64(w) != 0 {
-				ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), int64(v*uint64(w)), &n3)
-			}
-
-			*a = n3
-			break
-		}
-
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.TINT64], &n1) // i
-		gmove(&n1, &n2)
-		regfree(&n1)
-
-		var n4 gc.Node
-		if gc.Debug['B'] == 0 && !n.Bounded {
-			// check bounds
-			if gc.Isconst(nl, gc.CTSTR) {
-				gc.Nodconst(&n4, gc.Types[gc.TUINT64], int64(len(nl.Val.U.Sval)))
-			} else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-				n1 = n3
-				n1.Op = gc.OINDREG
-				n1.Type = gc.Types[gc.Tptr]
-				n1.Xoffset = int64(gc.Array_nel)
-				regalloc(&n4, gc.Types[gc.TUINT64], nil)
-				gmove(&n1, &n4)
-			} else {
-				if nl.Type.Bound < (1<<15)-1 {
-					gc.Nodconst(&n4, gc.Types[gc.TUINT64], nl.Type.Bound)
-				} else {
-					regalloc(&n4, gc.Types[gc.TUINT64], nil)
-					p1 := gins(ppc64.AMOVD, nil, &n4)
-					p1.From.Type = obj.TYPE_CONST
-					p1.From.Offset = nl.Type.Bound
-				}
-			}
-
-			gins(optoas(gc.OCMP, gc.Types[gc.TUINT64]), &n2, &n4)
-			if n4.Op == gc.OREGISTER {
-				regfree(&n4)
-			}
-			p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1)
-			if p2 != nil {
-				gc.Patch(p2, gc.Pc)
-			}
-			ginscall(gc.Panicindex, 0)
-			gc.Patch(p1, gc.Pc)
-		}
-
-		if gc.Isconst(nl, gc.CTSTR) {
-			regalloc(&n3, gc.Types[gc.Tptr], res)
-			p1 := gins(ppc64.AMOVD, nil, &n3)
-			gc.Datastring(nl.Val.U.Sval, &p1.From)
-			p1.From.Type = obj.TYPE_ADDR
-		} else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
-			n1 = n3
-			n1.Op = gc.OINDREG
-			n1.Type = gc.Types[gc.Tptr]
-			n1.Xoffset = int64(gc.Array_array)
-			gmove(&n1, &n3)
-		}
-
-		if w == 0 {
-		} else // nothing to do
-		if w == 1 {
-			/* w already scaled */
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			/* else if(w == 2 || w == 4 || w == 8) {
-				// TODO(minux): scale using shift
-			} */
-		} else {
-			regalloc(&n4, gc.Types[gc.TUINT64], nil)
-			gc.Nodconst(&n1, gc.Types[gc.TUINT64], int64(w))
-			gmove(&n1, &n4)
-			gins(optoas(gc.OMUL, gc.Types[gc.TUINT64]), &n4, &n2)
-			gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
-			regfree(&n4)
-		}
-
-		*a = n3
-		regfree(&n2)
-
-	default:
-		regalloc(a, gc.Types[gc.Tptr], res)
-		agen(n, a)
-	}
-}
-
-func ginsadd(as int, off int64, dst *gc.Node) {
-	var n1 gc.Node
-
-	regalloc(&n1, gc.Types[gc.Tptr], dst)
-	gmove(dst, &n1)
-	ginscon(as, off, &n1)
-	gmove(&n1, dst)
-	regfree(&n1)
-}
-
-/*
- * generate:
- *	res = &n;
- * The generated code checks that the result is not nil.
- */
-func agen(n *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nagen-res", res)
-		gc.Dump("agen-r", n)
-	}
-
-	if n == nil || n.Type == nil {
-		return
-	}
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-	}
-
-	if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) {
-		// Use of a nil interface or nil slice.
-		// Create a temporary we can take the address of and read.
-		// The generated code is just going to panic, so it need not
-		// be terribly efficient. See issue 3670.
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-
-		gc.Gvardef(&n1)
-		clearfat(&n1)
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.Tptr], res)
-		var n3 gc.Node
-		n3.Op = gc.OADDR
-		n3.Left = &n1
-		gins(ppc64.AMOVD, &n3, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		return
-	}
-
-	if n.Addable != 0 {
-		var n1 gc.Node
-		n1.Op = gc.OADDR
-		n1.Left = n
-		var n2 gc.Node
-		regalloc(&n2, gc.Types[gc.Tptr], res)
-		gins(ppc64.AMOVD, &n1, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		return
-	}
-
-	nl := n.Left
-
-	switch n.Op {
-	default:
-		gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign))
-
-		// TODO(minux): 5g has this: Release res so that it is available for cgen_call.
-	// Pick it up again after the call for OCALLMETH and OCALLFUNC.
-	case gc.OCALLMETH:
-		gc.Cgen_callmeth(n, 0)
-
-		cgen_aret(n, res)
-
-	case gc.OCALLINTER:
-		cgen_callinter(n, res, 0)
-		cgen_aret(n, res)
-
-	case gc.OCALLFUNC:
-		cgen_call(n, 0)
-		cgen_aret(n, res)
-
-	case gc.OSLICE,
-		gc.OSLICEARR,
-		gc.OSLICESTR,
-		gc.OSLICE3,
-		gc.OSLICE3ARR:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_slice(n, &n1)
-		agen(&n1, res)
-
-	case gc.OEFACE:
-		var n1 gc.Node
-		gc.Tempname(&n1, n.Type)
-		gc.Cgen_eface(n, &n1)
-		agen(&n1, res)
-
-	case gc.OINDEX:
-		var n1 gc.Node
-		agenr(n, &n1, res)
-		gmove(&n1, res)
-		regfree(&n1)
-
-		// should only get here with names in this func.
-	case gc.ONAME:
-		if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth)
-		}
-
-		// should only get here for heap vars or paramref
-		if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF {
-			gc.Dump("bad agen", n)
-			gc.Fatal("agen: bad ONAME class %#x", n.Class)
-		}
-
-		cgen(n.Heapaddr, res)
-		if n.Xoffset != 0 {
-			ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-
-	case gc.OIND:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-
-	case gc.ODOT:
-		agen(nl, res)
-		if n.Xoffset != 0 {
-			ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-
-	case gc.ODOTPTR:
-		cgen(nl, res)
-		gc.Cgen_checknil(res)
-		if n.Xoffset != 0 {
-			ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res)
-		}
-	}
-}
-
-/*
- * generate:
- *	newreg = &n;
- *	res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- * The generated code checks that the result is not *nil.
- */
-func igen(n *gc.Node, a *gc.Node, res *gc.Node) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nigen-n", n)
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF {
-			break
-		}
-		*a = *n
-		return
-
-		// Increase the refcount of the register so that igen's caller
-	// has to call regfree.
-	case gc.OINDREG:
-		if n.Val.U.Reg != ppc64.REGSP {
-			reg[n.Val.U.Reg]++
-		}
-		*a = *n
-		return
-
-	case gc.ODOT:
-		igen(n.Left, a, res)
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		fixlargeoffset(a)
-		return
-
-	case gc.ODOTPTR:
-		cgenr(n.Left, a, res)
-		gc.Cgen_checknil(a)
-		a.Op = gc.OINDREG
-		a.Xoffset += n.Xoffset
-		a.Type = n.Type
-		fixlargeoffset(a)
-		return
-
-	case gc.OCALLFUNC,
-		gc.OCALLMETH,
-		gc.OCALLINTER:
-		switch n.Op {
-		case gc.OCALLFUNC:
-			cgen_call(n, 0)
-
-		case gc.OCALLMETH:
-			gc.Cgen_callmeth(n, 0)
-
-		case gc.OCALLINTER:
-			cgen_callinter(n, nil, 0)
-		}
-
-		var flist gc.Iter
-		fp := gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type))
-		*a = gc.Node{}
-		a.Op = gc.OINDREG
-		a.Val.U.Reg = ppc64.REGSP
-		a.Addable = 1
-		a.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP)
-		a.Type = n.Type
-		return
-
-		// Index of fixed-size array by constant can
-	// put the offset in the addressing.
-	// Could do the same for slice except that we need
-	// to use the real index for the bounds checking.
-	case gc.OINDEX:
-		if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] && gc.Isfixedarray(n.Left.Left.Type)) {
-			if gc.Isconst(n.Right, gc.CTINT) {
-				// Compute &a.
-				if !gc.Isptr[n.Left.Type.Etype] {
-					igen(n.Left, a, res)
-				} else {
-					var n1 gc.Node
-					igen(n.Left, &n1, res)
-					gc.Cgen_checknil(&n1)
-					regalloc(a, gc.Types[gc.Tptr], res)
-					gmove(&n1, a)
-					regfree(&n1)
-					a.Op = gc.OINDREG
-				}
-
-				// Compute &a[i] as &a + i*width.
-				a.Type = n.Type
-
-				a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
-				fixlargeoffset(a)
-				return
-			}
-		}
-	}
-
-	agenr(n, a, res)
-	a.Op = gc.OINDREG
-	a.Type = n.Type
-}
-
-/*
- * generate:
- *	if(n == true) goto to;
- */
-func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) {
-	if gc.Debug['g'] != 0 {
-		gc.Dump("\nbgen", n)
-	}
-
-	if n == nil {
-		n = gc.Nodbool(true)
-	}
-
-	if n.Ninit != nil {
-		gc.Genlist(n.Ninit)
-	}
-
-	if n.Type == nil {
-		gc.Convlit(&n, gc.Types[gc.TBOOL])
-		if n.Type == nil {
-			return
-		}
-	}
-
-	et := int(n.Type.Etype)
-	if et != gc.TBOOL {
-		gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0))
-		gc.Patch(gins(obj.AEND, nil, nil), to)
-		return
-	}
-
-	var nr *gc.Node
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-		if n.Ninit != nil {
-			gc.Genlist(n.Ninit)
-		}
-	}
-
-	var nl *gc.Node
-	switch n.Op {
-	default:
-		var n1 gc.Node
-		regalloc(&n1, n.Type, nil)
-		cgen(n, &n1)
-		var n2 gc.Node
-		gc.Nodconst(&n2, n.Type, 0)
-		gins(optoas(gc.OCMP, n.Type), &n1, &n2)
-		a := ppc64.ABNE
-		if !true_ {
-			a = ppc64.ABEQ
-		}
-		gc.Patch(gc.Gbranch(a, n.Type, likely), to)
-		regfree(&n1)
-		return
-
-		// need to ask if it is bool?
-	case gc.OLITERAL:
-		if !true_ == (n.Val.U.Bval == 0) {
-			gc.Patch(gc.Gbranch(ppc64.ABR, nil, likely), to)
-		}
-		return
-
-	case gc.OANDAND,
-		gc.OOROR:
-		if (n.Op == gc.OANDAND) == true_ {
-			p1 := gc.Gbranch(obj.AJMP, nil, 0)
-			p2 := gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, gc.Pc)
-			bgen(n.Left, !true_, -likely, p2)
-			bgen(n.Right, !true_, -likely, p2)
-			p1 = gc.Gbranch(obj.AJMP, nil, 0)
-			gc.Patch(p1, to)
-			gc.Patch(p2, gc.Pc)
-		} else {
-			bgen(n.Left, true_, likely, to)
-			bgen(n.Right, true_, likely, to)
-		}
-
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			return
-		}
-		fallthrough
-
-	case gc.ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
-			return
-		}
-	}
-
-	switch n.Op {
-	case gc.ONOT:
-		bgen(nl, !true_, likely, to)
-		return
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		a := int(n.Op)
-		if !true_ {
-			if gc.Isfloat[nr.Type.Etype] {
-				// brcom is not valid on floats when NaN is involved.
-				p1 := gc.Gbranch(ppc64.ABR, nil, 0)
-
-				p2 := gc.Gbranch(ppc64.ABR, nil, 0)
-				gc.Patch(p1, gc.Pc)
-				ll := n.Ninit // avoid re-genning ninit
-				n.Ninit = nil
-				bgen(n, true, -likely, p2)
-				n.Ninit = ll
-				gc.Patch(gc.Gbranch(ppc64.ABR, nil, 0), to)
-				gc.Patch(p2, gc.Pc)
-				return
-			}
-
-			a = gc.Brcom(a)
-			true_ = !true_
-		}
-
-		// make simplest on right
-		if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) {
-			a = gc.Brrev(a)
-			r := nl
-			nl = nr
-			nr = r
-		}
-
-		if gc.Isslice(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal slice comparison")
-				break
-			}
-
-			a = optoas(a, gc.Types[gc.Tptr])
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Xoffset += int64(gc.Array_array)
-			n1.Type = gc.Types[gc.Tptr]
-			var tmp gc.Node
-			gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
-			var n2 gc.Node
-			regalloc(&n2, gc.Types[gc.Tptr], &n1)
-			gmove(&n1, &n2)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp)
-			regfree(&n2)
-			gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Isinter(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
-				gc.Yyerror("illegal interface comparison")
-				break
-			}
-
-			a = optoas(a, gc.Types[gc.Tptr])
-			var n1 gc.Node
-			igen(nl, &n1, nil)
-			n1.Type = gc.Types[gc.Tptr]
-			var tmp gc.Node
-			gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
-			var n2 gc.Node
-			regalloc(&n2, gc.Types[gc.Tptr], &n1)
-			gmove(&n1, &n2)
-			gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp)
-			regfree(&n2)
-			gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
-			regfree(&n1)
-			break
-		}
-
-		if gc.Iscomplex[nl.Type.Etype] {
-			gc.Complexbool(a, nl, nr, true_, likely, to)
-			break
-		}
-
-		var n1 gc.Node
-		var n2 gc.Node
-		if nr.Ullman >= gc.UINF {
-			regalloc(&n1, nl.Type, nil)
-			cgen(nl, &n1)
-
-			var tmp gc.Node
-			gc.Tempname(&tmp, nl.Type)
-			gmove(&n1, &tmp)
-			regfree(&n1)
-
-			regalloc(&n2, nr.Type, nil)
-			cgen(nr, &n2)
-
-			regalloc(&n1, nl.Type, nil)
-			cgen(&tmp, &n1)
-
-			goto cmp
-		}
-
-		regalloc(&n1, nl.Type, nil)
-		cgen(nl, &n1)
-
-		// TODO(minux): cmpi does accept 16-bit signed immediate as p->to.
-		// and cmpli accepts 16-bit unsigned immediate.
-		//if(smallintconst(nr)) {
-		//	gins(optoas(OCMP, nr->type), &n1, nr);
-		//	patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
-		//	regfree(&n1);
-		//	break;
-		//}
-
-		regalloc(&n2, nr.Type, nil)
-
-		cgen(nr, &n2)
-
-	cmp:
-		l := &n1
-		r := &n2
-		gins(optoas(gc.OCMP, nr.Type), l, r)
-		if gc.Isfloat[nr.Type.Etype] && (a == gc.OLE || a == gc.OGE) {
-			// To get NaN right, must rewrite x <= y into separate x < y or x = y.
-			switch a {
-			case gc.OLE:
-				a = gc.OLT
-
-			case gc.OGE:
-				a = gc.OGT
-			}
-
-			gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-			gc.Patch(gc.Gbranch(optoas(gc.OEQ, nr.Type), nr.Type, likely), to)
-		} else {
-			gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-		}
-
-		regfree(&n1)
-		regfree(&n2)
-	}
-
-	return
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-func stkof(n *gc.Node) int64 {
-	switch n.Op {
-	case gc.OINDREG:
-		return n.Xoffset
-
-	case gc.ODOT:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		return off + n.Xoffset
-
-	case gc.OINDEX:
-		t := n.Left.Type
-		if !gc.Isfixedarray(t) {
-			break
-		}
-		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
-			return off
-		}
-		if gc.Isconst(n.Right, gc.CTINT) {
-			return off + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval)
-		}
-		return 1000
-
-	case gc.OCALLMETH,
-		gc.OCALLINTER,
-		gc.OCALLFUNC:
-		t := n.Left.Type
-		if gc.Isptr[t.Etype] {
-			t = t.Type
-		}
-
-		var flist gc.Iter
-		t = gc.Structfirst(&flist, gc.Getoutarg(t))
-		if t != nil {
-			return t.Width + int64(gc.Widthptr) // +widthptr: correct for saved LR
-		}
-	}
-
-	// botch - probably failing to recognize address
-	// arithmetic on the above. eg INDEX and DOT
-	return -1000
-}
-
-/*
- * block copy:
- *	memmove(&ns, &n, w);
- */
-func sgen(n *gc.Node, ns *gc.Node, w int64) {
-	var res *gc.Node = ns
-
-	if gc.Debug['g'] != 0 {
-		fmt.Printf("\nsgen w=%d\n", w)
-		gc.Dump("r", n)
-		gc.Dump("res", ns)
-	}
-
-	if n.Ullman >= gc.UINF && ns.Ullman >= gc.UINF {
-		gc.Fatal("sgen UINF")
-	}
-
-	if w < 0 {
-		gc.Fatal("sgen copy %d", w)
-	}
-
-	// If copying .args, that's all the results, so record definition sites
-	// for them for the liveness analysis.
-	if ns.Op == gc.ONAME && ns.Sym.Name == ".args" {
-		for l := gc.Curfn.Dcl; l != nil; l = l.Next {
-			if l.N.Class == gc.PPARAMOUT {
-				gc.Gvardef(l.N)
-			}
-		}
-	}
-
-	// Avoid taking the address for simple enough types.
-	if gc.Componentgen(n, ns) {
-		return
-	}
-
-	if w == 0 {
-		// evaluate side effects only.
-		var dst gc.Node
-		regalloc(&dst, gc.Types[gc.Tptr], nil)
-
-		agen(res, &dst)
-		agen(n, &dst)
-		regfree(&dst)
-		return
-	}
-
+func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// determine alignment.
 	// want to avoid unaligned access, so have to use
 	// smaller operations for less aligned types.
@@ -1489,27 +40,6 @@
 	}
 	c := int32(w / int64(align))
 
-	// offset on the stack
-	osrc := int32(stkof(n))
-
-	odst := int32(stkof(res))
-	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
-		// osrc and odst both on stack, and at least one is in
-		// an unknown position.  Could generate code to test
-		// for forward/backward copy, but instead just copy
-		// to a temporary location first.
-		var tmp gc.Node
-		gc.Tempname(&tmp, n.Type)
-
-		sgen(n, &tmp, w)
-		sgen(&tmp, res, w)
-		return
-	}
-
-	if osrc%int32(align) != 0 || odst%int32(align) != 0 {
-		gc.Fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align)
-	}
-
 	// if we are copying forward on the stack and
 	// the src and dst overlap, then reverse direction
 	dir := align
@@ -1521,23 +51,23 @@
 	var dst gc.Node
 	var src gc.Node
 	if n.Ullman >= res.Ullman {
-		agenr(n, &dst, res) // temporarily use dst
-		regalloc(&src, gc.Types[gc.Tptr], nil)
+		gc.Agenr(n, &dst, res) // temporarily use dst
+		gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
 		gins(ppc64.AMOVD, &dst, &src)
 		if res.Op == gc.ONAME {
 			gc.Gvardef(res)
 		}
-		agen(res, &dst)
+		gc.Agen(res, &dst)
 	} else {
 		if res.Op == gc.ONAME {
 			gc.Gvardef(res)
 		}
-		agenr(res, &dst, res)
-		agenr(n, &src, nil)
+		gc.Agenr(res, &dst, res)
+		gc.Agenr(n, &src, nil)
 	}
 
 	var tmp gc.Node
-	regalloc(&tmp, gc.Types[gc.Tptr], nil)
+	gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
 
 	// set up end marker
 	var nend gc.Node
@@ -1545,7 +75,7 @@
 	// move src and dest to the end of block if necessary
 	if dir < 0 {
 		if c >= 4 {
-			regalloc(&nend, gc.Types[gc.Tptr], nil)
+			gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
 			gins(ppc64.AMOVD, &src, &nend)
 		}
 
@@ -1566,7 +96,7 @@
 		p.From.Offset = int64(-dir)
 
 		if c >= 4 {
-			regalloc(&nend, gc.Types[gc.Tptr], nil)
+			gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
 			p := gins(ppc64.AMOVD, &src, &nend)
 			p.From.Type = obj.TYPE_ADDR
 			p.From.Offset = w
@@ -1588,7 +118,7 @@
 		p = gins(ppc64.ACMP, &src, &nend)
 
 		gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), ploop)
-		regfree(&nend)
+		gc.Regfree(&nend)
 	} else {
 		// TODO(austin): Instead of generating ADD $-8,R8; ADD
 		// $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just
@@ -1613,7 +143,7 @@
 		}
 	}
 
-	regfree(&dst)
-	regfree(&src)
-	regfree(&tmp)
+	gc.Regfree(&dst)
+	gc.Regfree(&src)
+	gc.Regfree(&tmp)
 }
diff --git a/src/cmd/9g/galign.go b/src/cmd/9g/galign.go
index 69e6bac..b9e6c32 100644
--- a/src/cmd/9g/galign.go
+++ b/src/cmd/9g/galign.go
@@ -53,33 +53,38 @@
 	gc.Thearch.Typedefs = typedefs
 	gc.Thearch.REGSP = ppc64.REGSP
 	gc.Thearch.REGCTXT = ppc64.REGCTXT
+	gc.Thearch.REGCALLX = ppc64.REG_R3
+	gc.Thearch.REGCALLX2 = ppc64.REG_R4
+	gc.Thearch.REGRETURN = ppc64.REG_R3
+	gc.Thearch.REGMIN = ppc64.REG_R0
+	gc.Thearch.REGMAX = ppc64.REG_R31
+	gc.Thearch.FREGMIN = ppc64.REG_F0
+	gc.Thearch.FREGMAX = ppc64.REG_F31
 	gc.Thearch.MAXWIDTH = MAXWIDTH
-	gc.Thearch.Anyregalloc = anyregalloc
+	gc.Thearch.ReservedRegs = resvd
+
 	gc.Thearch.Betypeinit = betypeinit
-	gc.Thearch.Bgen = bgen
-	gc.Thearch.Cgen = cgen
-	gc.Thearch.Cgen_call = cgen_call
-	gc.Thearch.Cgen_callinter = cgen_callinter
-	gc.Thearch.Cgen_ret = cgen_ret
+	gc.Thearch.Cgen_hmul = cgen_hmul
+	gc.Thearch.Cgen_shift = cgen_shift
 	gc.Thearch.Clearfat = clearfat
 	gc.Thearch.Defframe = defframe
+	gc.Thearch.Dodiv = dodiv
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
-	gc.Thearch.Gclean = gclean
-	gc.Thearch.Ginit = ginit
 	gc.Thearch.Gins = gins
-	gc.Thearch.Ginscall = ginscall
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
-	gc.Thearch.Igen = igen
 	gc.Thearch.Linkarchinit = linkarchinit
 	gc.Thearch.Peep = peep
 	gc.Thearch.Proginfo = proginfo
-	gc.Thearch.Regalloc = regalloc
-	gc.Thearch.Regfree = regfree
 	gc.Thearch.Regtyp = regtyp
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
+	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Sudoaddable = sudoaddable
+	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
 	gc.Thearch.RtoB = RtoB
 	gc.Thearch.FtoB = RtoB
diff --git a/src/cmd/9g/gg.go b/src/cmd/9g/gg.go
deleted file mode 100644
index 068d8af..0000000
--- a/src/cmd/9g/gg.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import "cmd/internal/obj/ppc64"
-import "cmd/internal/gc"
-
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-var reg [ppc64.NREG + ppc64.NFREG]uint8
-
-var panicdiv *gc.Node
-
-/*
- * cgen.c
- */
-
-/*
- * list.c
- */
-
-/*
- * reg.c
- */
diff --git a/src/cmd/9g/ggen.go b/src/cmd/9g/ggen.go
index dfc54a7..0a788f8 100644
--- a/src/cmd/9g/ggen.go
+++ b/src/cmd/9g/ggen.go
@@ -112,333 +112,13 @@
 	return q
 }
 
-/*
- * generate: BL reg, f
- * where both reg and f are registers.
- * On power, f must be moved to CTR first.
- */
-func ginsBL(reg *gc.Node, f *gc.Node) {
-	p := gins(ppc64.AMOVD, f, nil)
-	p.To.Type = obj.TYPE_REG
-	p.To.Reg = ppc64.REG_CTR
-	p = gins(ppc64.ABL, reg, nil)
-	p.To.Type = obj.TYPE_REG
-	p.To.Reg = ppc64.REG_CTR
+func ginsnop() {
+	var reg gc.Node
+	gc.Nodreg(&reg, gc.Types[gc.TINT], ppc64.REG_R0)
+	gins(ppc64.AOR, &reg, &reg)
 }
 
-/*
- * generate:
- *	call f
- *	proc=-1	normal call but no return
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
-  *	proc=3	normal call to C pointer (not Go func value)
-*/
-func ginscall(f *gc.Node, proc int) {
-	if f.Type != nil {
-		extra := int32(0)
-		if proc == 1 || proc == 2 {
-			extra = 2 * int32(gc.Widthptr)
-		}
-		gc.Setmaxarg(f.Type, extra)
-	}
-
-	switch proc {
-	default:
-		gc.Fatal("ginscall: bad proc %d", proc)
-
-	case 0, // normal call
-		-1: // normal call but no return
-		if f.Op == gc.ONAME && f.Class == gc.PFUNC {
-			if f == gc.Deferreturn {
-				// Deferred calls will appear to be returning to
-				// the CALL deferreturn(SB) that we are about to emit.
-				// However, the stack trace code will show the line
-				// of the instruction byte before the return PC.
-				// To avoid that being an unrelated instruction,
-				// insert a ppc64 NOP that we will have the right line number.
-				// The ppc64 NOP is really or r0, r0, r0; use that description
-				// because the NOP pseudo-instruction would be removed by
-				// the linker.
-				var reg gc.Node
-				gc.Nodreg(&reg, gc.Types[gc.TINT], ppc64.REG_R0)
-
-				gins(ppc64.AOR, &reg, &reg)
-			}
-
-			p := gins(ppc64.ABL, nil, f)
-			gc.Afunclit(&p.To, f)
-			if proc == -1 || gc.Noreturn(p) {
-				gins(obj.AUNDEF, nil, nil)
-			}
-			break
-		}
-
-		var reg gc.Node
-		gc.Nodreg(&reg, gc.Types[gc.Tptr], ppc64.REGCTXT)
-		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[gc.Tptr], ppc64.REG_R3)
-		gmove(f, &reg)
-		reg.Op = gc.OINDREG
-		gmove(&reg, &r1)
-		reg.Op = gc.OREGISTER
-		ginsBL(&reg, &r1)
-
-	case 3: // normal call of c function pointer
-		ginsBL(nil, f)
-
-	case 1, // call in new proc (go)
-		2: // deferred call (defer)
-		var con gc.Node
-		gc.Nodconst(&con, gc.Types[gc.TINT64], int64(gc.Argsize(f.Type)))
-
-		var reg gc.Node
-		gc.Nodreg(&reg, gc.Types[gc.TINT64], ppc64.REG_R3)
-		var reg2 gc.Node
-		gc.Nodreg(&reg2, gc.Types[gc.TINT64], ppc64.REG_R4)
-		gmove(f, &reg)
-
-		gmove(&con, &reg2)
-		p := gins(ppc64.AMOVW, &reg2, nil)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = ppc64.REGSP
-		p.To.Offset = 8
-
-		p = gins(ppc64.AMOVD, &reg, nil)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = ppc64.REGSP
-		p.To.Offset = 16
-
-		if proc == 1 {
-			ginscall(gc.Newproc, 0)
-		} else {
-			if gc.Hasdefer == 0 {
-				gc.Fatal("hasdefer=0 but has defer")
-			}
-			ginscall(gc.Deferproc, 0)
-		}
-
-		if proc == 2 {
-			gc.Nodreg(&reg, gc.Types[gc.TINT64], ppc64.REG_R3)
-			p := gins(ppc64.ACMP, &reg, nil)
-			p.To.Type = obj.TYPE_REG
-			p.To.Reg = ppc64.REGZERO
-			p = gc.Gbranch(ppc64.ABEQ, nil, +1)
-			cgen_ret(nil)
-			gc.Patch(p, gc.Pc)
-		}
-	}
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-func cgen_callinter(n *gc.Node, res *gc.Node, proc int) {
-	i := n.Left
-	if i.Op != gc.ODOTINTER {
-		gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0))
-	}
-
-	f := i.Right // field
-	if f.Op != gc.ONAME {
-		gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0))
-	}
-
-	i = i.Left // interface
-
-	if i.Addable == 0 {
-		var tmpi gc.Node
-		gc.Tempname(&tmpi, i.Type)
-		cgen(i, &tmpi)
-		i = &tmpi
-	}
-
-	gc.Genlist(n.List) // assign the args
-
-	// i is now addable, prepare an indirected
-	// register to hold its address.
-	var nodi gc.Node
-	igen(i, &nodi, res) // REG = &inter
-
-	var nodsp gc.Node
-	gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], ppc64.REGSP)
-
-	nodsp.Xoffset = int64(gc.Widthptr)
-	if proc != 0 {
-		nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn
-	}
-	nodi.Type = gc.Types[gc.Tptr]
-	nodi.Xoffset += int64(gc.Widthptr)
-	cgen(&nodi, &nodsp) // {8 or 24}(SP) = 8(REG) -- i.data
-
-	var nodo gc.Node
-	regalloc(&nodo, gc.Types[gc.Tptr], res)
-
-	nodi.Type = gc.Types[gc.Tptr]
-	nodi.Xoffset -= int64(gc.Widthptr)
-	cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
-	regfree(&nodi)
-
-	var nodr gc.Node
-	regalloc(&nodr, gc.Types[gc.Tptr], &nodo)
-	if n.Left.Xoffset == gc.BADWIDTH {
-		gc.Fatal("cgen_callinter: badwidth")
-	}
-	gc.Cgen_checknil(&nodo) // in case offset is huge
-	nodo.Op = gc.OINDREG
-	nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8
-	if proc == 0 {
-		// plain call: use direct c function pointer - more efficient
-		cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
-		proc = 3
-	} else {
-		// go/defer. generate go func value.
-		p := gins(ppc64.AMOVD, &nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
-		p.From.Type = obj.TYPE_ADDR
-	}
-
-	nodr.Type = n.Left.Type
-	ginscall(&nodr, proc)
-
-	regfree(&nodr)
-	regfree(&nodo)
-}
-
-/*
- * generate function call;
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
- */
-func cgen_call(n *gc.Node, proc int) {
-	if n == nil {
-		return
-	}
-
-	var afun gc.Node
-	if n.Left.Ullman >= gc.UINF {
-		// if name involves a fn call
-		// precompute the address of the fn
-		gc.Tempname(&afun, gc.Types[gc.Tptr])
-
-		cgen(n.Left, &afun)
-	}
-
-	gc.Genlist(n.List) // assign the args
-	t := n.Left.Type
-
-	// call tempname pointer
-	if n.Left.Ullman >= gc.UINF {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, &afun)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call pointer
-	if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC {
-		var nod gc.Node
-		regalloc(&nod, gc.Types[gc.Tptr], nil)
-		gc.Cgen_as(&nod, n.Left)
-		nod.Type = t
-		ginscall(&nod, proc)
-		regfree(&nod)
-		return
-	}
-
-	// call direct
-	n.Left.Method = 1
-
-	ginscall(n.Left, proc)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = return value from call.
- */
-func cgen_callret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_callret: nil")
-	}
-
-	var nod gc.Node
-	nod.Op = gc.OINDREG
-	nod.Val.U.Reg = ppc64.REGSP
-	nod.Addable = 1
-
-	nod.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved LR at 0(R1)
-	nod.Type = fp.Type
-	gc.Cgen_as(res, &nod)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = &return value from call.
- */
-func cgen_aret(n *gc.Node, res *gc.Node) {
-	t := n.Left.Type
-	if gc.Isptr[t.Etype] {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	var nod1 gc.Node
-	nod1.Op = gc.OINDREG
-	nod1.Val.U.Reg = ppc64.REGSP
-	nod1.Addable = 1
-
-	nod1.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP)
-	nod1.Type = fp.Type
-
-	if res.Op != gc.OREGISTER {
-		var nod2 gc.Node
-		regalloc(&nod2, gc.Types[gc.Tptr], res)
-		agen(&nod1, &nod2)
-		gins(ppc64.AMOVD, &nod2, res)
-		regfree(&nod2)
-	} else {
-		agen(&nod1, res)
-	}
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-func cgen_ret(n *gc.Node) {
-	if n != nil {
-		gc.Genlist(n.List) // copy out args
-	}
-	if gc.Hasdefer != 0 {
-		ginscall(gc.Deferreturn, 0)
-	}
-	gc.Genlist(gc.Curfn.Exit)
-	p := gins(obj.ARET, nil, nil)
-	if n != nil && n.Op == gc.ORETJMP {
-		p.To.Name = obj.NAME_EXTERN
-		p.To.Type = obj.TYPE_ADDR
-		p.To.Sym = gc.Linksym(n.Left.Sym)
-	}
-}
+var panicdiv *gc.Node
 
 /*
  * generate division.
@@ -480,15 +160,15 @@
 	a := optoas(gc.ODIV, t)
 
 	var tl gc.Node
-	regalloc(&tl, t0, nil)
+	gc.Regalloc(&tl, t0, nil)
 	var tr gc.Node
-	regalloc(&tr, t0, nil)
+	gc.Regalloc(&tr, t0, nil)
 	if nl.Ullman >= nr.Ullman {
-		cgen(nl, &tl)
-		cgen(nr, &tr)
+		gc.Cgen(nl, &tl)
+		gc.Cgen(nr, &tr)
 	} else {
-		cgen(nr, &tr)
-		cgen(nl, &tl)
+		gc.Cgen(nr, &tr)
+		gc.Cgen(nl, &tl)
 	}
 
 	if t != t0 {
@@ -511,7 +191,7 @@
 	if panicdiv == nil {
 		panicdiv = gc.Sysfunc("panicdivide")
 	}
-	ginscall(panicdiv, -1)
+	gc.Ginscall(panicdiv, -1)
 	gc.Patch(p1, gc.Pc)
 
 	var p2 *obj.Prog
@@ -539,12 +219,12 @@
 
 	p1 = gins(a, &tr, &tl)
 	if op == gc.ODIV {
-		regfree(&tr)
+		gc.Regfree(&tr)
 		gmove(&tl, res)
 	} else {
 		// A%B = A-(A/B*B)
 		var tm gc.Node
-		regalloc(&tm, t, nil)
+		gc.Regalloc(&tm, t, nil)
 
 		// patch div to use the 3 register form
 		// TODO(minux): add gins3?
@@ -552,33 +232,19 @@
 
 		p1.To.Reg = tm.Val.U.Reg
 		gins(optoas(gc.OMUL, t), &tr, &tm)
-		regfree(&tr)
+		gc.Regfree(&tr)
 		gins(optoas(gc.OSUB, t), &tm, &tl)
-		regfree(&tm)
+		gc.Regfree(&tm)
 		gmove(&tl, res)
 	}
 
-	regfree(&tl)
+	gc.Regfree(&tl)
 	if check != 0 {
 		gc.Patch(p2, gc.Pc)
 	}
 }
 
 /*
- * generate division according to op, one of:
- *	res = nl / nr
- *	res = nl % nr
- */
-func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
-	// TODO(minux): enable division by magic multiply (also need to fix longmod below)
-	//if(nr->op != OLITERAL)
-	// division and mod using (slow) hardware instruction
-	dodiv(op, nl, nr, res)
-
-	return
-}
-
-/*
  * generate high multiply:
  *   res = (nl*nr) >> width
  */
@@ -593,9 +259,9 @@
 	t := (*gc.Type)(nl.Type)
 	w := int(int(t.Width * 8))
 	var n1 gc.Node
-	cgenr(nl, &n1, res)
+	gc.Cgenr(nl, &n1, res)
 	var n2 gc.Node
-	cgenr(nr, &n2, nil)
+	gc.Cgenr(nr, &n2, nil)
 	switch gc.Simtype[t.Etype] {
 	case gc.TINT8,
 		gc.TINT16,
@@ -625,9 +291,9 @@
 		gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
 	}
 
-	cgen(&n1, res)
-	regfree(&n1)
-	regfree(&n2)
+	gc.Cgen(&n1, res)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 /*
@@ -640,8 +306,8 @@
 
 	if nr.Op == gc.OLITERAL {
 		var n1 gc.Node
-		regalloc(&n1, nl.Type, res)
-		cgen(nl, &n1)
+		gc.Regalloc(&n1, nl.Type, res)
+		gc.Cgen(nl, &n1)
 		sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval)))
 		if sc >= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
@@ -654,21 +320,21 @@
 			gins(a, nr, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
 	if nl.Ullman >= gc.UINF {
 		var n4 gc.Node
 		gc.Tempname(&n4, nl.Type)
-		cgen(nl, &n4)
+		gc.Cgen(nl, &n4)
 		nl = &n4
 	}
 
 	if nr.Ullman >= gc.UINF {
 		var n5 gc.Node
 		gc.Tempname(&n5, nr.Type)
-		cgen(nr, &n5)
+		gc.Cgen(nr, &n5)
 		nr = &n5
 	}
 
@@ -682,24 +348,24 @@
 	}
 
 	var n1 gc.Node
-	regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
+	gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
 	var n3 gc.Node
-	regalloc(&n3, tcount, &n1) // to clear high bits of CX
+	gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
 
 	var n2 gc.Node
-	regalloc(&n2, nl.Type, res)
+	gc.Regalloc(&n2, nl.Type, res)
 
 	if nl.Ullman >= nr.Ullman {
-		cgen(nl, &n2)
-		cgen(nr, &n1)
+		gc.Cgen(nl, &n2)
+		gc.Cgen(nr, &n1)
 		gmove(&n1, &n3)
 	} else {
-		cgen(nr, &n1)
+		gc.Cgen(nr, &n1)
 		gmove(&n1, &n3)
-		cgen(nl, &n2)
+		gc.Cgen(nl, &n2)
 	}
 
-	regfree(&n3)
+	gc.Regfree(&n3)
 
 	// test and fix up large shifts
 	if !bounded {
@@ -721,8 +387,8 @@
 
 	gmove(&n2, res)
 
-	regfree(&n1)
-	regfree(&n2)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 func clearfat(nl *gc.Node) {
@@ -741,16 +407,16 @@
 	c := uint64(w % 8) // bytes
 	q := uint64(w / 8) // dwords
 
-	if reg[ppc64.REGRT1-ppc64.REG_R0] > 0 {
-		gc.Fatal("R%d in use during clearfat", ppc64.REGRT1-ppc64.REG_R0)
+	if gc.Reginuse(ppc64.REGRT1) {
+		gc.Fatal("%v in use during clearfat", obj.Rconv(ppc64.REGRT1))
 	}
 
 	var r0 gc.Node
 	gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REGZERO)
 	var dst gc.Node
 	gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1)
-	reg[ppc64.REGRT1-ppc64.REG_R0]++
-	agen(nl, &dst)
+	gc.Regrealloc(&dst)
+	gc.Agen(nl, &dst)
 
 	var boff uint64
 	if q > 128 {
@@ -759,7 +425,7 @@
 		p.From.Offset = 8
 
 		var end gc.Node
-		regalloc(&end, gc.Types[gc.Tptr], nil)
+		gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
 		p = gins(ppc64.AMOVD, &dst, &end)
 		p.From.Type = obj.TYPE_ADDR
 		p.From.Offset = int64(q * 8)
@@ -772,7 +438,7 @@
 		p = gins(ppc64.ACMP, &dst, &end)
 		gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl)
 
-		regfree(&end)
+		gc.Regfree(&end)
 
 		// The loop leaves R3 on the last zeroed dword
 		boff = 8
@@ -807,7 +473,7 @@
 		p.To.Offset = int64(t + boff)
 	}
 
-	reg[ppc64.REGRT1-ppc64.REG_R0]--
+	gc.Regfree(&dst)
 }
 
 // Called after regopt and peep have run.
diff --git a/src/cmd/9g/gsubr.go b/src/cmd/9g/gsubr.go
index 0c5bcf2..5a6fd29 100644
--- a/src/cmd/9g/gsubr.go
+++ b/src/cmd/9g/gsubr.go
@@ -62,171 +62,6 @@
 	ppc64.FREGTWO,
 }
 
-func ginit() {
-	for i := 0; i < len(reg); i++ {
-		reg[i] = 1
-	}
-	for i := 0; i < ppc64.NREG+ppc64.NFREG; i++ {
-		reg[i] = 0
-	}
-
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]-ppc64.REG_R0]++
-	}
-}
-
-var regpc [len(reg)]uint32
-
-func gclean() {
-	for i := int(0); i < len(resvd); i++ {
-		reg[resvd[i]-ppc64.REG_R0]--
-	}
-
-	for i := int(0); i < len(reg); i++ {
-		if reg[i] != 0 {
-			gc.Yyerror("reg %v left allocated, %p\n", obj.Rconv(i+ppc64.REG_R0), regpc[i])
-		}
-	}
-}
-
-func anyregalloc() bool {
-	var j int
-
-	for i := int(0); i < len(reg); i++ {
-		if reg[i] == 0 {
-			goto ok
-		}
-		for j = 0; j < len(resvd); j++ {
-			if resvd[j] == i {
-				goto ok
-			}
-		}
-		return true
-	ok:
-	}
-
-	return false
-}
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) {
-	if t == nil {
-		gc.Fatal("regalloc: t nil")
-	}
-	et := int(int(gc.Simtype[t.Etype]))
-
-	if gc.Debug['r'] != 0 {
-		fixfree := int(0)
-		fltfree := int(0)
-		for i := int(ppc64.REG_R0); i < ppc64.REG_F31; i++ {
-			if reg[i-ppc64.REG_R0] == 0 {
-				if i < ppc64.REG_F0 {
-					fixfree++
-				} else {
-					fltfree++
-				}
-			}
-		}
-
-		fmt.Printf("regalloc fix %d flt %d free\n", fixfree, fltfree)
-	}
-
-	var i int
-	switch et {
-	case gc.TINT8,
-		gc.TUINT8,
-		gc.TINT16,
-		gc.TUINT16,
-		gc.TINT32,
-		gc.TUINT32,
-		gc.TINT64,
-		gc.TUINT64,
-		gc.TPTR32,
-		gc.TPTR64,
-		gc.TBOOL:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= ppc64.REGMIN && i <= ppc64.REGMAX {
-				goto out
-			}
-		}
-
-		for i = ppc64.REGMIN; i <= ppc64.REGMAX; i++ {
-			if reg[i-ppc64.REG_R0] == 0 {
-				regpc[i-ppc64.REG_R0] = uint32(obj.Getcallerpc(&n))
-				goto out
-			}
-		}
-
-		gc.Flusherrors()
-		for i := int(ppc64.REG_R0); i < ppc64.REG_R0+ppc64.NREG; i++ {
-			fmt.Printf("R%d %p\n", i, regpc[i-ppc64.REG_R0])
-		}
-		gc.Fatal("out of fixed registers")
-
-	case gc.TFLOAT32,
-		gc.TFLOAT64:
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= ppc64.FREGMIN && i <= ppc64.FREGMAX {
-				goto out
-			}
-		}
-
-		for i = ppc64.FREGMIN; i <= ppc64.FREGMAX; i++ {
-			if reg[i-ppc64.REG_R0] == 0 {
-				regpc[i-ppc64.REG_R0] = uint32(obj.Getcallerpc(&n))
-				goto out
-			}
-		}
-
-		gc.Flusherrors()
-		for i := int(ppc64.REG_F0); i < ppc64.REG_F0+ppc64.NREG; i++ {
-			fmt.Printf("F%d %p\n", i, regpc[i-ppc64.REG_R0])
-		}
-		gc.Fatal("out of floating registers")
-
-	case gc.TCOMPLEX64,
-		gc.TCOMPLEX128:
-		gc.Tempname(n, t)
-		return
-	}
-
-	gc.Fatal("regalloc: unknown type %v", gc.Tconv(t, 0))
-	return
-
-out:
-	reg[i-ppc64.REG_R0]++
-	gc.Nodreg(n, t, i)
-}
-
-func regfree(n *gc.Node) {
-	if n.Op == gc.ONAME {
-		return
-	}
-	if n.Op != gc.OREGISTER && n.Op != gc.OINDREG {
-		gc.Fatal("regfree: not a register")
-	}
-	i := int(int(n.Val.U.Reg) - ppc64.REG_R0)
-	if i == ppc64.REGSP-ppc64.REG_R0 {
-		return
-	}
-	if i < 0 || i >= len(reg) {
-		gc.Fatal("regfree: reg out of range")
-	}
-	if reg[i] <= 0 {
-		gc.Fatal("regfree: reg not allocated")
-	}
-	reg[i]--
-	if reg[i] == 0 {
-		regpc[i] = 0
-	}
-}
-
 /*
  * generate
  *	as $c, n
@@ -236,19 +71,19 @@
 
 	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
 
-	if as != ppc64.AMOVD && (c < -ppc64.BIG || c > ppc64.BIG) {
+	if as != ppc64.AMOVD && (c < -ppc64.BIG || c > ppc64.BIG) || n2.Op != gc.OREGISTER || as == ppc64.AMULLD {
 		// cannot have more than 16-bit of immediate in ADD, etc.
 		// instead, MOV into register first.
 		var ntmp gc.Node
-		regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+		gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
 
-		gins(ppc64.AMOVD, &n1, &ntmp)
-		gins(as, &ntmp, n2)
-		regfree(&ntmp)
+		rawgins(ppc64.AMOVD, &n1, &ntmp)
+		rawgins(as, &ntmp, n2)
+		gc.Regfree(&ntmp)
 		return
 	}
 
-	gins(as, &n1, n2)
+	rawgins(as, &n1, n2)
 }
 
 /*
@@ -266,24 +101,24 @@
 
 	case ppc64.ACMP:
 		if -ppc64.BIG <= c && c <= ppc64.BIG {
-			gins(as, n2, &n1)
+			rawgins(as, n2, &n1)
 			return
 		}
 
 	case ppc64.ACMPU:
 		if 0 <= c && c <= 2*ppc64.BIG {
-			gins(as, n2, &n1)
+			rawgins(as, n2, &n1)
 			return
 		}
 	}
 
 	// MOV n1 into register first
 	var ntmp gc.Node
-	regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+	gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
 
-	gins(ppc64.AMOVD, &n1, &ntmp)
-	gins(as, n2, &ntmp)
-	regfree(&ntmp)
+	rawgins(ppc64.AMOVD, &n1, &ntmp)
+	rawgins(as, n2, &ntmp)
+	gc.Regfree(&ntmp)
 }
 
 /*
@@ -351,10 +186,10 @@
 			var con gc.Node
 			gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val)
 			var r1 gc.Node
-			regalloc(&r1, con.Type, t)
+			gc.Regalloc(&r1, con.Type, t)
 			gins(ppc64.AMOVD, &con, &r1)
 			gmove(&r1, t)
-			regfree(&r1)
+			gc.Regfree(&r1)
 			return
 
 		case gc.TUINT32,
@@ -363,10 +198,10 @@
 			var con gc.Node
 			gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val)
 			var r1 gc.Node
-			regalloc(&r1, con.Type, t)
+			gc.Regalloc(&r1, con.Type, t)
 			gins(ppc64.AMOVD, &con, &r1)
 			gmove(&r1, t)
-			regfree(&r1)
+			gc.Regfree(&r1)
 			return
 		}
 
@@ -546,21 +381,21 @@
 		bignodes()
 
 		var r1 gc.Node
-		regalloc(&r1, gc.Types[ft], f)
+		gc.Regalloc(&r1, gc.Types[ft], f)
 		gmove(f, &r1)
 		if tt == gc.TUINT64 {
-			regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
+			gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
 			gmove(&bigf, &r2)
 			gins(ppc64.AFCMPU, &r1, &r2)
 			p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1))
 			gins(ppc64.AFSUB, &r2, &r1)
 			gc.Patch(p1, gc.Pc)
-			regfree(&r2)
+			gc.Regfree(&r2)
 		}
 
-		regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
+		gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
 		var r3 gc.Node
-		regalloc(&r3, gc.Types[gc.TINT64], t)
+		gc.Regalloc(&r3, gc.Types[gc.TINT64], t)
 		gins(ppc64.AFCTIDZ, &r1, &r2)
 		p1 := (*obj.Prog)(gins(ppc64.AFMOVD, &r2, nil))
 		p1.To.Type = obj.TYPE_MEM
@@ -570,8 +405,8 @@
 		p1.From.Type = obj.TYPE_MEM
 		p1.From.Reg = ppc64.REGSP
 		p1.From.Offset = -8
-		regfree(&r2)
-		regfree(&r1)
+		gc.Regfree(&r2)
+		gc.Regfree(&r1)
 		if tt == gc.TUINT64 {
 			p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1)) // use CR0 here again
 			gc.Nodreg(&r1, gc.Types[gc.TINT64], ppc64.REGTMP)
@@ -581,7 +416,7 @@
 		}
 
 		gmove(&r3, t)
-		regfree(&r3)
+		gc.Regfree(&r3)
 		return
 
 		//warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
@@ -611,7 +446,7 @@
 		bignodes()
 
 		var r1 gc.Node
-		regalloc(&r1, gc.Types[gc.TINT64], nil)
+		gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
 		gmove(f, &r1)
 		if ft == gc.TUINT64 {
 			gc.Nodreg(&r2, gc.Types[gc.TUINT64], ppc64.REGTMP)
@@ -624,7 +459,7 @@
 			gc.Patch(p1, gc.Pc)
 		}
 
-		regalloc(&r2, gc.Types[gc.TFLOAT64], t)
+		gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
 		p1 := (*obj.Prog)(gins(ppc64.AMOVD, &r1, nil))
 		p1.To.Type = obj.TYPE_MEM
 		p1.To.Reg = ppc64.REGSP
@@ -634,7 +469,7 @@
 		p1.From.Reg = ppc64.REGSP
 		p1.From.Offset = -8
 		gins(ppc64.AFCFID, &r2, &r2)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		if ft == gc.TUINT64 {
 			p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1)) // use CR0 here again
 			gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], ppc64.FREGTWO)
@@ -643,7 +478,7 @@
 		}
 
 		gmove(&r2, t)
-		regfree(&r2)
+		gc.Regfree(&r2)
 		return
 
 		/*
@@ -670,29 +505,61 @@
 	// requires register destination
 rdst:
 	{
-		regalloc(&r1, t.Type, t)
+		gc.Regalloc(&r1, t.Type, t)
 
 		gins(a, f, &r1)
 		gmove(&r1, t)
-		regfree(&r1)
+		gc.Regfree(&r1)
 		return
 	}
 
 	// requires register intermediate
 hard:
-	regalloc(&r1, cvt, t)
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 }
 
+func intLiteral(n *gc.Node) (x int64, ok bool) {
+	if n == nil || n.Op != gc.OLITERAL {
+		return
+	}
+	switch n.Val.Ctype {
+	case gc.CTINT, gc.CTRUNE:
+		return gc.Mpgetfix(n.Val.U.Xval), true
+	case gc.CTBOOL:
+		return int64(n.Val.U.Bval), true
+	}
+	return
+}
+
+// gins is called by the front end.
+// It synthesizes some multiple-instruction sequences
+// so the front end can stay simpler.
+func gins(as int, f, t *gc.Node) *obj.Prog {
+	if as >= obj.A_ARCHSPECIFIC {
+		if x, ok := intLiteral(f); ok {
+			ginscon(as, x, t)
+			return nil // caller must not use
+		}
+	}
+	if as == ppc64.ACMP || as == ppc64.ACMPU {
+		if x, ok := intLiteral(t); ok {
+			ginscon2(as, f, x)
+			return nil // caller must not use
+		}
+	}
+	return rawgins(as, f, t)
+}
+
 /*
  * generate one instruction:
  *	as f, t
  */
-func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 	// TODO(austin): Add self-move test like in 6g (but be careful
 	// of truncation moves)
 
@@ -700,6 +567,41 @@
 	gc.Naddr(&p.From, f)
 	gc.Naddr(&p.To, t)
 
+	switch as {
+	case obj.ACALL:
+		if p.To.Type == obj.TYPE_REG && p.To.Reg != ppc64.REG_CTR {
+			// Allow front end to emit CALL REG, and rewrite into MOV REG, CTR; CALL CTR.
+			pp := gc.Prog(as)
+			pp.From = p.From
+			pp.To.Type = obj.TYPE_REG
+			pp.To.Reg = ppc64.REG_CTR
+
+			p.As = ppc64.AMOVD
+			p.From = p.To
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = ppc64.REG_CTR
+
+			if gc.Debug['g'] != 0 {
+				fmt.Printf("%v\n", p)
+				fmt.Printf("%v\n", pp)
+			}
+
+			return pp
+		}
+
+	// Bad things the front end has done to us. Crash to find call stack.
+	case ppc64.AAND, ppc64.AMULLD:
+		if p.From.Type == obj.TYPE_CONST {
+			gc.Debug['h'] = 1
+			gc.Fatal("bad inst: %v", p)
+		}
+	case ppc64.ACMP, ppc64.ACMPU:
+		if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
+			gc.Debug['h'] = 1
+			gc.Fatal("bad inst: %v", p)
+		}
+	}
+
 	if gc.Debug['g'] != 0 {
 		fmt.Printf("%v\n", p)
 	}
@@ -831,10 +733,9 @@
 		// ACMPU
 		gc.OLE<<16 | gc.TUINT16,
 		gc.OLE<<16 | gc.TUINT32,
-		gc.OLE<<16 | gc.TUINT64,
-		gc.OLE<<16 | gc.TFLOAT32,
-		// AFCMPU
-		gc.OLE<<16 | gc.TFLOAT64:
+		gc.OLE<<16 | gc.TUINT64:
+		// No OLE for floats, because it mishandles NaN.
+		// Front end must reverse comparison or use OLT and OEQ together.
 		a = ppc64.ABLE
 
 	case gc.OGT<<16 | gc.TINT8,
@@ -856,9 +757,9 @@
 		gc.OGE<<16 | gc.TUINT8,
 		gc.OGE<<16 | gc.TUINT16,
 		gc.OGE<<16 | gc.TUINT32,
-		gc.OGE<<16 | gc.TUINT64,
-		gc.OGE<<16 | gc.TFLOAT32,
-		gc.OGE<<16 | gc.TFLOAT64:
+		gc.OGE<<16 | gc.TUINT64:
+		// No OGE for floats, because it mishandles NaN.
+		// Front end must reverse comparison or use OLT and OEQ together.
 		a = ppc64.ABGE
 
 	case gc.OCMP<<16 | gc.TBOOL,
diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go
new file mode 100644
index 0000000..610f251
--- /dev/null
+++ b/src/cmd/internal/gc/cgen.go
@@ -0,0 +1,2567 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+/*
+ * generate:
+ *	res = n;
+ * simplifies and calls Thearch.Gmove.
+ */
+func Cgen(n *Node, res *Node) {
+	if Debug['g'] != 0 {
+		Dump("\ncgen-n", n)
+		Dump("cgen-res", res)
+	}
+
+	if n == nil || n.Type == nil {
+		return
+	}
+
+	if res == nil || res.Type == nil {
+		Fatal("cgen: res nil")
+	}
+
+	for n.Op == OCONVNOP {
+		n = n.Left
+	}
+
+	switch n.Op {
+	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+		if res.Op != ONAME || res.Addable == 0 {
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Cgen_slice(n, &n1)
+			Cgen(&n1, res)
+		} else {
+			Cgen_slice(n, res)
+		}
+		return
+
+	case OEFACE:
+		if res.Op != ONAME || res.Addable == 0 {
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Cgen_eface(n, &n1)
+			Cgen(&n1, res)
+		} else {
+			Cgen_eface(n, res)
+		}
+		return
+	}
+
+	if n.Ullman >= UINF {
+		if n.Op == OINDREG {
+			Fatal("cgen: this is going to miscompile")
+		}
+		if res.Ullman >= UINF {
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Cgen(n, &n1)
+			Cgen(&n1, res)
+			return
+		}
+	}
+
+	if Isfat(n.Type) {
+		if n.Type.Width < 0 {
+			Fatal("forgot to compute width for %v", Tconv(n.Type, 0))
+		}
+		sgen(n, res, n.Type.Width)
+		return
+	}
+
+	if res.Addable == 0 {
+		if n.Ullman > res.Ullman {
+			if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
+				var n1 Node
+				Tempname(&n1, n.Type)
+				Cgen(n, &n1)
+				Cgen(&n1, res)
+				return
+			}
+
+			var n1 Node
+			Regalloc(&n1, n.Type, res)
+			Cgen(n, &n1)
+			if n1.Ullman > res.Ullman {
+				Dump("n1", &n1)
+				Dump("res", res)
+				Fatal("loop in cgen")
+			}
+
+			Cgen(&n1, res)
+			Regfree(&n1)
+			return
+		}
+
+		var f int
+		if res.Ullman >= UINF {
+			goto gen
+		}
+
+		if Complexop(n, res) {
+			Complexgen(n, res)
+			return
+		}
+
+		f = 1 // gen thru register
+		switch n.Op {
+		case OLITERAL:
+			if Smallintconst(n) {
+				f = 0
+			}
+
+		case OREGISTER:
+			f = 0
+		}
+
+		if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
+			a := Thearch.Optoas(OAS, res.Type)
+			var addr obj.Addr
+			if Thearch.Sudoaddable(a, res, &addr) {
+				var p1 *obj.Prog
+				if f != 0 {
+					var n2 Node
+					Regalloc(&n2, res.Type, nil)
+					Cgen(n, &n2)
+					p1 = Thearch.Gins(a, &n2, nil)
+					Regfree(&n2)
+				} else {
+					p1 = Thearch.Gins(a, n, nil)
+				}
+				p1.To = addr
+				if Debug['g'] != 0 {
+					fmt.Printf("%v [ignore previous line]\n", p1)
+				}
+				Thearch.Sudoclean()
+				return
+			}
+		}
+
+	gen:
+		if Ctxt.Arch.Thechar == '8' {
+			// no registers to speak of
+			var n1, n2 Node
+			Tempname(&n1, n.Type)
+			Cgen(n, &n1)
+			Igen(res, &n2, nil)
+			Thearch.Gmove(&n1, &n2)
+			Regfree(&n2)
+			return
+		}
+
+		var n1 Node
+		Igen(res, &n1, nil)
+		Cgen(n, &n1)
+		Regfree(&n1)
+		return
+	}
+
+	// update addressability for string, slice
+	// can't do in walk because n->left->addable
+	// changes if n->left is an escaping local variable.
+	switch n.Op {
+	case OSPTR,
+		OLEN:
+		if Isslice(n.Left.Type) || Istype(n.Left.Type, TSTRING) {
+			n.Addable = n.Left.Addable
+		}
+
+	case OCAP:
+		if Isslice(n.Left.Type) {
+			n.Addable = n.Left.Addable
+		}
+
+	case OITAB:
+		n.Addable = n.Left.Addable
+	}
+
+	if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
+		// if both are addressable, move
+		if n.Addable != 0 && res.Addable != 0 {
+			if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || Iscomplex[n.Type.Etype] || Iscomplex[res.Type.Etype] {
+				Thearch.Gmove(n, res)
+			} else {
+				var n1 Node
+				Regalloc(&n1, n.Type, nil)
+				Thearch.Gmove(n, &n1)
+				Cgen(&n1, res)
+				Regfree(&n1)
+			}
+
+			return
+		}
+
+		// if both are not addressable, use a temporary.
+		if n.Addable == 0 && res.Addable == 0 {
+			// could use regalloc here sometimes,
+			// but have to check for ullman >= UINF.
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Cgen(n, &n1)
+			Cgen(&n1, res)
+			return
+		}
+
+		// if result is not addressable directly but n is,
+		// compute its address and then store via the address.
+		if res.Addable == 0 {
+			var n1 Node
+			Igen(res, &n1, nil)
+			Cgen(n, &n1)
+			Regfree(&n1)
+			return
+		}
+	}
+
+	if Complexop(n, res) {
+		Complexgen(n, res)
+		return
+	}
+
+	if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable != 0 {
+		Thearch.Gmove(n, res)
+		return
+	}
+
+	if Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+		// if both are addressable, move
+		if n.Addable != 0 {
+			if n.Op == OREGISTER || res.Op == OREGISTER {
+				Thearch.Gmove(n, res)
+			} else {
+				var n1 Node
+				Regalloc(&n1, n.Type, nil)
+				Thearch.Gmove(n, &n1)
+				Cgen(&n1, res)
+				Regfree(&n1)
+			}
+			return
+		}
+	}
+
+	// if n is sudoaddable generate addr and move
+	if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !Iscomplex[n.Type.Etype] && !Iscomplex[res.Type.Etype] {
+		a := Thearch.Optoas(OAS, n.Type)
+		var addr obj.Addr
+		if Thearch.Sudoaddable(a, n, &addr) {
+			if res.Op != OREGISTER {
+				var n2 Node
+				Regalloc(&n2, res.Type, nil)
+				p1 := Thearch.Gins(a, nil, &n2)
+				p1.From = addr
+				if Debug['g'] != 0 {
+					fmt.Printf("%v [ignore previous line]\n", p1)
+				}
+				Thearch.Gmove(&n2, res)
+				Regfree(&n2)
+			} else {
+				p1 := Thearch.Gins(a, nil, res)
+				p1.From = addr
+				if Debug['g'] != 0 {
+					fmt.Printf("%v [ignore previous line]\n", p1)
+				}
+			}
+			Thearch.Sudoclean()
+			return
+		}
+	}
+
+	nl := n.Left
+	nr := n.Right
+
+	if nl != nil && nl.Ullman >= UINF {
+		if nr != nil && nr.Ullman >= UINF {
+			var n1 Node
+			Tempname(&n1, nl.Type)
+			Cgen(nl, &n1)
+			n2 := *n
+			n2.Left = &n1
+			Cgen(&n2, res)
+			return
+		}
+	}
+
+	// 64-bit ops are hard on 32-bit machine.
+	if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
+		switch n.Op {
+		// math goes to cgen64.
+		case OMINUS,
+			OCOM,
+			OADD,
+			OSUB,
+			OMUL,
+			OLROT,
+			OLSH,
+			ORSH,
+			OAND,
+			OOR,
+			OXOR:
+			Thearch.Cgen64(n, res)
+			return
+		}
+	}
+
+	if Thearch.Cgen_float != nil && nl != nil && Isfloat[n.Type.Etype] && Isfloat[nl.Type.Etype] {
+		Thearch.Cgen_float(n, res)
+		return
+	}
+
+	if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
+		a := Thearch.Optoas(OAS, n.Type)
+		var addr obj.Addr
+		if Thearch.Sudoaddable(a, n, &addr) {
+			if res.Op == OREGISTER {
+				p1 := Thearch.Gins(a, nil, res)
+				p1.From = addr
+			} else {
+				var n2 Node
+				Regalloc(&n2, n.Type, nil)
+				p1 := Thearch.Gins(a, nil, &n2)
+				p1.From = addr
+				Thearch.Gins(a, &n2, res)
+				Regfree(&n2)
+			}
+
+			Thearch.Sudoclean()
+			return
+		}
+	}
+
+	var a int
+	switch n.Op {
+	default:
+		Dump("cgen", n)
+		Dump("cgen-res", res)
+		Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
+
+		// these call bgen to get a bool value
+	case OOROR,
+		OANDAND,
+		OEQ,
+		ONE,
+		OLT,
+		OLE,
+		OGE,
+		OGT,
+		ONOT:
+		p1 := Gbranch(obj.AJMP, nil, 0)
+
+		p2 := Pc
+		Thearch.Gmove(Nodbool(true), res)
+		p3 := Gbranch(obj.AJMP, nil, 0)
+		Patch(p1, Pc)
+		Bgen(n, true, 0, p2)
+		Thearch.Gmove(Nodbool(false), res)
+		Patch(p3, Pc)
+		return
+
+	case OPLUS:
+		Cgen(nl, res)
+		return
+
+		// unary
+	case OCOM:
+		a := Thearch.Optoas(OXOR, nl.Type)
+
+		var n1 Node
+		Regalloc(&n1, nl.Type, nil)
+		Cgen(nl, &n1)
+		var n2 Node
+		Nodconst(&n2, nl.Type, -1)
+		Thearch.Gins(a, &n2, &n1)
+		cgen_norm(n, &n1, res)
+		return
+
+	case OMINUS:
+		if Isfloat[nl.Type.Etype] {
+			nr = Nodintconst(-1)
+			Convlit(&nr, n.Type)
+			a = Thearch.Optoas(OMUL, nl.Type)
+			goto sbop
+		}
+
+		a := Thearch.Optoas(int(n.Op), nl.Type)
+		// unary
+		var n1 Node
+		Regalloc(&n1, nl.Type, res)
+
+		Cgen(nl, &n1)
+		if Ctxt.Arch.Thechar == '5' {
+			var n2 Node
+			Nodconst(&n2, nl.Type, 0)
+			Thearch.Gins(a, &n2, &n1)
+		} else if Ctxt.Arch.Thechar == '7' {
+			Thearch.Gins(a, &n1, &n1)
+		} else {
+			Thearch.Gins(a, nil, &n1)
+		}
+		cgen_norm(n, &n1, res)
+		return
+
+		// symmetric binary
+	case OAND,
+		OOR,
+		OXOR,
+		OADD,
+		OMUL:
+		if n.Op == OMUL && Thearch.Cgen_bmul != nil && Thearch.Cgen_bmul(int(n.Op), nl, nr, res) {
+			break
+		}
+		a = Thearch.Optoas(int(n.Op), nl.Type)
+		goto sbop
+
+		// asymmetric binary
+	case OSUB:
+		a = Thearch.Optoas(int(n.Op), nl.Type)
+		goto abop
+
+	case OHMUL:
+		Thearch.Cgen_hmul(nl, nr, res)
+
+	case OCONV:
+		if Eqtype(n.Type, nl.Type) || Noconv(n.Type, nl.Type) {
+			Cgen(nl, res)
+			return
+		}
+
+		if Ctxt.Arch.Thechar == '8' {
+			var n1 Node
+			var n2 Node
+			Tempname(&n2, n.Type)
+			Mgen(nl, &n1, res)
+			Thearch.Gmove(&n1, &n2)
+			Thearch.Gmove(&n2, res)
+			Mfree(&n1)
+			break
+		}
+
+		var n1 Node
+		var n2 Node
+		if Ctxt.Arch.Thechar == '5' {
+			if nl.Addable != 0 && !Is64(nl.Type) {
+				Regalloc(&n1, nl.Type, res)
+				Thearch.Gmove(nl, &n1)
+			} else {
+				if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || Isfloat[nl.Type.Etype] {
+					Tempname(&n1, nl.Type)
+				} else {
+					Regalloc(&n1, nl.Type, res)
+				}
+				Cgen(nl, &n1)
+			}
+			if n.Type.Width > int64(Widthptr) || Is64(n.Type) || Isfloat[n.Type.Etype] {
+				Tempname(&n2, n.Type)
+			} else {
+				Regalloc(&n2, n.Type, nil)
+			}
+		} else {
+			if n.Type.Width > nl.Type.Width {
+				// If loading from memory, do conversion during load,
+				// so as to avoid use of 8-bit register in, say, int(*byteptr).
+				switch nl.Op {
+				case ODOT, ODOTPTR, OINDEX, OIND, ONAME:
+					Igen(nl, &n1, res)
+					Regalloc(&n2, n.Type, res)
+					Thearch.Gmove(&n1, &n2)
+					Thearch.Gmove(&n2, res)
+					Regfree(&n2)
+					Regfree(&n1)
+					return
+				}
+			}
+			Regalloc(&n1, nl.Type, res)
+			Regalloc(&n2, n.Type, &n1)
+			Cgen(nl, &n1)
+		}
+
+		// if we do the conversion n1 -> n2 here
+		// reusing the register, then gmove won't
+		// have to allocate its own register.
+		Thearch.Gmove(&n1, &n2)
+		Thearch.Gmove(&n2, res)
+		if n2.Op == OREGISTER {
+			Regfree(&n2)
+		}
+		if n1.Op == OREGISTER {
+			Regfree(&n1)
+		}
+
+	case ODOT,
+		ODOTPTR,
+		OINDEX,
+		OIND,
+		ONAME: // PHEAP or PPARAMREF var
+		var n1 Node
+		Igen(n, &n1, res)
+
+		Thearch.Gmove(&n1, res)
+		Regfree(&n1)
+
+		// interface table is first word of interface value
+	case OITAB:
+		var n1 Node
+		Igen(nl, &n1, res)
+
+		n1.Type = n.Type
+		Thearch.Gmove(&n1, res)
+		Regfree(&n1)
+
+	case OSPTR:
+		// pointer is the first word of string or slice.
+		if Isconst(nl, CTSTR) {
+			var n1 Node
+			Regalloc(&n1, Types[Tptr], res)
+			p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1)
+			Datastring(nl.Val.U.Sval, &p1.From)
+			p1.From.Type = obj.TYPE_ADDR
+			Thearch.Gmove(&n1, res)
+			Regfree(&n1)
+			break
+		}
+
+		var n1 Node
+		Igen(nl, &n1, res)
+		n1.Type = n.Type
+		Thearch.Gmove(&n1, res)
+		Regfree(&n1)
+
+	case OLEN:
+		if Istype(nl.Type, TMAP) || Istype(nl.Type, TCHAN) {
+			// map and chan have len in the first int-sized word.
+			// a zero pointer means zero length
+			var n1 Node
+			Regalloc(&n1, Types[Tptr], res)
+
+			Cgen(nl, &n1)
+
+			var n2 Node
+			Nodconst(&n2, Types[Tptr], 0)
+			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2)
+			p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0)
+
+			n2 = n1
+			n2.Op = OINDREG
+			n2.Type = Types[Simtype[TINT]]
+			Thearch.Gmove(&n2, &n1)
+
+			Patch(p1, Pc)
+
+			Thearch.Gmove(&n1, res)
+			Regfree(&n1)
+			break
+		}
+
+		if Istype(nl.Type, TSTRING) || Isslice(nl.Type) {
+			// both slice and string have len one pointer into the struct.
+			// a zero pointer means zero length
+			var n1 Node
+			Igen(nl, &n1, res)
+
+			n1.Type = Types[Simtype[TUINT]]
+			n1.Xoffset += int64(Array_nel)
+			Thearch.Gmove(&n1, res)
+			Regfree(&n1)
+			break
+		}
+
+		Fatal("cgen: OLEN: unknown type %v", Tconv(nl.Type, obj.FmtLong))
+
+	case OCAP:
+		if Istype(nl.Type, TCHAN) {
+			// chan has cap in the second int-sized word.
+			// a zero pointer means zero length
+			var n1 Node
+			Regalloc(&n1, Types[Tptr], res)
+
+			Cgen(nl, &n1)
+
+			var n2 Node
+			Nodconst(&n2, Types[Tptr], 0)
+			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2)
+			p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0)
+
+			n2 = n1
+			n2.Op = OINDREG
+			n2.Xoffset = int64(Widthint)
+			n2.Type = Types[Simtype[TINT]]
+			Thearch.Gmove(&n2, &n1)
+
+			Patch(p1, Pc)
+
+			Thearch.Gmove(&n1, res)
+			Regfree(&n1)
+			break
+		}
+
+		if Isslice(nl.Type) {
+			var n1 Node
+			Igen(nl, &n1, res)
+			n1.Type = Types[Simtype[TUINT]]
+			n1.Xoffset += int64(Array_cap)
+			Thearch.Gmove(&n1, res)
+			Regfree(&n1)
+			break
+		}
+
+		Fatal("cgen: OCAP: unknown type %v", Tconv(nl.Type, obj.FmtLong))
+
+	case OADDR:
+		if n.Bounded { // let race detector avoid nil checks
+			Disable_checknil++
+		}
+		Agen(nl, res)
+		if n.Bounded {
+			Disable_checknil--
+		}
+
+	case OCALLMETH:
+		cgen_callmeth(n, 0)
+		cgen_callret(n, res)
+
+	case OCALLINTER:
+		cgen_callinter(n, res, 0)
+		cgen_callret(n, res)
+
+	case OCALLFUNC:
+		cgen_call(n, 0)
+		cgen_callret(n, res)
+
+	case OMOD, ODIV:
+		if Isfloat[n.Type.Etype] || Thearch.Dodiv == nil {
+			a = Thearch.Optoas(int(n.Op), nl.Type)
+			goto abop
+		}
+
+		if nl.Ullman >= nr.Ullman {
+			var n1 Node
+			Regalloc(&n1, nl.Type, res)
+			Cgen(nl, &n1)
+			cgen_div(int(n.Op), &n1, nr, res)
+			Regfree(&n1)
+		} else {
+			var n2 Node
+			if !Smallintconst(nr) {
+				Regalloc(&n2, nr.Type, res)
+				Cgen(nr, &n2)
+			} else {
+				n2 = *nr
+			}
+
+			cgen_div(int(n.Op), nl, &n2, res)
+			if n2.Op != OLITERAL {
+				Regfree(&n2)
+			}
+		}
+
+	case OLSH,
+		ORSH,
+		OLROT:
+		Thearch.Cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
+	}
+
+	return
+
+	/*
+	 * put simplest on right - we'll generate into left
+	 * and then adjust it using the computation of right.
+	 * constants and variables have the same ullman
+	 * count, so look for constants specially.
+	 *
+	 * an integer constant we can use as an immediate
+	 * is simpler than a variable - we can use the immediate
+	 * in the adjustment instruction directly - so it goes
+	 * on the right.
+	 *
+	 * other constants, like big integers or floating point
+	 * constants, require a mov into a register, so those
+	 * might as well go on the left, so we can reuse that
+	 * register for the computation.
+	 */
+sbop: // symmetric binary
+	if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (Smallintconst(nl) || (nr.Op == OLITERAL && !Smallintconst(nr)))) {
+		r := nl
+		nl = nr
+		nr = r
+	}
+
+abop: // asymmetric binary
+	var n1 Node
+	var n2 Node
+	if Ctxt.Arch.Thechar == '8' {
+		// no registers, sigh
+		if Smallintconst(nr) {
+			var n1 Node
+			Mgen(nl, &n1, res)
+			var n2 Node
+			Regalloc(&n2, nl.Type, &n1)
+			Thearch.Gmove(&n1, &n2)
+			Thearch.Gins(a, nr, &n2)
+			Thearch.Gmove(&n2, res)
+			Regfree(&n2)
+			Mfree(&n1)
+		} else if nl.Ullman >= nr.Ullman {
+			var nt Node
+			Tempname(&nt, nl.Type)
+			Cgen(nl, &nt)
+			var n2 Node
+			Mgen(nr, &n2, nil)
+			var n1 Node
+			Regalloc(&n1, nl.Type, res)
+			Thearch.Gmove(&nt, &n1)
+			Thearch.Gins(a, &n2, &n1)
+			Thearch.Gmove(&n1, res)
+			Regfree(&n1)
+			Mfree(&n2)
+		} else {
+			var n2 Node
+			Regalloc(&n2, nr.Type, res)
+			Cgen(nr, &n2)
+			var n1 Node
+			Regalloc(&n1, nl.Type, nil)
+			Cgen(nl, &n1)
+			Thearch.Gins(a, &n2, &n1)
+			Regfree(&n2)
+			Thearch.Gmove(&n1, res)
+			Regfree(&n1)
+		}
+		return
+	}
+
+	if nl.Ullman >= nr.Ullman {
+		Regalloc(&n1, nl.Type, res)
+		Cgen(nl, &n1)
+
+		if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+			n2 = *nr
+		} else {
+			Regalloc(&n2, nr.Type, nil)
+			Cgen(nr, &n2)
+		}
+	} else {
+		if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+			n2 = *nr
+		} else {
+			Regalloc(&n2, nr.Type, res)
+			Cgen(nr, &n2)
+		}
+
+		Regalloc(&n1, nl.Type, nil)
+		Cgen(nl, &n1)
+	}
+
+	Thearch.Gins(a, &n2, &n1)
+	if n2.Op != OLITERAL {
+		Regfree(&n2)
+	}
+	cgen_norm(n, &n1, res)
+}
+
+// cgen_norm moves n1 to res, truncating to expected type if necessary.
+// n1 is a register, and cgen_norm frees it.
+func cgen_norm(n, n1, res *Node) {
+	switch Ctxt.Arch.Thechar {
+	case '6', '8':
+		// We use sized math, so the result is already truncated.
+	default:
+		switch n.Op {
+		case OADD, OSUB, OMUL, ODIV, OCOM, OMINUS:
+			// TODO(rsc): What about left shift?
+			Thearch.Gins(Thearch.Optoas(OAS, n.Type), n1, n1)
+		}
+	}
+
+	Thearch.Gmove(n1, res)
+	Regfree(n1)
+}
+
+func Mgen(n *Node, n1 *Node, rg *Node) {
+	n1.Op = OEMPTY
+
+	if n.Addable != 0 {
+		*n1 = *n
+		if n1.Op == OREGISTER || n1.Op == OINDREG {
+			reg[n.Val.U.Reg-int16(Thearch.REGMIN)]++
+		}
+		return
+	}
+
+	Tempname(n1, n.Type)
+	Cgen(n, n1)
+	if n.Type.Width <= int64(Widthptr) || Isfloat[n.Type.Etype] {
+		n2 := *n1
+		Regalloc(n1, n.Type, rg)
+		Thearch.Gmove(&n2, n1)
+	}
+}
+
+func Mfree(n *Node) {
+	if n.Op == OREGISTER {
+		Regfree(n)
+	}
+}
+
+/*
+ * allocate a register (reusing res if possible) and generate
+ *  a = n
+ * The caller must call Regfree(a).
+ */
+func Cgenr(n *Node, a *Node, res *Node) {
+	if Debug['g'] != 0 {
+		Dump("cgenr-n", n)
+	}
+
+	if Isfat(n.Type) {
+		Fatal("cgenr on fat node")
+	}
+
+	if n.Addable != 0 {
+		Regalloc(a, n.Type, res)
+		Thearch.Gmove(n, a)
+		return
+	}
+
+	switch n.Op {
+	case ONAME,
+		ODOT,
+		ODOTPTR,
+		OINDEX,
+		OCALLFUNC,
+		OCALLMETH,
+		OCALLINTER:
+		var n1 Node
+		Igen(n, &n1, res)
+		Regalloc(a, Types[Tptr], &n1)
+		Thearch.Gmove(&n1, a)
+		Regfree(&n1)
+
+	default:
+		Regalloc(a, n.Type, res)
+		Cgen(n, a)
+	}
+}
+
+/*
+ * allocate a register (reusing res if possible) and generate
+ * a = &n
+ * The caller must call Regfree(a).
+ * The generated code checks that the result is not nil.
+ */
+func Agenr(n *Node, a *Node, res *Node) {
+	if Debug['g'] != 0 {
+		Dump("\nagenr-n", n)
+	}
+
+	nl := n.Left
+	nr := n.Right
+
+	switch n.Op {
+	case ODOT, ODOTPTR, OCALLFUNC, OCALLMETH, OCALLINTER:
+		var n1 Node
+		Igen(n, &n1, res)
+		Regalloc(a, Types[Tptr], &n1)
+		Agen(&n1, a)
+		Regfree(&n1)
+
+	case OIND:
+		Cgenr(n.Left, a, res)
+		Cgen_checknil(a)
+
+	case OINDEX:
+		if Ctxt.Arch.Thechar == '5' {
+			var p2 *obj.Prog // to be patched to panicindex.
+			w := uint32(n.Type.Width)
+			bounded := Debug['B'] != 0 || n.Bounded
+			var n1 Node
+			var n3 Node
+			if nr.Addable != 0 {
+				var tmp Node
+				if !Isconst(nr, CTINT) {
+					Tempname(&tmp, Types[TINT32])
+				}
+				if !Isconst(nl, CTSTR) {
+					Agenr(nl, &n3, res)
+				}
+				if !Isconst(nr, CTINT) {
+					p2 = Thearch.Cgenindex(nr, &tmp, bounded)
+					Regalloc(&n1, tmp.Type, nil)
+					Thearch.Gmove(&tmp, &n1)
+				}
+			} else if nl.Addable != 0 {
+				if !Isconst(nr, CTINT) {
+					var tmp Node
+					Tempname(&tmp, Types[TINT32])
+					p2 = Thearch.Cgenindex(nr, &tmp, bounded)
+					Regalloc(&n1, tmp.Type, nil)
+					Thearch.Gmove(&tmp, &n1)
+				}
+
+				if !Isconst(nl, CTSTR) {
+					Agenr(nl, &n3, res)
+				}
+			} else {
+				var tmp Node
+				Tempname(&tmp, Types[TINT32])
+				p2 = Thearch.Cgenindex(nr, &tmp, bounded)
+				nr = &tmp
+				if !Isconst(nl, CTSTR) {
+					Agenr(nl, &n3, res)
+				}
+				Regalloc(&n1, tmp.Type, nil)
+				Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
+			}
+
+			// &a is in &n3 (allocated in res)
+			// i is in &n1 (if not constant)
+			// w is width
+
+			// constant index
+			if Isconst(nr, CTINT) {
+				if Isconst(nl, CTSTR) {
+					Fatal("constant string constant index")
+				}
+				v := uint64(Mpgetfix(nr.Val.U.Xval))
+				var n2 Node
+				if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+					if Debug['B'] == 0 && !n.Bounded {
+						n1 = n3
+						n1.Op = OINDREG
+						n1.Type = Types[Tptr]
+						n1.Xoffset = int64(Array_nel)
+						var n4 Node
+						Regalloc(&n4, n1.Type, nil)
+						Thearch.Gmove(&n1, &n4)
+						Nodconst(&n2, Types[TUINT32], int64(v))
+						Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n4, &n2)
+						Regfree(&n4)
+						p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1)
+						Ginscall(Panicindex, 0)
+						Patch(p1, Pc)
+					}
+
+					n1 = n3
+					n1.Op = OINDREG
+					n1.Type = Types[Tptr]
+					n1.Xoffset = int64(Array_array)
+					Thearch.Gmove(&n1, &n3)
+				}
+
+				Nodconst(&n2, Types[Tptr], int64(v*uint64(w)))
+				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
+				*a = n3
+				break
+			}
+
+			var n2 Node
+			Regalloc(&n2, Types[TINT32], &n1) // i
+			Thearch.Gmove(&n1, &n2)
+			Regfree(&n1)
+
+			var n4 Node
+			if Debug['B'] == 0 && !n.Bounded {
+				// check bounds
+				if Isconst(nl, CTSTR) {
+					Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval)))
+				} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+					n1 = n3
+					n1.Op = OINDREG
+					n1.Type = Types[Tptr]
+					n1.Xoffset = int64(Array_nel)
+					Regalloc(&n4, Types[TUINT32], nil)
+					Thearch.Gmove(&n1, &n4)
+				} else {
+					Nodconst(&n4, Types[TUINT32], nl.Type.Bound)
+				}
+
+				Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n2, &n4)
+				if n4.Op == OREGISTER {
+					Regfree(&n4)
+				}
+				p1 := Gbranch(Thearch.Optoas(OLT, Types[TUINT32]), nil, +1)
+				if p2 != nil {
+					Patch(p2, Pc)
+				}
+				Ginscall(Panicindex, 0)
+				Patch(p1, Pc)
+			}
+
+			if Isconst(nl, CTSTR) {
+				Regalloc(&n3, Types[Tptr], res)
+				p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
+				Datastring(nl.Val.U.Sval, &p1.From)
+				p1.From.Type = obj.TYPE_ADDR
+			} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+				n1 = n3
+				n1.Op = OINDREG
+				n1.Type = Types[Tptr]
+				n1.Xoffset = int64(Array_array)
+				Thearch.Gmove(&n1, &n3)
+			}
+
+			if w == 0 {
+				// nothing to do
+			} else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
+				// done by back end
+			} else if w == 1 {
+				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
+			} else {
+				Regalloc(&n4, Types[TUINT32], nil)
+				Nodconst(&n1, Types[TUINT32], int64(w))
+				Thearch.Gmove(&n1, &n4)
+				Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2)
+				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
+				Regfree(&n4)
+			}
+			*a = n3
+			Regfree(&n2)
+			break
+		}
+		if Ctxt.Arch.Thechar == '8' {
+			var p2 *obj.Prog // to be patched to panicindex.
+			w := uint32(n.Type.Width)
+			bounded := Debug['B'] != 0 || n.Bounded
+			var n3 Node
+			var tmp Node
+			var n1 Node
+			if nr.Addable != 0 {
+				// Generate &nl first, and move nr into register.
+				if !Isconst(nl, CTSTR) {
+					Igen(nl, &n3, res)
+				}
+				if !Isconst(nr, CTINT) {
+					p2 = Thearch.Igenindex(nr, &tmp, bounded)
+					Regalloc(&n1, tmp.Type, nil)
+					Thearch.Gmove(&tmp, &n1)
+				}
+			} else if nl.Addable != 0 {
+				// Generate nr first, and move &nl into register.
+				if !Isconst(nr, CTINT) {
+					p2 = Thearch.Igenindex(nr, &tmp, bounded)
+					Regalloc(&n1, tmp.Type, nil)
+					Thearch.Gmove(&tmp, &n1)
+				}
+
+				if !Isconst(nl, CTSTR) {
+					Igen(nl, &n3, res)
+				}
+			} else {
+				p2 = Thearch.Igenindex(nr, &tmp, bounded)
+				nr = &tmp
+				if !Isconst(nl, CTSTR) {
+					Igen(nl, &n3, res)
+				}
+				Regalloc(&n1, tmp.Type, nil)
+				Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
+			}
+
+			// For fixed array we really want the pointer in n3.
+			var n2 Node
+			if Isfixedarray(nl.Type) {
+				Regalloc(&n2, Types[Tptr], &n3)
+				Agen(&n3, &n2)
+				Regfree(&n3)
+				n3 = n2
+			}
+
+			// &a[0] is in n3 (allocated in res)
+			// i is in n1 (if not constant)
+			// len(a) is in nlen (if needed)
+			// w is width
+
+			// constant index
+			if Isconst(nr, CTINT) {
+				if Isconst(nl, CTSTR) {
+					Fatal("constant string constant index") // front end should handle
+				}
+				v := uint64(Mpgetfix(nr.Val.U.Xval))
+				if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+					if Debug['B'] == 0 && !n.Bounded {
+						nlen := n3
+						nlen.Type = Types[TUINT32]
+						nlen.Xoffset += int64(Array_nel)
+						Nodconst(&n2, Types[TUINT32], int64(v))
+						Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &nlen, &n2)
+						p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1)
+						Ginscall(Panicindex, -1)
+						Patch(p1, Pc)
+					}
+				}
+
+				// Load base pointer in n2 = n3.
+				Regalloc(&n2, Types[Tptr], &n3)
+
+				n3.Type = Types[Tptr]
+				n3.Xoffset += int64(Array_array)
+				Thearch.Gmove(&n3, &n2)
+				Regfree(&n3)
+				if v*uint64(w) != 0 {
+					Nodconst(&n1, Types[Tptr], int64(v*uint64(w)))
+					Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n1, &n2)
+				}
+				*a = n2
+				break
+			}
+
+			// i is in register n1, extend to 32 bits.
+			t := Types[TUINT32]
+
+			if Issigned[n1.Type.Etype] {
+				t = Types[TINT32]
+			}
+
+			Regalloc(&n2, t, &n1) // i
+			Thearch.Gmove(&n1, &n2)
+			Regfree(&n1)
+
+			if Debug['B'] == 0 && !n.Bounded {
+				// check bounds
+				t := Types[TUINT32]
+
+				var nlen Node
+				if Isconst(nl, CTSTR) {
+					Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
+				} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+					nlen = n3
+					nlen.Type = t
+					nlen.Xoffset += int64(Array_nel)
+				} else {
+					Nodconst(&nlen, t, nl.Type.Bound)
+				}
+
+				Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen)
+				p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1)
+				if p2 != nil {
+					Patch(p2, Pc)
+				}
+				Ginscall(Panicindex, -1)
+				Patch(p1, Pc)
+			}
+
+			if Isconst(nl, CTSTR) {
+				Regalloc(&n3, Types[Tptr], res)
+				p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
+				Datastring(nl.Val.U.Sval, &p1.From)
+				p1.From.Type = obj.TYPE_ADDR
+				Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
+				goto indexdone1
+			}
+
+			// Load base pointer in n3.
+			Regalloc(&tmp, Types[Tptr], &n3)
+
+			if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+				n3.Type = Types[Tptr]
+				n3.Xoffset += int64(Array_array)
+				Thearch.Gmove(&n3, &tmp)
+			}
+
+			Regfree(&n3)
+			n3 = tmp
+
+			if w == 0 {
+				// nothing to do
+			} else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
+				// done by back end
+			} else if w == 1 {
+				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
+			} else {
+				Nodconst(&tmp, Types[TUINT32], int64(w))
+				Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &tmp, &n2)
+				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
+			}
+
+		indexdone1:
+			*a = n3
+			Regfree(&n2)
+			break
+		}
+
+		freelen := 0
+		w := uint64(n.Type.Width)
+
+		// Generate the non-addressable child first.
+		var n3 Node
+		var nlen Node
+		var tmp Node
+		var n1 Node
+		if nr.Addable != 0 {
+			goto irad
+		}
+		if nl.Addable != 0 {
+			Cgenr(nr, &n1, nil)
+			if !Isconst(nl, CTSTR) {
+				if Isfixedarray(nl.Type) {
+					Agenr(nl, &n3, res)
+				} else {
+					Igen(nl, &nlen, res)
+					freelen = 1
+					nlen.Type = Types[Tptr]
+					nlen.Xoffset += int64(Array_array)
+					Regalloc(&n3, Types[Tptr], res)
+					Thearch.Gmove(&nlen, &n3)
+					nlen.Type = Types[Simtype[TUINT]]
+					nlen.Xoffset += int64(Array_nel) - int64(Array_array)
+				}
+			}
+
+			goto index
+		}
+
+		Tempname(&tmp, nr.Type)
+		Cgen(nr, &tmp)
+		nr = &tmp
+
+	irad:
+		if !Isconst(nl, CTSTR) {
+			if Isfixedarray(nl.Type) {
+				Agenr(nl, &n3, res)
+			} else {
+				if nl.Addable == 0 {
+					// igen will need an addressable node.
+					var tmp2 Node
+					Tempname(&tmp2, nl.Type)
+
+					Cgen(nl, &tmp2)
+					nl = &tmp2
+				}
+
+				Igen(nl, &nlen, res)
+				freelen = 1
+				nlen.Type = Types[Tptr]
+				nlen.Xoffset += int64(Array_array)
+				Regalloc(&n3, Types[Tptr], res)
+				Thearch.Gmove(&nlen, &n3)
+				nlen.Type = Types[Simtype[TUINT]]
+				nlen.Xoffset += int64(Array_nel) - int64(Array_array)
+			}
+		}
+
+		if !Isconst(nr, CTINT) {
+			Cgenr(nr, &n1, nil)
+		}
+
+		goto index
+
+		// &a is in &n3 (allocated in res)
+		// i is in &n1 (if not constant)
+		// len(a) is in nlen (if needed)
+		// w is width
+
+		// constant index
+	index:
+		if Isconst(nr, CTINT) {
+			if Isconst(nl, CTSTR) {
+				Fatal("constant string constant index") // front end should handle
+			}
+			v := uint64(Mpgetfix(nr.Val.U.Xval))
+			if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+				if Debug['B'] == 0 && !n.Bounded {
+					if nlen.Op != OREGISTER && (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') {
+						var tmp2 Node
+						Regalloc(&tmp2, Types[Simtype[TUINT]], nil)
+						Thearch.Gmove(&nlen, &tmp2)
+						Regfree(&nlen) // in case it is OINDREG
+						nlen = tmp2
+					}
+					var n2 Node
+					Nodconst(&n2, Types[Simtype[TUINT]], int64(v))
+					if Smallintconst(nr) {
+						Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &n2)
+					} else {
+						Regalloc(&tmp, Types[Simtype[TUINT]], nil)
+						Thearch.Gmove(&n2, &tmp)
+						Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &tmp)
+						Regfree(&tmp)
+					}
+
+					p1 := Gbranch(Thearch.Optoas(OGT, Types[Simtype[TUINT]]), nil, +1)
+					Ginscall(Panicindex, -1)
+					Patch(p1, Pc)
+				}
+
+				Regfree(&nlen)
+			}
+
+			if v*w != 0 {
+				Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), int64(v*w), &n3)
+			}
+			*a = n3
+			break
+		}
+
+		// type of the index
+		t := Types[TUINT64]
+
+		if Issigned[n1.Type.Etype] {
+			t = Types[TINT64]
+		}
+
+		var n2 Node
+		Regalloc(&n2, t, &n1) // i
+		Thearch.Gmove(&n1, &n2)
+		Regfree(&n1)
+
+		if Debug['B'] == 0 && !n.Bounded {
+			// check bounds
+			t = Types[Simtype[TUINT]]
+
+			if Is64(nr.Type) {
+				t = Types[TUINT64]
+			}
+			if Isconst(nl, CTSTR) {
+				Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
+			} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+				if Is64(nr.Type) || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+					var n5 Node
+					Regalloc(&n5, t, nil)
+					Thearch.Gmove(&nlen, &n5)
+					Regfree(&nlen)
+					nlen = n5
+				}
+			} else {
+				Nodconst(&nlen, t, nl.Type.Bound)
+				if !Smallintconst(&nlen) {
+					var n5 Node
+					Regalloc(&n5, t, nil)
+					Thearch.Gmove(&nlen, &n5)
+					nlen = n5
+					freelen = 1
+				}
+			}
+
+			Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen)
+			p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1)
+			Ginscall(Panicindex, -1)
+			Patch(p1, Pc)
+		}
+
+		if Isconst(nl, CTSTR) {
+			Regalloc(&n3, Types[Tptr], res)
+			p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ!
+			Datastring(nl.Val.U.Sval, &p1.From)
+			p1.From.Type = obj.TYPE_ADDR
+			Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
+			goto indexdone
+		}
+
+		if w == 0 {
+			// nothing to do
+		} else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
+			// done by back end
+		} else if w == 1 {
+			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
+		} else {
+			Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2)
+			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
+		}
+
+	indexdone:
+		*a = n3
+		Regfree(&n2)
+		if freelen != 0 {
+			Regfree(&nlen)
+		}
+
+	default:
+		Regalloc(a, Types[Tptr], res)
+		Agen(n, a)
+	}
+}
+
+/*
+ * generate:
+ *	res = &n;
+ * The generated code checks that the result is not nil.
+ */
+func Agen(n *Node, res *Node) {
+	if Debug['g'] != 0 {
+		Dump("\nagen-res", res)
+		Dump("agen-r", n)
+	}
+
+	if n == nil || n.Type == nil {
+		return
+	}
+
+	for n.Op == OCONVNOP {
+		n = n.Left
+	}
+
+	if Isconst(n, CTNIL) && n.Type.Width > int64(Widthptr) {
+		// Use of a nil interface or nil slice.
+		// Create a temporary we can take the address of and read.
+		// The generated code is just going to panic, so it need not
+		// be terribly efficient. See issue 3670.
+		var n1 Node
+		Tempname(&n1, n.Type)
+
+		Gvardef(&n1)
+		Thearch.Clearfat(&n1)
+		var n2 Node
+		Regalloc(&n2, Types[Tptr], res)
+		var n3 Node
+		n3.Op = OADDR
+		n3.Left = &n1
+		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n3, &n2)
+		Thearch.Gmove(&n2, res)
+		Regfree(&n2)
+		return
+	}
+
+	if n.Addable != 0 {
+		if n.Op == OREGISTER {
+			Fatal("agen OREGISTER")
+		}
+		var n1 Node
+		n1.Op = OADDR
+		n1.Left = n
+		var n2 Node
+		Regalloc(&n2, Types[Tptr], res)
+		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2)
+		Thearch.Gmove(&n2, res)
+		Regfree(&n2)
+		return
+	}
+
+	nl := n.Left
+
+	switch n.Op {
+	default:
+		Fatal("agen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
+
+	case OCALLMETH:
+		cgen_callmeth(n, 0)
+		cgen_aret(n, res)
+
+	case OCALLINTER:
+		cgen_callinter(n, res, 0)
+		cgen_aret(n, res)
+
+	case OCALLFUNC:
+		cgen_call(n, 0)
+		cgen_aret(n, res)
+
+	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+		var n1 Node
+		Tempname(&n1, n.Type)
+		Cgen_slice(n, &n1)
+		Agen(&n1, res)
+
+	case OEFACE:
+		var n1 Node
+		Tempname(&n1, n.Type)
+		Cgen_eface(n, &n1)
+		Agen(&n1, res)
+
+	case OINDEX:
+		var n1 Node
+		Agenr(n, &n1, res)
+		Thearch.Gmove(&n1, res)
+		Regfree(&n1)
+
+	case ONAME:
+		// should only get here with names in this func.
+		if n.Funcdepth > 0 && n.Funcdepth != Funcdepth {
+			Dump("bad agen", n)
+			Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, Funcdepth)
+		}
+
+		// should only get here for heap vars or paramref
+		if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
+			Dump("bad agen", n)
+			Fatal("agen: bad ONAME class %#x", n.Class)
+		}
+
+		Cgen(n.Heapaddr, res)
+		if n.Xoffset != 0 {
+			addOffset(res, n.Xoffset)
+		}
+
+	case OIND:
+		Cgen(nl, res)
+		Cgen_checknil(res)
+
+	case ODOT:
+		Agen(nl, res)
+		if n.Xoffset != 0 {
+			addOffset(res, n.Xoffset)
+		}
+
+	case ODOTPTR:
+		Cgen(nl, res)
+		Cgen_checknil(res)
+		if n.Xoffset != 0 {
+			addOffset(res, n.Xoffset)
+		}
+	}
+}
+
+func addOffset(res *Node, offset int64) {
+	if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' {
+		Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
+		return
+	}
+
+	var n1, n2 Node
+	Regalloc(&n1, Types[Tptr], nil)
+	Thearch.Gmove(res, &n1)
+	Regalloc(&n2, Types[Tptr], nil)
+	Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2)
+	Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1)
+	Thearch.Gmove(&n1, res)
+	Regfree(&n1)
+	Regfree(&n2)
+}
+
+/*
+ * generate:
+ *	newreg = &n;
+ *	res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must Regfree(a).
+ * The generated code checks that the result is not *nil.
+ */
+func Igen(n *Node, a *Node, res *Node) {
+	if Debug['g'] != 0 {
+		Dump("\nigen-n", n)
+	}
+
+	switch n.Op {
+	case ONAME:
+		if (n.Class&PHEAP != 0) || n.Class == PPARAMREF {
+			break
+		}
+		*a = *n
+		return
+
+	case OINDREG:
+		// Increase the refcount of the register so that igen's caller
+		// has to call Regfree.
+		if n.Val.U.Reg != int16(Thearch.REGSP) {
+			reg[n.Val.U.Reg-int16(Thearch.REGMIN)]++
+		}
+		*a = *n
+		return
+
+	case ODOT:
+		Igen(n.Left, a, res)
+		a.Xoffset += n.Xoffset
+		a.Type = n.Type
+		Fixlargeoffset(a)
+		return
+
+	case ODOTPTR:
+		Cgenr(n.Left, a, res)
+		Cgen_checknil(a)
+		a.Op = OINDREG
+		a.Xoffset += n.Xoffset
+		a.Type = n.Type
+		Fixlargeoffset(a)
+		return
+
+	case OCALLFUNC,
+		OCALLMETH,
+		OCALLINTER:
+		switch n.Op {
+		case OCALLFUNC:
+			cgen_call(n, 0)
+
+		case OCALLMETH:
+			cgen_callmeth(n, 0)
+
+		case OCALLINTER:
+			cgen_callinter(n, nil, 0)
+		}
+
+		var flist Iter
+		fp := Structfirst(&flist, Getoutarg(n.Left.Type))
+		*a = Node{}
+		a.Op = OINDREG
+		a.Val.U.Reg = int16(Thearch.REGSP)
+		a.Addable = 1
+		a.Xoffset = fp.Width
+		if HasLinkRegister() {
+			a.Xoffset += int64(Ctxt.Arch.Ptrsize)
+		}
+		a.Type = n.Type
+		return
+
+		// Index of fixed-size array by constant can
+	// put the offset in the addressing.
+	// Could do the same for slice except that we need
+	// to use the real index for the bounds checking.
+	case OINDEX:
+		if Isfixedarray(n.Left.Type) || (Isptr[n.Left.Type.Etype] && Isfixedarray(n.Left.Left.Type)) {
+			if Isconst(n.Right, CTINT) {
+				// Compute &a.
+				if !Isptr[n.Left.Type.Etype] {
+					Igen(n.Left, a, res)
+				} else {
+					var n1 Node
+					Igen(n.Left, &n1, res)
+					Cgen_checknil(&n1)
+					Regalloc(a, Types[Tptr], res)
+					Thearch.Gmove(&n1, a)
+					Regfree(&n1)
+					a.Op = OINDREG
+				}
+
+				// Compute &a[i] as &a + i*width.
+				a.Type = n.Type
+
+				a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
+				Fixlargeoffset(a)
+				return
+			}
+		}
+	}
+
+	Agenr(n, a, res)
+	a.Op = OINDREG
+	a.Type = n.Type
+}
+
+/*
+ * generate:
+ *	if(n == true) goto to;
+ */
+func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) {
+	if Debug['g'] != 0 {
+		Dump("\nbgen", n)
+	}
+
+	if n == nil {
+		n = Nodbool(true)
+	}
+
+	if n.Ninit != nil {
+		Genlist(n.Ninit)
+	}
+
+	if n.Type == nil {
+		Convlit(&n, Types[TBOOL])
+		if n.Type == nil {
+			return
+		}
+	}
+
+	et := int(n.Type.Etype)
+	if et != TBOOL {
+		Yyerror("cgen: bad type %v for %v", Tconv(n.Type, 0), Oconv(int(n.Op), 0))
+		Patch(Thearch.Gins(obj.AEND, nil, nil), to)
+		return
+	}
+
+	for n.Op == OCONVNOP {
+		n = n.Left
+		if n.Ninit != nil {
+			Genlist(n.Ninit)
+		}
+	}
+
+	if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] {
+		Thearch.Bgen_float(n, bool2int(true_), likely, to)
+		return
+	}
+
+	var nl *Node
+	var nr *Node
+	switch n.Op {
+	default:
+		goto def
+
+		// need to ask if it is bool?
+	case OLITERAL:
+		if !true_ == (n.Val.U.Bval == 0) {
+			Patch(Gbranch(obj.AJMP, nil, likely), to)
+		}
+		return
+
+	case ONAME:
+		if n.Addable == 0 || Ctxt.Arch.Thechar == '5' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+			goto def
+		}
+		var n1 Node
+		Nodconst(&n1, n.Type, 0)
+		Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &n1)
+		a := Thearch.Optoas(ONE, n.Type)
+		if !true_ {
+			a = Thearch.Optoas(OEQ, n.Type)
+		}
+		Patch(Gbranch(a, n.Type, likely), to)
+		return
+
+	case OANDAND, OOROR:
+		if (n.Op == OANDAND) == true_ {
+			p1 := Gbranch(obj.AJMP, nil, 0)
+			p2 := Gbranch(obj.AJMP, nil, 0)
+			Patch(p1, Pc)
+			Bgen(n.Left, !true_, -likely, p2)
+			Bgen(n.Right, !true_, -likely, p2)
+			p1 = Gbranch(obj.AJMP, nil, 0)
+			Patch(p1, to)
+			Patch(p2, Pc)
+		} else {
+			Bgen(n.Left, true_, likely, to)
+			Bgen(n.Right, true_, likely, to)
+		}
+
+		return
+
+	case OEQ, ONE, OLT, OGT, OLE, OGE:
+		nr = n.Right
+		if nr == nil || nr.Type == nil {
+			return
+		}
+		fallthrough
+
+	case ONOT: // unary
+		nl = n.Left
+
+		if nl == nil || nl.Type == nil {
+			return
+		}
+	}
+
+	switch n.Op {
+	case ONOT:
+		Bgen(nl, !true_, likely, to)
+		return
+
+	case OEQ, ONE, OLT, OGT, OLE, OGE:
+		a := int(n.Op)
+		if !true_ {
+			if Isfloat[nr.Type.Etype] {
+				// brcom is not valid on floats when NaN is involved.
+				p1 := Gbranch(obj.AJMP, nil, 0)
+				p2 := Gbranch(obj.AJMP, nil, 0)
+				Patch(p1, Pc)
+				ll := n.Ninit // avoid re-genning ninit
+				n.Ninit = nil
+				Bgen(n, true, -likely, p2)
+				n.Ninit = ll
+				Patch(Gbranch(obj.AJMP, nil, 0), to)
+				Patch(p2, Pc)
+				return
+			}
+
+			a = Brcom(a)
+			true_ = !true_
+		}
+
+		// make simplest on right
+		if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
+			a = Brrev(a)
+			r := nl
+			nl = nr
+			nr = r
+		}
+
+		if Isslice(nl.Type) {
+			// front end should only leave cmp to literal nil
+			if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
+				Yyerror("illegal slice comparison")
+				break
+			}
+
+			a = Thearch.Optoas(a, Types[Tptr])
+			var n1 Node
+			Igen(nl, &n1, nil)
+			n1.Xoffset += int64(Array_array)
+			n1.Type = Types[Tptr]
+			var n2 Node
+			Regalloc(&n2, Types[Tptr], &n1)
+			Cgen(&n1, &n2)
+			Regfree(&n1)
+			var tmp Node
+			Nodconst(&tmp, Types[Tptr], 0)
+			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
+			Patch(Gbranch(a, Types[Tptr], likely), to)
+			Regfree(&n2)
+			break
+		}
+
+		if Isinter(nl.Type) {
+			// front end should only leave cmp to literal nil
+			if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
+				Yyerror("illegal interface comparison")
+				break
+			}
+
+			a = Thearch.Optoas(a, Types[Tptr])
+			var n1 Node
+			Igen(nl, &n1, nil)
+			n1.Type = Types[Tptr]
+			var n2 Node
+			Regalloc(&n2, Types[Tptr], &n1)
+			Cgen(&n1, &n2)
+			Regfree(&n1)
+			var tmp Node
+			Nodconst(&tmp, Types[Tptr], 0)
+			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
+			Patch(Gbranch(a, Types[Tptr], likely), to)
+			Regfree(&n2)
+			break
+		}
+
+		if Iscomplex[nl.Type.Etype] {
+			Complexbool(a, nl, nr, true_, likely, to)
+			break
+		}
+
+		if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
+			if nl.Addable == 0 || Isconst(nl, CTINT) {
+				var n1 Node
+				Tempname(&n1, nl.Type)
+				Cgen(nl, &n1)
+				nl = &n1
+			}
+
+			if nr.Addable == 0 {
+				var n2 Node
+				Tempname(&n2, nr.Type)
+				Cgen(nr, &n2)
+				nr = &n2
+			}
+
+			Thearch.Cmp64(nl, nr, a, likely, to)
+			break
+		}
+
+		var n1 Node
+		var n2 Node
+		if nr.Ullman >= UINF {
+			Regalloc(&n1, nl.Type, nil)
+			Cgen(nl, &n1)
+
+			var tmp Node
+			Tempname(&tmp, nl.Type)
+			Thearch.Gmove(&n1, &tmp)
+			Regfree(&n1)
+
+			Regalloc(&n2, nr.Type, nil)
+			Cgen(nr, &n2)
+
+			Regalloc(&n1, nl.Type, nil)
+			Cgen(&tmp, &n1)
+
+			goto cmp
+		}
+
+		if nl.Addable == 0 && Ctxt.Arch.Thechar == '8' {
+			Tempname(&n1, nl.Type)
+		} else {
+			Regalloc(&n1, nl.Type, nil)
+		}
+		Cgen(nl, &n1)
+		nl = &n1
+
+		if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' {
+			Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
+			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
+			if n1.Op == OREGISTER {
+				Regfree(&n1)
+			}
+			break
+		}
+
+		if nr.Addable == 0 && Ctxt.Arch.Thechar == '8' {
+			var tmp Node
+			Tempname(&tmp, nr.Type)
+			Cgen(nr, &tmp)
+			nr = &tmp
+		}
+
+		Regalloc(&n2, nr.Type, nil)
+		Cgen(nr, &n2)
+		nr = &n2
+
+	cmp:
+		l, r := nl, nr
+		// On x86, only < and <= work right with NaN; reverse if needed
+		if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) {
+			l, r = r, l
+			a = Brrev(a)
+		}
+
+		Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
+
+		if Ctxt.Arch.Thechar == '6' && Isfloat[nr.Type.Etype] && (n.Op == OEQ || n.Op == ONE) {
+			if n.Op == OEQ {
+				// neither NE nor P
+				p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely)
+				p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely)
+				Patch(Gbranch(obj.AJMP, nil, 0), to)
+				Patch(p1, Pc)
+				Patch(p2, Pc)
+			} else {
+				// either NE or P
+				Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
+				Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
+			}
+		} else if Ctxt.Arch.Thechar == '5' && Isfloat[nl.Type.Etype] {
+			if n.Op == ONE {
+				Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
+				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
+			} else {
+				p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
+				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
+				Patch(p, Pc)
+			}
+		} else if (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') && Isfloat[nl.Type.Etype] && (a == OLE || a == OGE) {
+			// On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
+			if a == OLE {
+				a = OLT
+			} else {
+				a = OGT
+			}
+			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
+			Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
+		} else {
+			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
+		}
+		if n1.Op == OREGISTER {
+			Regfree(&n1)
+		}
+		if n2.Op == OREGISTER {
+			Regfree(&n2)
+		}
+	}
+
+	return
+
+def:
+	// TODO: Optimize on systems that can compare to zero easily.
+	var n1 Node
+	Regalloc(&n1, n.Type, nil)
+	Cgen(n, &n1)
+	var n2 Node
+	Nodconst(&n2, n.Type, 0)
+	Thearch.Gins(Thearch.Optoas(OCMP, n.Type), &n1, &n2)
+	a := Thearch.Optoas(ONE, n.Type)
+	if !true_ {
+		a = Thearch.Optoas(OEQ, n.Type)
+	}
+	Patch(Gbranch(a, n.Type, likely), to)
+	Regfree(&n1)
+	return
+}
+
+/*
+ * n is on stack, either local variable
+ * or return value from function call.
+ * return n's offset from SP.
+ */
+func stkof(n *Node) int64 {
+	switch n.Op {
+	case OINDREG:
+		return n.Xoffset
+
+	case ODOT:
+		t := n.Left.Type
+		if Isptr[t.Etype] {
+			break
+		}
+		off := stkof(n.Left)
+		if off == -1000 || off == 1000 {
+			return off
+		}
+		return off + n.Xoffset
+
+	case OINDEX:
+		t := n.Left.Type
+		if !Isfixedarray(t) {
+			break
+		}
+		off := stkof(n.Left)
+		if off == -1000 || off == 1000 {
+			return off
+		}
+		if Isconst(n.Right, CTINT) {
+			return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval)
+		}
+		return 1000
+
+	case OCALLMETH, OCALLINTER, OCALLFUNC:
+		t := n.Left.Type
+		if Isptr[t.Etype] {
+			t = t.Type
+		}
+
+		var flist Iter
+		t = Structfirst(&flist, Getoutarg(t))
+		if t != nil {
+			w := t.Width
+			if HasLinkRegister() {
+				w += int64(Ctxt.Arch.Ptrsize)
+			}
+			return w
+		}
+	}
+
+	// botch - probably failing to recognize address
+	// arithmetic on the above. eg INDEX and DOT
+	return -1000
+}
+
+/*
+ * block copy:
+ *	memmove(&ns, &n, w);
+ */
+func sgen(n *Node, ns *Node, w int64) {
+	if Debug['g'] != 0 {
+		fmt.Printf("\nsgen w=%d\n", w)
+		Dump("r", n)
+		Dump("res", ns)
+	}
+
+	if n.Ullman >= UINF && ns.Ullman >= UINF {
+		Fatal("sgen UINF")
+	}
+
+	if w < 0 {
+		Fatal("sgen copy %d", w)
+	}
+
+	// If copying .args, that's all the results, so record definition sites
+	// for them for the liveness analysis.
+	if ns.Op == ONAME && ns.Sym.Name == ".args" {
+		for l := Curfn.Dcl; l != nil; l = l.Next {
+			if l.N.Class == PPARAMOUT {
+				Gvardef(l.N)
+			}
+		}
+	}
+
+	// Avoid taking the address for simple enough types.
+	if Componentgen(n, ns) {
+		return
+	}
+
+	if w == 0 {
+		// evaluate side effects only
+		var nodr Node
+		Regalloc(&nodr, Types[Tptr], nil)
+		Agen(ns, &nodr)
+		Agen(n, &nodr)
+		Regfree(&nodr)
+		return
+	}
+
+	// offset on the stack
+	osrc := stkof(n)
+	odst := stkof(ns)
+
+	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
+		// osrc and odst both on stack, and at least one is in
+		// an unknown position.  Could generate code to test
+		// for forward/backward copy, but instead just copy
+		// to a temporary location first.
+		var tmp Node
+		Tempname(&tmp, n.Type)
+		sgen(n, &tmp, w)
+		sgen(&tmp, ns, w)
+		return
+	}
+
+	Thearch.Stackcopy(n, ns, osrc, odst, w)
+}
+
+/*
+ * generate:
+ *	call f
+ *	proc=-1	normal call but no return
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+  *	proc=3	normal call to C pointer (not Go func value)
+*/
+func Ginscall(f *Node, proc int) {
+	if f.Type != nil {
+		extra := int32(0)
+		if proc == 1 || proc == 2 {
+			extra = 2 * int32(Widthptr)
+		}
+		Setmaxarg(f.Type, extra)
+	}
+
+	switch proc {
+	default:
+		Fatal("Ginscall: bad proc %d", proc)
+
+	case 0, // normal call
+		-1: // normal call but no return
+		if f.Op == ONAME && f.Class == PFUNC {
+			if f == Deferreturn {
+				// Deferred calls will appear to be returning to
+				// the CALL deferreturn(SB) that we are about to emit.
+				// However, the stack trace code will show the line
+				// of the instruction byte before the return PC.
+				// To avoid that being an unrelated instruction,
+				// insert an actual hardware NOP that will have the right line number.
+				// This is different from obj.ANOP, which is a virtual no-op
+				// that doesn't make it into the instruction stream.
+				Thearch.Ginsnop()
+			}
+
+			p := Thearch.Gins(obj.ACALL, nil, f)
+			Afunclit(&p.To, f)
+			if proc == -1 || Noreturn(p) {
+				Thearch.Gins(obj.AUNDEF, nil, nil)
+			}
+			break
+		}
+
+		var reg Node
+		Nodreg(&reg, Types[Tptr], Thearch.REGCTXT)
+		var r1 Node
+		Nodreg(&r1, Types[Tptr], Thearch.REGCALLX)
+		Thearch.Gmove(f, &reg)
+		reg.Op = OINDREG
+		Thearch.Gmove(&reg, &r1)
+		reg.Op = OREGISTER
+		Thearch.Gins(obj.ACALL, &reg, &r1)
+
+	case 3: // normal call of c function pointer
+		Thearch.Gins(obj.ACALL, nil, f)
+
+	case 1, // call in new proc (go)
+		2: // deferred call (defer)
+		var stk Node
+
+		// size of arguments at 0(SP)
+		stk.Op = OINDREG
+		stk.Val.U.Reg = int16(Thearch.REGSP)
+		stk.Xoffset = 0
+		if HasLinkRegister() {
+			stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
+		}
+		Thearch.Ginscon(Thearch.Optoas(OAS, Types[Tptr]), int64(Argsize(f.Type)), &stk)
+
+		// FuncVal* at 8(SP)
+		stk.Xoffset = int64(Widthptr)
+		if HasLinkRegister() {
+			stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
+		}
+
+		var reg Node
+		Nodreg(&reg, Types[Tptr], Thearch.REGCALLX2)
+		Thearch.Gmove(f, &reg)
+		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &reg, &stk)
+
+		if proc == 1 {
+			Ginscall(Newproc, 0)
+		} else {
+			if Hasdefer == 0 {
+				Fatal("hasdefer=0 but has defer")
+			}
+			Ginscall(Deferproc, 0)
+		}
+
+		if proc == 2 {
+			Nodreg(&reg, Types[TINT32], Thearch.REGRETURN)
+			Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), &reg, Nodintconst(0))
+			p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1)
+			cgen_ret(nil)
+			Patch(p, Pc)
+		}
+	}
+}
+
+/*
+ * n is call to interface method.
+ * generate res = n.
+ */
+func cgen_callinter(n *Node, res *Node, proc int) {
+	i := n.Left
+	if i.Op != ODOTINTER {
+		Fatal("cgen_callinter: not ODOTINTER %v", Oconv(int(i.Op), 0))
+	}
+
+	f := i.Right // field
+	if f.Op != ONAME {
+		Fatal("cgen_callinter: not ONAME %v", Oconv(int(f.Op), 0))
+	}
+
+	i = i.Left // interface
+
+	if i.Addable == 0 {
+		var tmpi Node
+		Tempname(&tmpi, i.Type)
+		Cgen(i, &tmpi)
+		i = &tmpi
+	}
+
+	Genlist(n.List) // assign the args
+
+	// i is now addable, prepare an indirected
+	// register to hold its address.
+	var nodi Node
+	Igen(i, &nodi, res) // REG = &inter
+
+	var nodsp Node
+	Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP)
+	nodsp.Xoffset = 0
+	if HasLinkRegister() {
+		nodsp.Xoffset += int64(Ctxt.Arch.Ptrsize)
+	}
+	if proc != 0 {
+		nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn
+	}
+	nodi.Type = Types[Tptr]
+	nodi.Xoffset += int64(Widthptr)
+	Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data
+
+	var nodo Node
+	Regalloc(&nodo, Types[Tptr], res)
+
+	nodi.Type = Types[Tptr]
+	nodi.Xoffset -= int64(Widthptr)
+	Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
+	Regfree(&nodi)
+
+	var nodr Node
+	Regalloc(&nodr, Types[Tptr], &nodo)
+	if n.Left.Xoffset == BADWIDTH {
+		Fatal("cgen_callinter: badwidth")
+	}
+	Cgen_checknil(&nodo) // in case offset is huge
+	nodo.Op = OINDREG
+	nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8
+	if proc == 0 {
+		// plain call: use direct c function pointer - more efficient
+		Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
+		proc = 3
+	} else {
+		// go/defer. generate go func value.
+		Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
+	}
+
+	nodr.Type = n.Left.Type
+	Ginscall(&nodr, proc)
+
+	Regfree(&nodr)
+	Regfree(&nodo)
+}
+
+/*
+ * generate function call;
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+ */
+func cgen_call(n *Node, proc int) {
+	if n == nil {
+		return
+	}
+
+	var afun Node
+	if n.Left.Ullman >= UINF {
+		// if name involves a fn call
+		// precompute the address of the fn
+		Tempname(&afun, Types[Tptr])
+
+		Cgen(n.Left, &afun)
+	}
+
+	Genlist(n.List) // assign the args
+	t := n.Left.Type
+
+	// call tempname pointer
+	if n.Left.Ullman >= UINF {
+		var nod Node
+		Regalloc(&nod, Types[Tptr], nil)
+		Cgen_as(&nod, &afun)
+		nod.Type = t
+		Ginscall(&nod, proc)
+		Regfree(&nod)
+		return
+	}
+
+	// call pointer
+	if n.Left.Op != ONAME || n.Left.Class != PFUNC {
+		var nod Node
+		Regalloc(&nod, Types[Tptr], nil)
+		Cgen_as(&nod, n.Left)
+		nod.Type = t
+		Ginscall(&nod, proc)
+		Regfree(&nod)
+		return
+	}
+
+	// call direct
+	n.Left.Method = 1
+
+	Ginscall(n.Left, proc)
+}
+
+func HasLinkRegister() bool {
+	c := Ctxt.Arch.Thechar
+	return c != '6' && c != '8'
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ *	res = return value from call.
+ */
+func cgen_callret(n *Node, res *Node) {
+	t := n.Left.Type
+	if t.Etype == TPTR32 || t.Etype == TPTR64 {
+		t = t.Type
+	}
+
+	var flist Iter
+	fp := Structfirst(&flist, Getoutarg(t))
+	if fp == nil {
+		Fatal("cgen_callret: nil")
+	}
+
+	var nod Node
+	nod.Op = OINDREG
+	nod.Val.U.Reg = int16(Thearch.REGSP)
+	nod.Addable = 1
+
+	nod.Xoffset = fp.Width
+	if HasLinkRegister() {
+		nod.Xoffset += int64(Ctxt.Arch.Ptrsize)
+	}
+	nod.Type = fp.Type
+	Cgen_as(res, &nod)
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ *	res = &return value from call.
+ */
+func cgen_aret(n *Node, res *Node) {
+	t := n.Left.Type
+	if Isptr[t.Etype] {
+		t = t.Type
+	}
+
+	var flist Iter
+	fp := Structfirst(&flist, Getoutarg(t))
+	if fp == nil {
+		Fatal("cgen_aret: nil")
+	}
+
+	var nod1 Node
+	nod1.Op = OINDREG
+	nod1.Val.U.Reg = int16(Thearch.REGSP)
+	nod1.Addable = 1
+	nod1.Xoffset = fp.Width
+	if HasLinkRegister() {
+		nod1.Xoffset += int64(Ctxt.Arch.Ptrsize)
+	}
+	nod1.Type = fp.Type
+
+	if res.Op != OREGISTER {
+		var nod2 Node
+		Regalloc(&nod2, Types[Tptr], res)
+		Agen(&nod1, &nod2)
+		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res)
+		Regfree(&nod2)
+	} else {
+		Agen(&nod1, res)
+	}
+}
+
+/*
+ * generate return.
+ * n->left is assignments to return values.
+ */
+func cgen_ret(n *Node) {
+	if n != nil {
+		Genlist(n.List) // copy out args
+	}
+	if Hasdefer != 0 {
+		Ginscall(Deferreturn, 0)
+	}
+	Genlist(Curfn.Exit)
+	p := Thearch.Gins(obj.ARET, nil, nil)
+	if n != nil && n.Op == ORETJMP {
+		p.To.Type = obj.TYPE_MEM
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = Linksym(n.Left.Sym)
+	}
+}
+
+/*
+ * generate division according to op, one of:
+ *	res = nl / nr
+ *	res = nl % nr
+ */
+func cgen_div(op int, nl *Node, nr *Node, res *Node) {
+	var w int
+
+	// TODO(rsc): arm64 needs to support the relevant instructions
+	// in peep and optoas in order to enable this.
+	// TODO(rsc): ppc64 needs to support the relevant instructions
+	// in peep and optoas in order to enable this.
+	if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+		goto longdiv
+	}
+	w = int(nl.Type.Width * 8)
+
+	// Front end handled 32-bit division. We only need to handle 64-bit.
+	// try to do division by multiply by (2^w)/d
+	// see hacker's delight chapter 10
+	switch Simtype[nl.Type.Etype] {
+	default:
+		goto longdiv
+
+	case TUINT64:
+		var m Magic
+		m.W = w
+		m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
+		Umagic(&m)
+		if m.Bad != 0 {
+			break
+		}
+		if op == OMOD {
+			goto longmod
+		}
+
+		var n1 Node
+		Cgenr(nl, &n1, nil)
+		var n2 Node
+		Nodconst(&n2, nl.Type, int64(m.Um))
+		var n3 Node
+		Regalloc(&n3, nl.Type, res)
+		Thearch.Cgen_hmul(&n1, &n2, &n3)
+
+		if m.Ua != 0 {
+			// need to add numerator accounting for overflow
+			Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
+
+			Nodconst(&n2, nl.Type, 1)
+			Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3)
+			Nodconst(&n2, nl.Type, int64(m.S)-1)
+			Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3)
+		} else {
+			Nodconst(&n2, nl.Type, int64(m.S))
+			Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx
+		}
+
+		Thearch.Gmove(&n3, res)
+		Regfree(&n1)
+		Regfree(&n3)
+		return
+
+	case TINT64:
+		var m Magic
+		m.W = w
+		m.Sd = Mpgetfix(nr.Val.U.Xval)
+		Smagic(&m)
+		if m.Bad != 0 {
+			break
+		}
+		if op == OMOD {
+			goto longmod
+		}
+
+		var n1 Node
+		Cgenr(nl, &n1, res)
+		var n2 Node
+		Nodconst(&n2, nl.Type, m.Sm)
+		var n3 Node
+		Regalloc(&n3, nl.Type, nil)
+		Thearch.Cgen_hmul(&n1, &n2, &n3)
+
+		if m.Sm < 0 {
+			// need to add numerator
+			Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
+		}
+
+		Nodconst(&n2, nl.Type, int64(m.S))
+		Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3
+
+		Nodconst(&n2, nl.Type, int64(w)-1)
+
+		Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg
+		Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added
+
+		if m.Sd < 0 {
+			// this could probably be removed
+			// by factoring it into the multiplier
+			Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3)
+		}
+
+		Thearch.Gmove(&n3, res)
+		Regfree(&n1)
+		Regfree(&n3)
+		return
+	}
+
+	goto longdiv
+
+	// division and mod using (slow) hardware instruction
+longdiv:
+	Thearch.Dodiv(op, nl, nr, res)
+
+	return
+
+	// mod using formula A%B = A-(A/B*B) but
+	// we know that there is a fast algorithm for A/B
+longmod:
+	var n1 Node
+	Regalloc(&n1, nl.Type, res)
+
+	Cgen(nl, &n1)
+	var n2 Node
+	Regalloc(&n2, nl.Type, nil)
+	cgen_div(ODIV, &n1, nr, &n2)
+	a := Thearch.Optoas(OMUL, nl.Type)
+	if w == 8 {
+		// use 2-operand 16-bit multiply
+		// because there is no 2-operand 8-bit multiply
+		a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW
+	}
+
+	if !Smallintconst(nr) {
+		var n3 Node
+		Regalloc(&n3, nl.Type, nil)
+		Cgen(nr, &n3)
+		Thearch.Gins(a, &n3, &n2)
+		Regfree(&n3)
+	} else {
+		Thearch.Gins(a, nr, &n2)
+	}
+	Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1)
+	Thearch.Gmove(&n1, res)
+	Regfree(&n1)
+	Regfree(&n2)
+}
+
+func Fixlargeoffset(n *Node) {
+	if n == nil {
+		return
+	}
+	if n.Op != OINDREG {
+		return
+	}
+	if n.Val.U.Reg == int16(Thearch.REGSP) { // stack offset cannot be large
+		return
+	}
+	if n.Xoffset != int64(int32(n.Xoffset)) {
+		// offset too large, add to register instead.
+		a := *n
+
+		a.Op = OREGISTER
+		a.Type = Types[Tptr]
+		a.Xoffset = 0
+		Cgen_checknil(&a)
+		Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a)
+		n.Xoffset = 0
+	}
+}
diff --git a/src/cmd/internal/gc/cplx.go b/src/cmd/internal/gc/cplx.go
index 0097571..7c0a150 100644
--- a/src/cmd/internal/gc/cplx.go
+++ b/src/cmd/internal/gc/cplx.go
@@ -25,21 +25,21 @@
 	if nr != nil {
 		if nl.Ullman > nr.Ullman && nl.Addable == 0 {
 			Tempname(&tnl, nl.Type)
-			Thearch.Cgen(nl, &tnl)
+			Cgen(nl, &tnl)
 			nl = &tnl
 		}
 
 		if nr.Addable == 0 {
 			var tnr Node
 			Tempname(&tnr, nr.Type)
-			Thearch.Cgen(nr, &tnr)
+			Cgen(nr, &tnr)
 			nr = &tnr
 		}
 	}
 
 	if nl.Addable == 0 {
 		Tempname(&tnl, nl.Type)
-		Thearch.Cgen(nl, &tnl)
+		Cgen(nl, &tnl)
 		nl = &tnl
 	}
 
@@ -78,7 +78,7 @@
 		true_ = !true_
 	}
 
-	Thearch.Bgen(&na, true_, likely, to)
+	Bgen(&na, true_, likely, to)
 }
 
 // break addable nc-complex into nr-real and ni-imaginary
@@ -111,7 +111,7 @@
 	ra.Op = OMINUS
 	ra.Left = nl
 	ra.Type = nl.Type
-	Thearch.Cgen(&ra, res)
+	Cgen(&ra, res)
 }
 
 // build and execute tree
@@ -150,14 +150,14 @@
 	ra.Left = &n1
 	ra.Right = &n3
 	ra.Type = n1.Type
-	Thearch.Cgen(&ra, &n5)
+	Cgen(&ra, &n5)
 
 	ra = Node{}
 	ra.Op = uint8(op)
 	ra.Left = &n2
 	ra.Right = &n4
 	ra.Type = n2.Type
-	Thearch.Cgen(&ra, &n6)
+	Cgen(&ra, &n6)
 }
 
 // build and execute tree
@@ -197,7 +197,7 @@
 	ra.Left = &rm1
 	ra.Right = &rm2
 	ra.Type = rm1.Type
-	Thearch.Cgen(&ra, &tmp)
+	Cgen(&ra, &tmp)
 
 	// imag part
 	rm1 = Node{}
@@ -218,10 +218,10 @@
 	ra.Left = &rm1
 	ra.Right = &rm2
 	ra.Type = rm1.Type
-	Thearch.Cgen(&ra, &n6)
+	Cgen(&ra, &n6)
 
 	// tmp ->real part
-	Thearch.Cgen(&tmp, &n5)
+	Cgen(&tmp, &n5)
 }
 
 func nodfconst(n *Node, t *Type, fval *Mpflt) {
@@ -322,8 +322,8 @@
 		var n3 Node
 		subnode(&n3, &n4, t)
 
-		Thearch.Cgen(&n1, &n3)
-		Thearch.Cgen(&n2, &n4)
+		Cgen(&n1, &n3)
+		Cgen(&n2, &n4)
 	}
 }
 
@@ -346,9 +346,9 @@
 			subnode(&n1, &n2, res)
 			var tmp Node
 			Tempname(&tmp, n1.Type)
-			Thearch.Cgen(n.Left, &tmp)
-			Thearch.Cgen(n.Right, &n2)
-			Thearch.Cgen(&tmp, &n1)
+			Cgen(n.Left, &tmp)
+			Cgen(n.Right, &n2)
+			Cgen(&tmp, &n1)
 			return
 		}
 
@@ -366,11 +366,11 @@
 		var n2 Node
 		subnode(&n1, &n2, nl)
 		if n.Op == OREAL {
-			Thearch.Cgen(&n1, res)
+			Cgen(&n1, res)
 			return
 		}
 
-		Thearch.Cgen(&n2, res)
+		Cgen(&n2, res)
 		return
 	}
 
@@ -394,9 +394,9 @@
 
 	if res.Addable == 0 {
 		var n1 Node
-		Thearch.Igen(res, &n1, nil)
-		Thearch.Cgen(n, &n1)
-		Thearch.Regfree(&n1)
+		Igen(res, &n1, nil)
+		Cgen(n, &n1)
+		Regfree(&n1)
 		return
 	}
 
@@ -419,10 +419,10 @@
 		OCALLMETH,
 		OCALLINTER:
 		var n1 Node
-		Thearch.Igen(n, &n1, res)
+		Igen(n, &n1, res)
 
 		Complexmove(&n1, res)
-		Thearch.Regfree(&n1)
+		Regfree(&n1)
 		return
 
 	case OCONV,
@@ -447,21 +447,21 @@
 	if nr != nil {
 		if nl.Ullman > nr.Ullman && nl.Addable == 0 {
 			Tempname(&tnl, nl.Type)
-			Thearch.Cgen(nl, &tnl)
+			Cgen(nl, &tnl)
 			nl = &tnl
 		}
 
 		if nr.Addable == 0 {
 			var tnr Node
 			Tempname(&tnr, nr.Type)
-			Thearch.Cgen(nr, &tnr)
+			Cgen(nr, &tnr)
 			nr = &tnr
 		}
 	}
 
 	if nl.Addable == 0 {
 		Tempname(&tnl, nl.Type)
-		Thearch.Cgen(nl, &tnl)
+		Cgen(nl, &tnl)
 		nl = &tnl
 	}
 
diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go
index 314f6c1..9686092 100644
--- a/src/cmd/internal/gc/gen.go
+++ b/src/cmd/internal/gc/gen.go
@@ -235,13 +235,13 @@
 		Fatal("cgen_proc: unknown call %v", Oconv(int(n.Left.Op), 0))
 
 	case OCALLMETH:
-		Cgen_callmeth(n.Left, proc)
+		cgen_callmeth(n.Left, proc)
 
 	case OCALLINTER:
-		Thearch.Cgen_callinter(n.Left, nil, proc)
+		cgen_callinter(n.Left, nil, proc)
 
 	case OCALLFUNC:
-		Thearch.Cgen_call(n.Left, proc)
+		cgen_call(n.Left, proc)
 	}
 }
 
@@ -377,7 +377,7 @@
 	}
 
 	ullmancalc(&z)
-	Thearch.Cgen(&z, n)
+	Cgen(&z, n)
 }
 
 /*
@@ -393,17 +393,17 @@
 	 */
 
 	tmp := temp(Types[Tptr])
-	Thearch.Cgen(n.Right, tmp)
+	Cgen(n.Right, tmp)
 
 	Gvardef(res)
 
 	dst := *res
 	dst.Type = Types[Tptr]
 	dst.Xoffset += int64(Widthptr)
-	Thearch.Cgen(tmp, &dst)
+	Cgen(tmp, &dst)
 
 	dst.Xoffset -= int64(Widthptr)
-	Thearch.Cgen(n.Left, &dst)
+	Cgen(n.Left, &dst)
 }
 
 /*
@@ -443,7 +443,7 @@
 	var src Node
 	if isnil(n.Left) {
 		Tempname(&src, n.Left.Type)
-		Thearch.Cgen(n.Left, &src)
+		Cgen(n.Left, &src)
 	} else {
 		src = *n.Left
 	}
@@ -455,11 +455,11 @@
 		if !Isptr[n.Left.Type.Etype] {
 			Fatal("slicearr is supposed to work on pointer: %v\n", Nconv(n, obj.FmtSign))
 		}
-		Thearch.Cgen(&src, base)
+		Cgen(&src, base)
 		Cgen_checknil(base)
 	} else {
 		src.Type = Types[Tptr]
-		Thearch.Cgen(&src, base)
+		Cgen(&src, base)
 	}
 
 	// committed to the update
@@ -468,10 +468,10 @@
 	// compute len and cap.
 	// len = n-i, cap = m-i, and offs = i*width.
 	// computing offs last lets the multiply overwrite i.
-	Thearch.Cgen((*Node)(len), tmplen)
+	Cgen((*Node)(len), tmplen)
 
 	if n.Op != OSLICESTR {
-		Thearch.Cgen(cap, tmpcap)
+		Cgen(cap, tmpcap)
 	}
 
 	// if new cap != 0 { base += add }
@@ -489,11 +489,11 @@
 		Nodconst(&con, tmpcap.Type, 0)
 		cmp := Nod(OEQ, tmpcap, &con)
 		typecheck(&cmp, Erv)
-		Thearch.Bgen(cmp, true, -1, p2)
+		Bgen(cmp, true, -1, p2)
 
 		add := Nod(OADD, base, offs)
 		typecheck(&add, Erv)
-		Thearch.Cgen(add, base)
+		Cgen(add, base)
 
 		Patch(p2, Pc)
 	}
@@ -503,14 +503,14 @@
 
 	dst.Xoffset += int64(Array_array)
 	dst.Type = Types[Tptr]
-	Thearch.Cgen(base, &dst)
+	Cgen(base, &dst)
 
 	// dst.len = hi [ - lo ]
 	dst = *res
 
 	dst.Xoffset += int64(Array_nel)
 	dst.Type = Types[Simtype[TUINT]]
-	Thearch.Cgen(tmplen, &dst)
+	Cgen(tmplen, &dst)
 
 	if n.Op != OSLICESTR {
 		// dst.cap = cap [ - lo ]
@@ -518,7 +518,7 @@
 
 		dst.Xoffset += int64(Array_cap)
 		dst.Type = Types[Simtype[TUINT]]
-		Thearch.Cgen(tmpcap, &dst)
+		Cgen(tmpcap, &dst)
 	}
 }
 
@@ -620,7 +620,7 @@
 
 	lno := setlineno(n)
 
-	wasregalloc := Thearch.Anyregalloc()
+	wasregalloc := Anyregalloc()
 
 	if n == nil {
 		goto ret
@@ -760,10 +760,10 @@
 			lab.Continpc = continpc
 		}
 
-		gen(n.Nincr)                              // contin:	incr
-		Patch(p1, Pc)                             // test:
-		Thearch.Bgen(n.Ntest, false, -1, breakpc) //		if(!test) goto break
-		Genlist(n.Nbody)                          //		body
+		gen(n.Nincr)                      // contin:	incr
+		Patch(p1, Pc)                     // test:
+		Bgen(n.Ntest, false, -1, breakpc) //		if(!test) goto break
+		Genlist(n.Nbody)                  //		body
 		gjmp(continpc)
 		Patch(breakpc, Pc) // done:
 		continpc = scontin
@@ -774,15 +774,15 @@
 		}
 
 	case OIF:
-		p1 := gjmp(nil)                                  //		goto test
-		p2 := gjmp(nil)                                  // p2:		goto else
-		Patch(p1, Pc)                                    // test:
-		Thearch.Bgen(n.Ntest, false, int(-n.Likely), p2) //		if(!test) goto p2
-		Genlist(n.Nbody)                                 //		then
-		p3 := gjmp(nil)                                  //		goto done
-		Patch(p2, Pc)                                    // else:
-		Genlist(n.Nelse)                                 //		else
-		Patch(p3, Pc)                                    // done:
+		p1 := gjmp(nil)                          //		goto test
+		p2 := gjmp(nil)                          // p2:		goto else
+		Patch(p1, Pc)                            // test:
+		Bgen(n.Ntest, false, int(-n.Likely), p2) //		if(!test) goto p2
+		Genlist(n.Nbody)                         //		then
+		p3 := gjmp(nil)                          //		goto done
+		Patch(p2, Pc)                            // else:
+		Genlist(n.Nelse)                         //		else
+		Patch(p3, Pc)                            // done:
 
 	case OSWITCH:
 		sbreak := breakpc
@@ -832,13 +832,13 @@
 		Cgen_as(n.Left, n.Right)
 
 	case OCALLMETH:
-		Cgen_callmeth(n, 0)
+		cgen_callmeth(n, 0)
 
 	case OCALLINTER:
-		Thearch.Cgen_callinter(n, nil, 0)
+		cgen_callinter(n, nil, 0)
 
 	case OCALLFUNC:
-		Thearch.Cgen_call(n, 0)
+		cgen_call(n, 0)
 
 	case OPROC:
 		cgen_proc(n, 1)
@@ -848,7 +848,7 @@
 
 	case ORETURN,
 		ORETJMP:
-		Thearch.Cgen_ret(n)
+		cgen_ret(n)
 
 	case OCHECKNIL:
 		Cgen_checknil(n.Left)
@@ -858,7 +858,7 @@
 	}
 
 ret:
-	if Thearch.Anyregalloc() != wasregalloc {
+	if Anyregalloc() != wasregalloc {
 		Dump("node", n)
 		Fatal("registers left allocated")
 	}
@@ -908,10 +908,10 @@
 		return
 	}
 
-	Thearch.Cgen(nr, nl)
+	Cgen(nr, nl)
 }
 
-func Cgen_callmeth(n *Node, proc int) {
+func cgen_callmeth(n *Node, proc int) {
 	// generate a rewrite in n2 for the method call
 	// (p.f)(...) goes to (f)(p,...)
 
@@ -929,7 +929,7 @@
 	if n2.Left.Op == ONAME {
 		n2.Left.Class = PFUNC
 	}
-	Thearch.Cgen_call(&n2, proc)
+	cgen_call(&n2, proc)
 }
 
 func checklabels() {
@@ -1020,14 +1020,14 @@
 		if nr != nil && !cadable(nr) {
 			goto no
 		}
-		Thearch.Igen(nl, &nodl, nil)
+		Igen(nl, &nodl, nil)
 		freel = 1
 	}
 
 	if nr != nil {
 		nodr = *nr
 		if !cadable(nr) {
-			Thearch.Igen(nr, &nodr, nil)
+			Igen(nr, &nodr, nil)
 			freer = 1
 		}
 	} else {
@@ -1035,7 +1035,7 @@
 		var tmp Node
 		Nodconst(&tmp, nl.Type, 0)
 
-		Thearch.Regalloc(&nodr, Types[TUINT], nil)
+		Regalloc(&nodr, Types[TUINT], nil)
 		Thearch.Gmove(&tmp, &nodr)
 		freer = 1
 	}
@@ -1190,19 +1190,19 @@
 
 no:
 	if freer != 0 {
-		Thearch.Regfree(&nodr)
+		Regfree(&nodr)
 	}
 	if freel != 0 {
-		Thearch.Regfree(&nodl)
+		Regfree(&nodl)
 	}
 	return false
 
 yes:
 	if freer != 0 {
-		Thearch.Regfree(&nodr)
+		Regfree(&nodr)
 	}
 	if freel != 0 {
-		Thearch.Regfree(&nodl)
+		Regfree(&nodl)
 	}
 	return true
 }
diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go
index 26f545a..c33664f 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/internal/gc/go.go
@@ -777,47 +777,60 @@
 )
 
 type Arch struct {
-	Thechar        int
-	Thestring      string
-	Thelinkarch    *obj.LinkArch
-	Typedefs       []Typedef
-	REGSP          int
-	REGCTXT        int
-	MAXWIDTH       int64
-	Anyregalloc    func() bool
-	Betypeinit     func()
-	Bgen           func(*Node, bool, int, *obj.Prog)
-	Cgen           func(*Node, *Node)
-	Cgen_call      func(*Node, int)
-	Cgen_callinter func(*Node, *Node, int)
-	Cgen_ret       func(*Node)
-	Clearfat       func(*Node)
-	Defframe       func(*obj.Prog)
-	Excise         func(*Flow)
-	Expandchecks   func(*obj.Prog)
-	Gclean         func()
-	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)
-	Proginfo       func(*obj.Prog) // fills in Prog.Info
-	Regalloc       func(*Node, *Type, *Node)
-	Regfree        func(*Node)
-	Regtyp         func(*obj.Addr) bool
-	Sameaddr       func(*obj.Addr, *obj.Addr) bool
-	Smallindir     func(*obj.Addr, *obj.Addr) bool
-	Stackaddr      func(*obj.Addr) bool
-	Excludedregs   func() uint64
-	RtoB           func(int) uint64
-	FtoB           func(int) uint64
-	BtoR           func(uint64) int
-	BtoF           func(uint64) int
-	Optoas         func(int, *Type) int
-	Doregbits      func(int) uint64
-	Regnames       func(*int) []string
+	Thechar      int
+	Thestring    string
+	Thelinkarch  *obj.LinkArch
+	Typedefs     []Typedef
+	REGSP        int
+	REGCTXT      int
+	REGCALLX     int // BX
+	REGCALLX2    int // AX
+	REGRETURN    int // AX
+	REGMIN       int
+	REGMAX       int
+	FREGMIN      int
+	FREGMAX      int
+	MAXWIDTH     int64
+	ReservedRegs []int
+
+	AddIndex     func(*Node, int64, *Node) bool // optional
+	Betypeinit   func()
+	Bgen_float   func(*Node, int, int, *obj.Prog) // optional
+	Cgen64       func(*Node, *Node)               // only on 32-bit systems
+	Cgenindex    func(*Node, *Node, bool) *obj.Prog
+	Cgen_bmul    func(int, *Node, *Node, *Node) bool
+	Cgen_float   func(*Node, *Node) // optional
+	Cgen_hmul    func(*Node, *Node, *Node)
+	Cgen_shift   func(int, bool, *Node, *Node, *Node)
+	Clearfat     func(*Node)
+	Cmp64        func(*Node, *Node, int, int, *obj.Prog) // only on 32-bit systems
+	Defframe     func(*obj.Prog)
+	Dodiv        func(int, *Node, *Node, *Node)
+	Excise       func(*Flow)
+	Expandchecks func(*obj.Prog)
+	Gins         func(int, *Node, *Node) *obj.Prog
+	Ginscon      func(int, int64, *Node)
+	Ginsnop      func()
+	Gmove        func(*Node, *Node)
+	Igenindex    func(*Node, *Node, bool) *obj.Prog
+	Linkarchinit func()
+	Peep         func(*obj.Prog)
+	Proginfo     func(*obj.Prog) // fills in Prog.Info
+	Regtyp       func(*obj.Addr) bool
+	Sameaddr     func(*obj.Addr, *obj.Addr) bool
+	Smallindir   func(*obj.Addr, *obj.Addr) bool
+	Stackaddr    func(*obj.Addr) bool
+	Stackcopy    func(*Node, *Node, int64, int64, int64)
+	Sudoaddable  func(int, *Node, *obj.Addr) bool
+	Sudoclean    func()
+	Excludedregs func() uint64
+	RtoB         func(int) uint64
+	FtoB         func(int) uint64
+	BtoR         func(uint64) int
+	BtoF         func(uint64) int
+	Optoas       func(int, *Type) int
+	Doregbits    func(int) uint64
+	Regnames     func(*int) []string
 }
 
 var pcloc int32
diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/internal/gc/gsubr.go
index f5d7621..05642d6 100644
--- a/src/cmd/internal/gc/gsubr.go
+++ b/src/cmd/internal/gc/gsubr.go
@@ -30,7 +30,12 @@
 
 package gc
 
-import "cmd/internal/obj"
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"runtime"
+	"strings"
+)
 
 var ddumped int
 
@@ -295,6 +300,8 @@
 	switch n.Op {
 	default:
 		a := a // copy to let escape into Ctxt.Dconv
+		Debug['h'] = 1
+		Dump("naddr", n)
 		Fatal("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a))
 
 	case OREGISTER:
@@ -559,11 +566,8 @@
 		n.Op = OINDREG
 
 		n.Val.U.Reg = int16(Thearch.REGSP)
-		if Thearch.Thechar == '5' {
-			n.Xoffset += 4
-		}
-		if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
-			n.Xoffset += 8
+		if HasLinkRegister() {
+			n.Xoffset += int64(Ctxt.Arch.Ptrsize)
 		}
 
 	case 1: // input arg
@@ -571,10 +575,6 @@
 
 	case 2: // offset output arg
 		Fatal("shouldn't be used")
-
-		n.Op = OINDREG
-		n.Val.U.Reg = int16(Thearch.REGSP)
-		n.Xoffset += Types[Tptr].Width
 	}
 
 	n.Typecheck = 1
@@ -598,3 +598,228 @@
 	p.To.Offset = 0
 	return q
 }
+
+var reg [100]int       // count of references to reg
+var regstk [100][]byte // allocation sites, when -v is given
+
+func ginit() {
+	for r := range reg {
+		reg[r] = 1
+	}
+
+	for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
+		reg[r-Thearch.REGMIN] = 0
+	}
+	for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
+		reg[r-Thearch.REGMIN] = 0
+	}
+
+	for _, r := range Thearch.ReservedRegs {
+		reg[r-Thearch.REGMIN] = 1
+	}
+}
+
+func gclean() {
+	for _, r := range Thearch.ReservedRegs {
+		reg[r-Thearch.REGMIN]--
+	}
+
+	for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
+		n := reg[r-Thearch.REGMIN]
+		if n != 0 {
+			Yyerror("reg %v left allocated", obj.Rconv(r))
+			if Debug['v'] != 0 {
+				Regdump()
+			}
+		}
+	}
+
+	for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
+		n := reg[r-Thearch.REGMIN]
+		if n != 0 {
+			Yyerror("reg %v left allocated", obj.Rconv(r))
+			if Debug['v'] != 0 {
+				Regdump()
+			}
+		}
+	}
+}
+
+func Anyregalloc() bool {
+	n := 0
+	for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
+		if reg[r-Thearch.REGMIN] == 0 {
+			n++
+		}
+	}
+	return n > len(Thearch.ReservedRegs)
+}
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o may be reusable register.
+ * caller must Regfree(n).
+ */
+func Regalloc(n *Node, t *Type, o *Node) {
+	if t == nil {
+		Fatal("regalloc: t nil")
+	}
+	et := int(Simtype[t.Etype])
+	if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) {
+		Fatal("regalloc 64bit")
+	}
+
+	var i int
+Switch:
+	switch et {
+	default:
+		Fatal("regalloc: unknown type %v", Tconv(t, 0))
+
+	case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL:
+		if o != nil && o.Op == OREGISTER {
+			i = int(o.Val.U.Reg)
+			if Thearch.REGMIN <= i && i <= Thearch.REGMAX {
+				break Switch
+			}
+		}
+		for i = Thearch.REGMIN; i <= Thearch.REGMAX; i++ {
+			if reg[i-Thearch.REGMIN] == 0 {
+				break Switch
+			}
+		}
+		Flusherrors()
+		Regdump()
+		Fatal("out of fixed registers")
+
+	case TFLOAT32, TFLOAT64:
+		if o != nil && o.Op == OREGISTER {
+			i = int(o.Val.U.Reg)
+			if Thearch.FREGMIN <= i && i <= Thearch.FREGMAX {
+				break Switch
+			}
+		}
+		for i = Thearch.FREGMIN; i <= Thearch.FREGMAX; i++ {
+			if reg[i-Thearch.REGMIN] == 0 { // note: REGMIN, not FREGMIN
+				break Switch
+			}
+		}
+		Flusherrors()
+		Regdump()
+		Fatal("out of floating registers")
+
+	case TCOMPLEX64, TCOMPLEX128:
+		Tempname(n, t)
+		return
+	}
+
+	ix := i - Thearch.REGMIN
+	if reg[ix] == 0 && Debug['v'] > 0 {
+		if regstk[ix] == nil {
+			regstk[ix] = make([]byte, 4096)
+		}
+		stk := regstk[ix]
+		n := runtime.Stack(stk[:cap(stk)], false)
+		regstk[ix] = stk[:n]
+	}
+	reg[ix]++
+	Nodreg(n, t, i)
+}
+
+func Regfree(n *Node) {
+	if n.Op == ONAME {
+		return
+	}
+	if n.Op != OREGISTER && n.Op != OINDREG {
+		Fatal("regfree: not a register")
+	}
+	i := int(n.Val.U.Reg)
+	if i == Thearch.REGSP {
+		return
+	}
+	switch {
+	case Thearch.REGMIN <= i && i <= Thearch.REGMAX,
+		Thearch.FREGMIN <= i && i <= Thearch.FREGMAX:
+		// ok
+	default:
+		Fatal("regfree: reg out of range")
+	}
+
+	i -= Thearch.REGMIN
+	if reg[i] <= 0 {
+		Fatal("regfree: reg not allocated")
+	}
+	reg[i]--
+	if reg[i] == 0 {
+		regstk[i] = regstk[i][:0]
+	}
+}
+
+// Reginuse reports whether r is in use.
+func Reginuse(r int) bool {
+	switch {
+	case Thearch.REGMIN <= r && r <= Thearch.REGMAX,
+		Thearch.FREGMIN <= r && r <= Thearch.FREGMAX:
+		// ok
+	default:
+		Fatal("reginuse: reg out of range")
+	}
+
+	return reg[r-Thearch.REGMIN] > 0
+}
+
+// Regrealloc(n) undoes the effect of Regfree(n),
+// so that a register can be given up but then reclaimed.
+func Regrealloc(n *Node) {
+	if n.Op != OREGISTER && n.Op != OINDREG {
+		Fatal("regrealloc: not a register")
+	}
+	i := int(n.Val.U.Reg)
+	if i == Thearch.REGSP {
+		return
+	}
+	switch {
+	case Thearch.REGMIN <= i && i <= Thearch.REGMAX,
+		Thearch.FREGMIN <= i && i <= Thearch.FREGMAX:
+		// ok
+	default:
+		Fatal("regrealloc: reg out of range")
+	}
+
+	i -= Thearch.REGMIN
+	if reg[i] == 0 && Debug['v'] > 0 {
+		if regstk[i] == nil {
+			regstk[i] = make([]byte, 4096)
+		}
+		stk := regstk[i]
+		n := runtime.Stack(stk[:cap(stk)], false)
+		regstk[i] = stk[:n]
+	}
+	reg[i]++
+}
+
+func Regdump() {
+	if Debug['v'] == 0 {
+		fmt.Printf("run compiler with -v for register allocation sites\n")
+		return
+	}
+
+	dump := func(r int) {
+		stk := regstk[r-Thearch.REGMIN]
+		if len(stk) == 0 {
+			return
+		}
+		fmt.Printf("reg %v allocated at:\n", obj.Rconv(r))
+		fmt.Printf("\t%s\n", strings.Replace(strings.TrimSpace(string(stk)), "\n", "\n\t", -1))
+	}
+
+	for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
+		if reg[r-Thearch.REGMIN] != 0 {
+			dump(r)
+		}
+	}
+	for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
+		if reg[r-Thearch.REGMIN] == 0 {
+			dump(r)
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/pgen.go b/src/cmd/internal/gc/pgen.go
index ab55911..de106ad 100644
--- a/src/cmd/internal/gc/pgen.go
+++ b/src/cmd/internal/gc/pgen.go
@@ -335,10 +335,10 @@
 
 	if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || n.Addable == 0 || n.Op == OLITERAL {
 		var reg Node
-		Thearch.Regalloc(&reg, Types[Tptr], n)
-		Thearch.Cgen(n, &reg)
+		Regalloc(&reg, Types[Tptr], n)
+		Cgen(n, &reg)
 		Thearch.Gins(obj.ACHECKNIL, &reg, nil)
-		Thearch.Regfree(&reg)
+		Regfree(&reg)
 		return
 	}
 
@@ -458,7 +458,7 @@
 
 	Afunclit(&ptxt.From, Curfn.Nname)
 
-	Thearch.Ginit()
+	ginit()
 
 	gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
 	gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
@@ -484,7 +484,7 @@
 
 	Genlist(Curfn.Enter)
 	Genlist(Curfn.Nbody)
-	Thearch.Gclean()
+	gclean()
 	checklabels()
 	if nerrors != 0 {
 		goto ret
@@ -494,13 +494,13 @@
 	}
 
 	if Curfn.Type.Outtuple != 0 {
-		Thearch.Ginscall(throwreturn, 0)
+		Ginscall(throwreturn, 0)
 	}
 
-	Thearch.Ginit()
+	ginit()
 
 	// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
-	Thearch.Cgen_ret(nil)
+	cgen_ret(nil)
 
 	if Hasdefer != 0 {
 		// deferreturn pretends to have one uintptr argument.
@@ -510,7 +510,7 @@
 		}
 	}
 
-	Thearch.Gclean()
+	gclean()
 	if nerrors != 0 {
 		goto ret
 	}
diff --git a/src/cmd/internal/gc/popt.go b/src/cmd/internal/gc/popt.go
index ac6dd5e..2428284 100644
--- a/src/cmd/internal/gc/popt.go
+++ b/src/cmd/internal/gc/popt.go
@@ -924,8 +924,6 @@
 // Assume that stack variables with address not taken can be loaded multiple times
 // from memory without being rechecked. Other variables need to be checked on
 // each load.
-type NilVar struct {
-}
 
 var killed int // f->data is either nil or &killed
 
diff --git a/src/cmd/internal/gc/reg.go b/src/cmd/internal/gc/reg.go
index 37fd3c3..5546960 100644
--- a/src/cmd/internal/gc/reg.go
+++ b/src/cmd/internal/gc/reg.go
@@ -1344,7 +1344,7 @@
 		}
 	}
 
-	if Debug['v'] != 0 && strings.Contains(Curfn.Nname.Sym.Name, "Parse") {
+	if false && Debug['v'] != 0 && strings.Contains(Curfn.Nname.Sym.Name, "Parse") {
 		Warn("regions: %d\n", nregion)
 	}
 	if nregion >= MaxRgn {
diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go
index ac7c285..1c84aa1 100644
--- a/src/cmd/internal/gc/syntax.go
+++ b/src/cmd/internal/gc/syntax.go
@@ -294,6 +294,7 @@
 	OLROT   // left rotate: AROL.
 	ORROTC  // right rotate-carry: ARCR.
 	ORETJMP // return to other function
+	OPS     // compare parity set (for x86 NaN check)
 
 	OEND
 )
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index d8f39fe..05bf679 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -232,6 +232,7 @@
 	{ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
 	{AB, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
 	{ABL, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
+	{ABL, C_REG, C_NONE, C_REG, 6, 4, 0, 0, 0},
 	{ABL, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
 	{obj.ARET, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
 	{obj.ARET, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
diff --git a/src/cmd/internal/obj/go.go b/src/cmd/internal/obj/go.go
index 496a5b8..2b65ee6 100644
--- a/src/cmd/internal/obj/go.go
+++ b/src/cmd/internal/obj/go.go
@@ -49,7 +49,7 @@
 	os.Exit(2)
 }
 
-func linksetexp() {
+func init() {
 	for _, f := range strings.Split(goexperiment, ",") {
 		if f != "" {
 			addexp(f)
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 410ed84..ca3ffc1 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -123,8 +123,6 @@
 }
 
 func Linknew(arch *LinkArch) *Link {
-	linksetexp()
-
 	ctxt := new(Link)
 	ctxt.Hash = make(map[SymVer]*LSym)
 	ctxt.Arch = arch
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 6a0baa6..58b1c30 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -190,6 +190,18 @@
 		}
 	}
 
+	// Rewrite MOVL/MOVQ $XXX(FP/SP) as LEAL/LEAQ.
+	if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Thechar == '6' || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
+		switch p.As {
+		case AMOVL:
+			p.As = ALEAL
+			p.From.Type = obj.TYPE_MEM
+		case AMOVQ:
+			p.As = ALEAQ
+			p.From.Type = obj.TYPE_MEM
+		}
+	}
+
 	if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
 		nacladdr(ctxt, p, &p.From3)
 		nacladdr(ctxt, p, &p.From)