cmd: add new common architecture representation

Information about CPU architectures (e.g., name, family, byte
ordering, pointer and register size) is currently redundantly
scattered around the source tree. Instead consolidate the basic
information into a single new package cmd/internal/sys.

Also, introduce new sys.I386, sys.AMD64, etc. names for the constants
'8', '6', etc. and replace most uses of the latter. The notable
exceptions are a couple of error messages that still refer to the old
char-based toolchain names and function reltype in cmd/link.

Passes toolstash/buildall.

Change-Id: I8a6f0cbd49577ec1672a98addebc45f767e36461
Reviewed-on: https://go-review.googlesource.com/21623
Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go
index 14721ea..461ef2a 100644
--- a/src/cmd/compile/internal/amd64/galign.go
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -18,12 +18,7 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
 	if obj.Getgoarch() == "amd64p32" {
-		gc.Widthptr = 4
-		gc.Widthint = 4
 		addptr = x86.AADDL
 		movptr = x86.AMOVL
 		leaptr = x86.ALEAL
@@ -42,12 +37,9 @@
 		resvd = append(resvd, x86.REG_BP)
 	}
 
-	gc.Thearch.Thechar = '6'
-	gc.Thearch.Thestring = "amd64"
-	gc.Thearch.Thelinkarch = &x86.Linkamd64
+	gc.Thearch.LinkArch = &x86.Linkamd64
 	if obj.Getgoarch() == "amd64p32" {
-		gc.Thearch.Thestring = "amd64p32"
-		gc.Thearch.Thelinkarch = &x86.Linkamd64p32
+		gc.Thearch.LinkArch = &x86.Linkamd64p32
 	}
 	gc.Thearch.REGSP = x86.REGSP
 	gc.Thearch.REGCTXT = x86.REGCTXT
diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go
index e05f4d0..afd86e4 100644
--- a/src/cmd/compile/internal/arm/galign.go
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -11,15 +11,10 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 4
-	gc.Widthint = 4
-	gc.Widthreg = 4
 }
 
 func Main() {
-	gc.Thearch.Thechar = '5'
-	gc.Thearch.Thestring = "arm"
-	gc.Thearch.Thelinkarch = &arm.Linkarm
+	gc.Thearch.LinkArch = &arm.Linkarm
 	gc.Thearch.REGSP = arm.REGSP
 	gc.Thearch.REGCTXT = arm.REGCTXT
 	gc.Thearch.REGCALLX = arm.REG_R1
diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go
index 7e1226f..17c851c 100644
--- a/src/cmd/compile/internal/arm64/galign.go
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -10,15 +10,10 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
 }
 
 func Main() {
-	gc.Thearch.Thechar = '7'
-	gc.Thearch.Thestring = "arm64"
-	gc.Thearch.Thelinkarch = &arm64.Linkarm64
+	gc.Thearch.LinkArch = &arm64.Linkarm64
 	gc.Thearch.REGSP = arm64.REGSP
 	gc.Thearch.REGCTXT = arm64.REGCTXT
 	gc.Thearch.REGCALLX = arm64.REGRT1
diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
index c594ad4..a9cedf7 100644
--- a/src/cmd/compile/internal/gc/cgen.go
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -7,6 +7,7 @@
 import (
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
+	"cmd/internal/sys"
 	"fmt"
 )
 
@@ -88,7 +89,7 @@
 
 	if !res.Addable {
 		if n.Ullman > res.Ullman {
-			if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
+			if Ctxt.Arch.RegSize == 4 && Is64(n.Type) {
 				var n1 Node
 				Tempname(&n1, n.Type)
 				Cgen(n, &n1)
@@ -127,7 +128,7 @@
 				f = false
 			}
 
-			if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 && !wb {
+			if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 && !wb {
 				a := Thearch.Optoas(OAS, res.Type)
 				var addr obj.Addr
 				if Thearch.Sudoaddable(a, res, &addr) {
@@ -151,7 +152,7 @@
 			}
 		}
 
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			// no registers to speak of
 			var n1, n2 Node
 			Tempname(&n1, n.Type)
@@ -203,7 +204,7 @@
 
 	// Write barrier now handled. Code below this line can ignore wb.
 
-	if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
+	if Ctxt.Arch.Family == sys.ARM { // TODO(rsc): Maybe more often?
 		// if both are addressable, move
 		if n.Addable && res.Addable {
 			if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || n.Type.IsComplex() || res.Type.IsComplex() {
@@ -246,12 +247,12 @@
 		return
 	}
 
-	if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable {
+	if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) && n.Addable {
 		Thearch.Gmove(n, res)
 		return
 	}
 
-	if Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+	if Ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.PPC64) {
 		// if both are addressable, move
 		if n.Addable {
 			if n.Op == OREGISTER || res.Op == OREGISTER {
@@ -268,7 +269,7 @@
 	}
 
 	// if n is sudoaddable generate addr and move
-	if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() {
+	if Ctxt.Arch.Family == sys.ARM && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() {
 		a := Thearch.Optoas(OAS, n.Type)
 		var addr obj.Addr
 		if Thearch.Sudoaddable(a, n, &addr) {
@@ -310,7 +311,7 @@
 	}
 
 	// 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)) {
+	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,
@@ -334,7 +335,7 @@
 		return
 	}
 
-	if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 {
+	if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 {
 		a := Thearch.Optoas(OAS, n.Type)
 		var addr obj.Addr
 		if Thearch.Sudoaddable(a, n, &addr) {
@@ -401,11 +402,11 @@
 		Regalloc(&n1, nl.Type, res)
 
 		Cgen(nl, &n1)
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			var n2 Node
 			Nodconst(&n2, nl.Type, 0)
 			Thearch.Gins(a, &n2, &n1)
-		} else if Ctxt.Arch.Thechar == '7' {
+		} else if Ctxt.Arch.Family == sys.ARM64 {
 			Thearch.Gins(a, &n1, &n1)
 		} else {
 			Thearch.Gins(a, nil, &n1)
@@ -452,7 +453,7 @@
 			return
 		}
 
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			var n1 Node
 			var n2 Node
 			Tempname(&n2, n.Type)
@@ -465,7 +466,7 @@
 
 		var n1 Node
 		var n2 Node
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			if nl.Addable && !Is64(nl.Type) {
 				Regalloc(&n1, nl.Type, res)
 				Thearch.Gmove(nl, &n1)
@@ -707,7 +708,7 @@
 abop: // asymmetric binary
 	var n1 Node
 	var n2 Node
-	if Ctxt.Arch.Thechar == '8' {
+	if Ctxt.Arch.Family == sys.I386 {
 		// no registers, sigh
 		if Smallintconst(nr) {
 			var n1 Node
@@ -751,14 +752,14 @@
 		Regalloc(&n1, nl.Type, res)
 		Cgen(nl, &n1)
 
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
 			n2 = *nr
 		} else {
 			Regalloc(&n2, nr.Type, nil)
 			Cgen(nr, &n2)
 		}
 	} else {
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
 			n2 = *nr
 		} else {
 			Regalloc(&n2, nr.Type, res)
@@ -876,8 +877,8 @@
 // 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':
+	switch Ctxt.Arch.Family {
+	case sys.AMD64, sys.I386:
 		// We use sized math, so the result is already truncated.
 	default:
 		switch n.Op {
@@ -980,7 +981,7 @@
 		Cgen_checknil(a)
 
 	case OINDEX:
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			var p2 *obj.Prog // to be patched to panicindex.
 			w := uint32(n.Type.Width)
 			bounded := Debug['B'] != 0 || n.Bounded
@@ -1127,7 +1128,7 @@
 			Regfree(&n2)
 			break
 		}
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			var p2 *obj.Prog // to be patched to panicindex.
 			w := uint32(n.Type.Width)
 			bounded := Debug['B'] != 0 || n.Bounded
@@ -1604,7 +1605,7 @@
 }
 
 func addOffset(res *Node, offset int64) {
-	if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' {
+	if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) {
 		Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
 		return
 	}
@@ -1825,13 +1826,14 @@
 		return
 
 	case ONAME:
+		// Some architectures might need a temporary or other help here,
+		// but they don't support direct generation of a bool value yet.
+		// We can fix that as we go.
+		mayNeedTemp := Ctxt.Arch.InFamily(sys.ARM, sys.ARM64, sys.MIPS64, sys.PPC64)
+
 		if genval {
-			// 5g, 7g, and 9g might need a temporary or other help here,
-			// but they don't support direct generation of a bool value yet.
-			// We can fix that as we go.
-			switch Ctxt.Arch.Thechar {
-			case '0', '5', '7', '9':
-				Fatalf("genval 0g, 5g, 7g, 9g ONAMES not fully implemented")
+			if mayNeedTemp {
+				Fatalf("genval ONAMES not fully implemented")
 			}
 			Cgen(n, res)
 			if !wantTrue {
@@ -1840,7 +1842,7 @@
 			return
 		}
 
-		if n.Addable && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' {
+		if n.Addable && !mayNeedTemp {
 			// no need for a temporary
 			bgenNonZero(n, nil, wantTrue, likely, to)
 			return
@@ -1977,7 +1979,7 @@
 		return
 	}
 
-	if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
+	if Ctxt.Arch.RegSize == 4 && Is64(nr.Type) {
 		if genval {
 			// TODO: Teach Cmp64 to generate boolean values and remove this.
 			bvgenjump(n, res, wantTrue, false)
@@ -2015,7 +2017,7 @@
 		Regfree(&n2)
 	} else {
 		var n1 Node
-		if !nl.Addable && Ctxt.Arch.Thechar == '8' {
+		if !nl.Addable && Ctxt.Arch.Family == sys.I386 {
 			Tempname(&n1, nl.Type)
 		} else {
 			Regalloc(&n1, nl.Type, nil)
@@ -2024,13 +2026,13 @@
 		Cgen(nl, &n1)
 		nl = &n1
 
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '9' {
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.PPC64 {
 			Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
 			bins(nr.Type, res, op, likely, to)
 			return
 		}
 
-		if !nr.Addable && Ctxt.Arch.Thechar == '8' {
+		if !nr.Addable && Ctxt.Arch.Family == sys.I386 {
 			nr = CgenTemp(nr)
 		}
 
@@ -2044,13 +2046,13 @@
 	l, r := nl, nr
 
 	// On x86, only < and <= work right with NaN; reverse if needed
-	if Ctxt.Arch.Thechar == '6' && nl.Type.IsFloat() && (op == OGT || op == OGE) {
+	if Ctxt.Arch.Family == sys.AMD64 && nl.Type.IsFloat() && (op == OGT || op == OGE) {
 		l, r = r, l
 		op = Brrev(op)
 	}
 
 	// MIPS does not have CMP instruction
-	if Ctxt.Arch.Thechar == '0' {
+	if Ctxt.Arch.Family == sys.MIPS64 {
 		p := Thearch.Ginscmp(op, nr.Type, l, r, likely)
 		Patch(p, to)
 		return
@@ -2062,8 +2064,8 @@
 	// Handle floating point special cases.
 	// Note that 8g has Bgen_float and is handled above.
 	if nl.Type.IsFloat() {
-		switch Ctxt.Arch.Thechar {
-		case '5':
+		switch Ctxt.Arch.Family {
+		case sys.ARM:
 			if genval {
 				Fatalf("genval 5g Isfloat special cases not implemented")
 			}
@@ -2077,7 +2079,7 @@
 				Patch(p, Pc)
 			}
 			return
-		case '6':
+		case sys.AMD64:
 			switch n.Op {
 			case OEQ:
 				// neither NE nor P
@@ -2111,7 +2113,7 @@
 				}
 				return
 			}
-		case '7', '9':
+		case sys.ARM64, sys.PPC64:
 			if genval {
 				Fatalf("genval 7g, 9g Isfloat special cases not implemented")
 			}
@@ -2143,7 +2145,7 @@
 	}
 
 	// MIPS does not have CMP instruction
-	if Thearch.Thechar == '0' {
+	if Thearch.LinkArch.Family == sys.MIPS64 {
 		p := Gbranch(Thearch.Optoas(op, n.Type), n.Type, likely)
 		Naddr(&p.From, n)
 		Patch(p, to)
@@ -2352,7 +2354,7 @@
 				// into the instruction stream.
 				Thearch.Ginsnop()
 
-				if Thearch.Thechar == '9' {
+				if Thearch.LinkArch.Family == sys.PPC64 {
 					// On ppc64, when compiling Go into position
 					// independent code on ppc64le we insert an
 					// instruction to reload the TOC pointer from the
@@ -2630,7 +2632,7 @@
 	// 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 == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+	if nr.Op != OLITERAL || Ctxt.Arch.Family == sys.MIPS64 || Ctxt.Arch.Family == sys.ARM64 || Ctxt.Arch.Family == sys.PPC64 {
 		goto longdiv
 	}
 	w = int(nl.Type.Width * 8)
@@ -2995,7 +2997,7 @@
 	regalloc := Regalloc
 	ginscon := Thearch.Ginscon
 	gins := Thearch.Gins
-	if Thearch.Thechar == '8' {
+	if Thearch.LinkArch.Family == sys.I386 {
 		regalloc = func(n *Node, t *Type, reuse *Node) {
 			Tempname(n, t)
 		}
@@ -3238,7 +3240,7 @@
 	compare := func(n1, n2 *Node) {
 		// n1 might be a 64-bit constant, even on 32-bit architectures,
 		// but it will be represented in 32 bits.
-		if Ctxt.Arch.Regsize == 4 && Is64(n1.Type) {
+		if Ctxt.Arch.RegSize == 4 && Is64(n1.Type) {
 			if n1.Val().U.(*Mpint).CmpInt64(1<<31) >= 0 {
 				Fatalf("missed slice out of bounds check")
 			}
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index 4a98f41..7527452 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -8,6 +8,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 )
 
@@ -1174,7 +1175,7 @@
 		}
 		// NOTE: Assuming little endian (signed top half at offset 4).
 		// We don't have any 32-bit big-endian systems.
-		if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
+		if !Thearch.LinkArch.InFamily(sys.ARM, sys.I386) {
 			Fatalf("unknown 32-bit architecture")
 		}
 		return f(Types[TUINT32], startOffset) &&
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index 4cb985b..ef8b516 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -360,9 +360,8 @@
 )
 
 type Arch struct {
-	Thechar      int
-	Thestring    string
-	Thelinkarch  *obj.LinkArch
+	LinkArch *obj.LinkArch
+
 	REGSP        int
 	REGCTXT      int
 	REGCALLX     int // BX
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index a2fa5f8..63a8e96 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"runtime"
 	"strings"
@@ -57,7 +58,7 @@
 		return true
 
 	case OADDR:
-		return Thearch.Thechar == '6' || Thearch.Thechar == '9' // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
+		return Thearch.LinkArch.InFamily(sys.AMD64, sys.PPC64) // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
 	}
 
 	return false
@@ -83,7 +84,7 @@
 	p := Prog(as)
 	p.To.Type = obj.TYPE_BRANCH
 	p.To.Val = nil
-	if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' && Thearch.Thechar != '0' {
+	if as != obj.AJMP && likely != 0 && Thearch.LinkArch.Family != sys.PPC64 && Thearch.LinkArch.Family != sys.ARM64 && Thearch.LinkArch.Family != sys.MIPS64 {
 		p.From.Type = obj.TYPE_CONST
 		if likely > 0 {
 			p.From.Offset = 1
@@ -330,7 +331,7 @@
 		a.Type = obj.TYPE_REG
 		a.Reg = n.Reg
 		a.Sym = nil
-		if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+		if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
 			a.Width = 0
 		}
 
@@ -342,7 +343,7 @@
 		if a.Offset != int64(int32(a.Offset)) {
 			Yyerror("offset %d too large for OINDREG", a.Offset)
 		}
-		if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+		if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
 			a.Width = 0
 		}
 
@@ -424,7 +425,7 @@
 		Naddr(a, n.Left)
 
 	case OLITERAL:
-		if Thearch.Thechar == '8' {
+		if Thearch.LinkArch.Family == sys.I386 {
 			a.Width = 0
 		}
 		switch n.Val().Ctype() {
@@ -457,7 +458,7 @@
 	case OADDR:
 		Naddr(a, n.Left)
 		a.Etype = uint8(Tptr)
-		if Thearch.Thechar != '0' && Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
+		if !Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) { // TODO(rsc): Do this even for arm, ppc64.
 			a.Width = int64(Widthptr)
 		}
 		if a.Type != obj.TYPE_MEM {
@@ -496,7 +497,7 @@
 		}
 		a.Etype = uint8(Simtype[TUINT])
 		a.Offset += int64(Array_nel)
-		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+		if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
 			a.Width = int64(Widthint)
 		}
 
@@ -509,7 +510,7 @@
 		}
 		a.Etype = uint8(Simtype[TUINT])
 		a.Offset += int64(Array_cap)
-		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+		if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
 			a.Width = int64(Widthint)
 		}
 	}
@@ -695,7 +696,7 @@
 		Fatalf("regalloc: t nil")
 	}
 	et := Simtype[t.Etype]
-	if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) {
+	if Ctxt.Arch.RegSize == 4 && (et == TINT64 || et == TUINT64) {
 		Fatalf("regalloc 64bit")
 	}
 
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 73ecb09..72e6478 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -10,6 +10,7 @@
 	"bufio"
 	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"flag"
 	"fmt"
 	"io"
@@ -96,12 +97,12 @@
 	// but not other values.
 	p := obj.Getgoarch()
 
-	if !strings.HasPrefix(p, Thearch.Thestring) {
-		log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p)
+	if !strings.HasPrefix(p, Thearch.LinkArch.Name) {
+		log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.LinkArch.Family, p)
 	}
 	goarch = p
 
-	Ctxt = obj.Linknew(Thearch.Thelinkarch)
+	Ctxt = obj.Linknew(Thearch.LinkArch)
 	Ctxt.DiagFunc = Yyerror
 	Ctxt.Bso = &bstdout
 	bstdout = *obj.Binitw(os.Stdout)
@@ -200,15 +201,13 @@
 	obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
 	var flag_shared int
 	var flag_dynlink bool
-	switch Thearch.Thechar {
-	case '5', '6', '7', '8', '9':
+	if Thearch.LinkArch.InFamily(sys.ARM, sys.AMD64, sys.ARM64, sys.I386, sys.PPC64) {
 		obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
 	}
-	if Thearch.Thechar == '6' {
+	if Thearch.LinkArch.Family == sys.AMD64 {
 		obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
 	}
-	switch Thearch.Thechar {
-	case '5', '6', '7', '8', '9':
+	if Thearch.LinkArch.InFamily(sys.ARM, sys.AMD64, sys.ARM64, sys.I386, sys.PPC64) {
 		flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
 	}
 	obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
@@ -301,9 +300,9 @@
 	}
 
 	Thearch.Betypeinit()
-	if Widthptr == 0 {
-		Fatalf("betypeinit failed")
-	}
+	Widthint = Thearch.LinkArch.IntSize
+	Widthptr = Thearch.LinkArch.PtrSize
+	Widthreg = Thearch.LinkArch.RegSize
 
 	initUniverse()
 
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index 63f7bf8..bfb65ad 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -7,6 +7,7 @@
 import (
 	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"crypto/md5"
 	"fmt"
 	"sort"
@@ -286,7 +287,7 @@
 		if haspointers(n.Type) {
 			stkptrsize = Stksize
 		}
-		if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+		if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) {
 			Stksize = Rnd(Stksize, int64(Widthptr))
 		}
 		if Stksize >= 1<<31 {
@@ -323,7 +324,7 @@
 		Fatalf("bad checknil")
 	}
 
-	if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
+	if (Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
 		var reg Node
 		Regalloc(&reg, Types[Tptr], n)
 		Cgen(n, &reg)
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index 43f594e..6e43d31 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -17,6 +17,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"sort"
 	"strings"
@@ -1396,7 +1397,7 @@
 						// The instruction before a call to deferreturn is always a
 						// no-op, to keep PC-specific data unambiguous.
 						prev := p.Opt.(*obj.Prog)
-						if Ctxt.Arch.Thechar == '9' {
+						if Ctxt.Arch.Family == sys.PPC64 {
 							// On ppc64 there is an additional instruction
 							// (another no-op or reload of toc pointer) before
 							// the call.
diff --git a/src/cmd/compile/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go
index 26746a5..8705d6d 100644
--- a/src/cmd/compile/internal/gc/reg.go
+++ b/src/cmd/compile/internal/gc/reg.go
@@ -33,6 +33,7 @@
 import (
 	"bytes"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"sort"
 	"strings"
@@ -249,7 +250,7 @@
 	p1.As = Thearch.Optoas(OAS, Types[uint8(v.etype)])
 
 	// TODO(rsc): Remove special case here.
-	if (Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && v.etype == TBOOL {
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && v.etype == TBOOL {
 		p1.As = Thearch.Optoas(OAS, Types[TUINT8])
 	}
 	p1.From.Type = obj.TYPE_REG
@@ -302,7 +303,7 @@
 		// TODO(rsc): Remove special case here.
 	case obj.TYPE_ADDR:
 		var bit Bits
-		if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+		if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) {
 			goto memcase
 		}
 		a.Type = obj.TYPE_MEM
@@ -368,7 +369,7 @@
 				if v.etype == et {
 					if int64(v.width) == w {
 						// TODO(rsc): Remove special case for arm here.
-						if flag == 0 || Thearch.Thechar != '5' {
+						if flag == 0 || Thearch.LinkArch.Family != sys.ARM {
 							return blsh(uint(i))
 						}
 					}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 127a7c4..90c4d4e 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -13,6 +13,7 @@
 
 	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 )
 
 var ssaEnabled = true
@@ -24,13 +25,13 @@
 	ssaExp.unimplemented = false
 	ssaExp.mustImplement = true
 	if ssaConfig == nil {
-		ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
+		ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0)
 	}
 	return ssaConfig
 }
 
 func shouldssa(fn *Node) bool {
-	switch Thearch.Thestring {
+	switch Thearch.LinkArch.Name {
 	default:
 		// Only available for testing.
 		if os.Getenv("SSATEST") == "" {
@@ -2409,7 +2410,7 @@
 	// so far has only been noticed for Bswap32 and the 16-bit count
 	// leading/trailing instructions, but heuristics might change
 	// in the future or on different architectures).
-	if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.Thechar != '6' {
+	if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.LinkArch.Family != sys.AMD64 {
 		return false
 	}
 	if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index ff8ddea..586a8e9c 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -6,6 +6,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"strings"
 )
@@ -672,8 +673,7 @@
 		walkexprlist(n.List.Slice(), init)
 
 		if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
-			switch Thearch.Thechar {
-			case '5', '6', '7', '9':
+			if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64) {
 				n.Op = OSQRT
 				n.Left = n.List.First()
 				n.List.Set(nil)
@@ -1056,7 +1056,7 @@
 		n = walkexpr(n, init)
 
 	case OCONV, OCONVNOP:
-		if Thearch.Thechar == '5' {
+		if Thearch.LinkArch.Family == sys.ARM {
 			if n.Left.Type.IsFloat() {
 				if n.Type.Etype == TINT64 {
 					n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
@@ -3274,7 +3274,7 @@
 // The result of walkrotate MUST be assigned back to n, e.g.
 // 	n.Left = walkrotate(n.Left)
 func walkrotate(n *Node) *Node {
-	if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
 		return n
 	}
 
@@ -3401,7 +3401,7 @@
 	// if >= 0, nr is 1<<pow // 1 if nr is negative.
 
 	// TODO(minux)
-	if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
 		return n
 	}
 
diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go
index 9d582f4..22890c8 100644
--- a/src/cmd/compile/internal/mips64/galign.go
+++ b/src/cmd/compile/internal/mips64/galign.go
@@ -11,18 +11,12 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
 }
 
 func Main() {
-	gc.Thearch.Thechar = '0'
-	gc.Thearch.Thestring = "mips64"
-	gc.Thearch.Thelinkarch = &mips.Linkmips64
+	gc.Thearch.LinkArch = &mips.Linkmips64
 	if obj.Getgoarch() == "mips64le" {
-		gc.Thearch.Thestring = "mips64le"
-		gc.Thearch.Thelinkarch = &mips.Linkmips64le
+		gc.Thearch.LinkArch = &mips.Linkmips64le
 	}
 	gc.Thearch.REGSP = mips.REGSP
 	gc.Thearch.REGCTXT = mips.REGCTXT
diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go
index 91bece6..04fa4cf 100644
--- a/src/cmd/compile/internal/ppc64/galign.go
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -11,10 +11,6 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
-
 	if gc.Ctxt.Flag_shared != 0 {
 		gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R2)
 		gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R12)
@@ -22,12 +18,9 @@
 }
 
 func Main() {
-	gc.Thearch.Thechar = '9'
-	gc.Thearch.Thestring = "ppc64"
-	gc.Thearch.Thelinkarch = &ppc64.Linkppc64
+	gc.Thearch.LinkArch = &ppc64.Linkppc64
 	if obj.Getgoarch() == "ppc64le" {
-		gc.Thearch.Thestring = "ppc64le"
-		gc.Thearch.Thelinkarch = &ppc64.Linkppc64le
+		gc.Thearch.LinkArch = &ppc64.Linkppc64le
 	}
 	gc.Thearch.REGSP = ppc64.REGSP
 	gc.Thearch.REGCTXT = ppc64.REGCTXT
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
index 4ab72b6..738d887 100644
--- a/src/cmd/compile/internal/x86/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -13,15 +13,10 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 4
-	gc.Widthint = 4
-	gc.Widthreg = 4
 }
 
 func Main() {
-	gc.Thearch.Thechar = '8'
-	gc.Thearch.Thestring = "386"
-	gc.Thearch.Thelinkarch = &x86.Link386
+	gc.Thearch.LinkArch = &x86.Link386
 	gc.Thearch.REGSP = x86.REGSP
 	gc.Thearch.REGCTXT = x86.REGCTXT
 	gc.Thearch.REGCALLX = x86.REG_BX